Bulk Alt Text Generator — Image SEO & Accessibility Metadata avatar

Bulk Alt Text Generator — Image SEO & Accessibility Metadata

Pricing

from $10.00 / 1,000 image processeds

Go to Apify Store
Bulk Alt Text Generator — Image SEO & Accessibility Metadata

Bulk Alt Text Generator — Image SEO & Accessibility Metadata

Generate alt text, SEO filenames, captions, titles & keywords for up to 5,000 images per run. WCAG-informed, 20+ languages, structured JSON output. Failed images are never charged. $0.01 per image.

Pricing

from $10.00 / 1,000 image processeds

Rating

0.0

(0)

Developer

My Excel Solutions

My Excel Solutions

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Generate structured alt text, SEO filenames, captions, titles, and keywords from direct image URLs or a sitemap. This Apify Actor is designed for ecommerce catalogs, content teams, accessibility audits, agencies, and AI agents that need predictable JSON at scale.

The generated alt text is WCAG-informed and can help an accessibility workflow. It does not certify WCAG, European Accessibility Act, or other legal compliance; a human should review important or ambiguous images in their page context.

What you get

Each successful image produces a record like this:

{
"sourceUrl": "https://example.com/products/rust-red-backpack.jpg",
"status": "ok",
"altText": "Rust-red canvas backpack with front pocket and brown leather straps",
"seoFilename": "rust-red-canvas-travel-backpack",
"caption": "A durable rust-red canvas backpack designed for everyday travel and commuting.",
"title": "Rust-Red Canvas Travel Backpack",
"keywords": [
"canvas backpack",
"red backpack",
"travel bag",
"daypack",
"commuter bag",
"leather straps"
],
"model": "gemini-2.5-flash-lite",
"tokensUsed": 512
}

Failures are explicit and uncharged:

{
"sourceUrl": "https://example.com/broken.jpg",
"status": "failed",
"failureReason": "not_an_image"
}

Before and after

These outputs are captured by the deterministic end-to-end fixture run used in this repository. The same run exercises downloading, image normalization, structured model output, charging, and dataset records.

Source stateGenerated alt textGenerated SEO filename
IMG_1042.jpg, no alt textRust-red canvas backpack with front pocket and brown leather strapsrust-red-canvas-travel-backpack
product-final-2.png, no alt textWhite ceramic coffee mug beside roasted coffee beans on a wooden tablewhite-ceramic-coffee-mug

Input

Use either imageUrls or sitemapUrl, not both.

{
"imageUrls": [
"https://example.com/images/product-front.jpg",
"https://example.com/images/product-side.png"
],
"context": "Handmade silver jewellery store",
"language": "en",
"tone": "ecommerce",
"fields": ["altText", "seoFilename", "caption", "title", "keywords"]
}
  • imageUrls: up to 5,000 direct HTTP(S) image URLs.
  • sitemapUrl: image sitemap, one-level sitemap index, or page sitemap. Page sitemap mode fetches at most 200 pages and reads og:image metadata.
  • context: optional factual brand or product context, limited to 2,000 characters.
  • language: output language code; the Console includes 20 common choices.
  • tone: neutral, ecommerce, or editorial.
  • fields: any non-empty subset of altText, seoFilename, caption, title, and keywords.

Sitemap mode

For an image sitemap:

{
"sitemapUrl": "https://example.com/image-sitemap.xml",
"context": "Outdoor clothing retailer",
"language": "de",
"tone": "ecommerce"
}

The Actor extracts <image:image><image:loc> values. For a sitemap index it follows child sitemaps one level deep. If the input is a page sitemap, it fetches up to 200 pages with concurrency four and extracts each page's og:image. URLs are deduplicated and the final image list is capped at 5,000.

Reliability and cost controls

  • Downloads are limited to 20 MB and 30 seconds per image.
  • sharp verifies the payload, applies EXIF orientation, strips metadata, flattens transparency, limits the longest edge to 512 px, and re-encodes JPEG at quality 80 before Gemini receives it.
  • At most eight images are processed concurrently.
  • Gemini calls use a server-side JSON response schema, two retries with backoff for 429/5xx responses, and one corrective retry for invalid model JSON.
  • A failed download or model response cannot crash the rest of the run and is never charged as image-processed.
  • Every run logs {images, succeeded, failed, charged, estCogsUsd, ms}. The estimate uses actual Gemini usage token counts.
  • Prompt context and output length are bounded. The designed worst-case COGS is below $0.001/image, with a hard $0.003/image stop guardrail.

Pricing and free-tier gate

EventPriceWhen it occurs
image-processed$0.01Once per successful image only
apify-actor-start$0.001Synthetic Actor start event configured in Apify Console

Failed images are returned with status: "failed" and are not charged as image-processed. The Actor checks the pay-per-event spending limit after each successful dataset push and exits gracefully when the limit is reached.

Up to eight images can already be in flight when a charge-limit or COGS stop is detected. Any remaining completed results in that batch are intentionally withheld and uncharged, although their Gemini cost may already have been incurred; the run summary still counts them as processed.

Runs started by users for whom APIFY_USER_IS_PAYING !== "1" are capped at five images. Every emitted record receives "note": "free tier", and the log explains how many images were omitted.

Run locally

Prerequisites: Node.js 22 and npm.

npm install
npm run check
npm run build

For a completely local run with no Gemini cost, start the fixture image server in one PowerShell window:

npm run fixture:server

Then run the Actor in another window:

$env:MOCK_GEMINI='1'
$env:APIFY_USER_IS_PAYING='1'
$env:ACTOR_TEST_PAY_PER_EVENT='true'
$env:ACTOR_USE_CHARGING_LOG_DATASET='true'
npx apify-cli run -i '{"imageUrls":["http://127.0.0.1:3210/backpack.png","http://127.0.0.1:3210/coffee.jpg","http://127.0.0.1:3210/corrupt.jpg"],"context":"Fixture ecommerce store"}'

Local results are saved under storage/datasets/default. Charging-log records are under storage/datasets/charging_log when the charging-log environment variable is enabled.

For a real Gemini run, remove MOCK_GEMINI, set GEMINI_API_KEY in the environment, and keep the API key out of input JSON and source control:

Remove-Item Env:MOCK_GEMINI -ErrorAction SilentlyContinue
$env:GEMINI_API_KEY='<your-developer-key>'
npx apify-cli run -i '{"imageUrls":["https://example.com/product.jpg"],"context":"Your factual product context"}'

API and MCP/agent use

After deployment, call the Actor with the standard Apify API or client and read the default dataset:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('YOUR_USERNAME/bulk-alt-text-generator').call({
imageUrls: ['https://example.com/product.jpg'],
context: 'Minimalist homeware shop',
language: 'en',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

For an MCP-capable agent, connect to https://mcp.apify.com, expose this Actor as a tool, and pass the same input object. The hosted Apify MCP server infers structured output fields from the Actor dataset schema, so agents can consume success and failure records directly.

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com"
}
}
}

Development

npm run typecheck
npm run lint
npm run test
npm run check

The test suite covers large JPEG downscaling, PNG transparency, corrupt/oversized/timed-out downloads, concurrency, recorded Gemini responses and retries, COGS math, image/page/index sitemaps, charging limits, the free-tier gate, and an end-to-end local fixture run.

Limits

  • No image generation or editing.
  • No OCR or document processing.
  • No Shopify CSV preset or asynchronous Gemini Batch API in Phase 1.
  • AI output can be wrong; review high-impact accessibility and product content in its rendered page context.