🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

astro-aeo-image

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

astro-aeo-image

Astro image service that embeds your alt text (and optional description/keywords) as standards XMP into the optimized output files — so your dist/_astro assets are self-describing for Google Images and AI answer engines. Wraps Astro's default shar

latest
Source
npmnpm
Version
0.4.0
Version published
Weekly downloads
249
308.2%
Maintainers
1
Weekly downloads
 
Created
Source

astro-aeo-image

An Astro image service that embeds your <Image> alt text (and optional description/keywords/license) as standards XMP/IPTC directly into the optimized output files — so your dist/_astro assets are self-describing: Google Images reads embedded IPTC metadata and recommends embedding it, and the description travels with the file for accessibility, attribution, and the AI-search era.

npm license

Astro already requires an alt on every <Image /> — but that text normally lives only in the HTML attribute. The moment the optimized file is downloaded, hot-linked, or indexed as a file, the page context is gone. astro-aeo-image writes the description (and attribution/license) into the image bytes, where it travels with the file.

What's documented: Google Images reads embedded IPTC metadata (creator/credit/copyright/license) and recommends embedding it. For image ranking, Google uses the HTML alt — so embedding complements it (durability, accessibility, attribution), it doesn't replace it or claim a ranking boost. AI engines consuming embedded metadata is forward-looking, not yet a spec.

How it's different from image.service.config.keepMetadata

This is an authoring layer, not a preservation one — and that distinction is the whole point:

sharp's keepMetadata / keepExifastro-aeo-image
Carries through metadata already in the source file
Authors new descriptive metadata from your app data (the alt you already wrote, captions, keywords)
Writes Iptc4xmpCore:AltTextAccessibility + dc:description for AEO/accessibility

sharp can preserve a camera's existing EXIF; it can't compose a fresh XMP packet from the alt prop in your .astro file. That's the gap this fills.

How it works

It's a thin wrapper around Astro's own default sharp service. Everything sharp does is unchanged — same resizing, formats, quality, caching. After sharp encodes each variant, this service splices descriptive XMP into the output buffer via aeo-image: byte-preserving, no re-encode — the compressed pixels are identical; only a metadata block is added.

Install

npm install astro-aeo-image

aeo-image comes along as its only dependency (zero-dependency itself). astro is a peer dependency (you already have it).

Configure

Add the integration — one line:

// astro.config.mjs
import { defineConfig } from "astro/config";
import aeoImage from "astro-aeo-image";

export default defineConfig({
  integrations: [
    aeoImage(), // or aeoImage({ useAltAsDescription: false })
  ],
});
Advanced: use the image service directly (without the integration)
// astro.config.mjs
import { defineConfig } from "astro/config";

export default defineConfig({
  image: {
    service: {
      entrypoint: "astro-aeo-image/service",
      config: { useAltAsDescription: true },
    },
  },
});

The integration is just a thin wrapper that sets this for you and forwards options.

That's it. Every <Image /> you already have now ships its alt inside the file:

---
import { Image } from "astro:assets";
import barn from "../assets/barn.jpg";
---
<Image src={barn} alt="A weathered red barn under a violet dusk sky in rural Vermont" width={1200} height={800} />

The generated dist/_astro/barn.*.webp now contains:

  • Iptc4xmpCore:AltTextAccessibility = the alt text
  • dc:description = the alt text (unless useAltAsDescription: false)

Optional richer metadata

Pass extra props on <Image> for fuller AEO signals (distinct SEO description, keywords, title):

<Image
  src={barn}
  alt="A weathered red barn at dusk"
  description="A restored 1890s dairy barn in Vermont, now a working agrivoltaics site"
  keywords={["barn", "vermont", "agrivoltaics", "rural"]}
  title="Vermont Agrivoltaics Barn"
  width={1200} height={800}
/>
PropXMP field
alt (required by Astro)Iptc4xmpCore:AltTextAccessibility (+ dc:description)
descriptiondc:description
keywords (array or comma string)dc:subject
titledc:title
creatordc:creator
creditphotoshop:Credit
rightsdc:rights
copyrightNoticephotoshop:Copyright
licenseUrlxmpRights:WebStatementGoogle Licensable
licensor {url, name?} (or flat licensorUrl/licensorName)IPTC PLUS plus:LicensorGoogle "Get this image" link
digitalSourceType (full IRI or bare term like "trainedAlgorithmicMedia")Iptc4xmpExt:DigitalSourceTypeAI-generated disclosure
aiGenerated (boolean shorthand)sets Iptc4xmpExt:DigitalSourceType to trainedAlgorithmicMedia
ai {prompt?, promptWriter?, system?, systemVersion?} (or flat aiPrompt/aiPromptWriter/aiSystem/aiSystemVersion)IPTC 2025.1 Iptc4xmpExt:AIPromptInformation / AIPromptWriterName / AISystemUsed / AISystemVersionUsed

Make images Licensable in Google

The last fields implement what Google Images reads for the Licensable badge:

<Image
  src={barn}
  alt="A weathered red barn at dusk"
  creator="Jane Doe"
  copyrightNotice="© 2026 Example Studio"
  licenseUrl="https://example.com/license/barn"
  licensorUrl="https://example.com/buy/barn"
  width={1200} height={800}
/>

Label AI-generated images (IPTC 2025.1)

For AI-generated assets, embed the IPTC 2025.1 provenance fields plus the Digital Source Type IRI that downstream tools read to label an image as AI-generated:

<Image
  src={market}
  alt="A neon-lit street market at night in the rain"
  aiGenerated
  aiPrompt="neon street market, rain reflections, cinematic 35mm"
  aiPromptWriter="Jane Doe"
  aiSystem="DALL-E via Bing Image Creator"
  aiSystemVersion="3"
  width={1200} height={800}
/>

aiGenerated is shorthand for digitalSourceType="trainedAlgorithmicMedia"; pass digitalSourceType explicitly for other terms (e.g. "compositeSynthetic" — bare CV terms are expanded to the full IPTC IRI). Per IPTC guidance, leave creator off for fully AI-generated images — the prompt writer is explicitly not the creator.

For TypeScript autocomplete on the custom props, augment Astro's image props in src/env.d.ts:

declare namespace Astro {
  interface CustomImageProps {
    description?: string;
    keywords?: string[] | string;
    title?: string;
    aiGenerated?: boolean;
    aiPrompt?: string;
    aiSystem?: string;
  }
}

Supported formats

Whatever you output from Astro: WebP, AVIF, JPEG, PNG (via aeo-image). SVG/GIF and any format aeo-image doesn't handle are passed through untouched — the service degrades gracefully and never fails a build over metadata.

Standards

Metadata is written as Adobe XMP (not legacy IPTC-IIM), conforming to the IPTC Photo Metadata Standard 2025.1 (descriptive + accessibility + rights/licensing + AI-provenance subset) plus Dublin Core, Adobe, and PLUS namespaces — see aeo-image's conformance notes. This includes the 2025.1 AI-generation provenance properties and Iptc4xmpExt:DigitalSourceType (readable by exiftool, named tags from 13.40).

Verifying it worked

Given <Image alt="A weathered red barn under a violet dusk sky in rural Vermont" />, the built file gains embedded metadata:

$ exiftool dist/_astro/barn.abc123.webp | grep -iE "description|alt"
# ── before (default Astro service) ──
#   (no metadata)

# ── after (astro-aeo-image) ──
Description                     : A weathered red barn under a violet dusk sky in rural Vermont
Alt Text Accessibility          : A weathered red barn under a violet dusk sky in rural Vermont

Or check it programmatically:

node -e "import('aeo-image').then(async m=>{const {readFileSync}=await import('node:fs');console.log(m.readMetadata(new Uint8Array(readFileSync(process.argv[1]))))})" dist/_astro/<your-image>.webp
# → { description: '…', altText: '…' }

The pixels are untouched — only a metadata block is added.

Status & scope

  • The metadata-embedding core is unit-tested against the published aeo-image.
  • On static builds, Astro passes <Image> props (including alt) to the service's transform, which is where embedding happens. For on-demand/SSR image endpoints, the custom props are included in propertiesToHash so they survive into transform; if you rely on SSR image optimization, please smoke-test and open an issue with your Astro version if a prop doesn't come through.
  • Wraps astro/assets/services/sharp. If you use a different image service, this won't layer on top of it.

License

MIT

Keywords

astro

FAQs

Package last updated on 12 Jun 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts