# AI Alt Text Generator & Checker: Fix Missing Alt Text (`raional/ai-alt-text-generator`) Actor

Generate accessibility- and SEO-ready alt text for a list of image URLs, or scan a whole website and write alt text for every image that's missing it. Powered by AI vision.

- **URL**: https://apify.com/raional/ai-alt-text-generator.md
- **Developed by:** [Raion Al](https://apify.com/raional) (community)
- **Categories:** SEO tools, E-commerce, Developer tools
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 image processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## AI Alt Text Generator: Bulk Alt Text for Image URL Lists

Generate **accessibility- and SEO-ready alt text** for images at scale using AI vision. Feed it a **list of image URLs**, like product catalog exports, CMS asset libraries, or migration lists, and get alt text back for each, ready to export to CSV, JSON, or Excel.

Great for: **image alt text**, **bulk alt text generation**, **AI image captioning**, **WCAG / accessibility** compliance, **SEO images**, e-commerce product catalogs, and CMS migrations.

**Need a whole-site audit instead?** If you want to scan an entire website (sitemap crawling, not just a single page) and optionally generate AI descriptions for what it finds, use the companion [Image Alt Text Checker](https://apify.com/raional/image-alt-text-checker). It has the same AI description add-on plus full-site crawling and a no-AI metadata audit mode.

***

### What it does

- **Give it a list of image URLs** → get alt text for each. This is the primary way to use this actor.
- **Or check a single page**: point it at one page and it finds `<img>` tags missing alt text and writes it for you. (For crawling a whole site, use the Image Alt Text Checker instead.)
- Multilingual output, a length cap tuned for WCAG (~125 characters), an optional **SEO keyword hint**, and **decorative-image detection** (recommends empty `alt=""` for purely ornamental images instead of a bogus description).

### Output

One dataset row per image, with a table view built in:

| Field | Description |
|---|---|
| `imageUrl` | The image that was described |
| `altText` | The generated alt text (empty for decorative images) |
| `flaggedDecorative` | `true` if the image was judged purely decorative |
| `charCount` | Length of the alt text |
| `pageUrl` | The page it was found on (single-page check only) |
| `existingAlt` | The alt text already present, if any |
| `status` | `ok`, `error`, or `mocked` |

A run **summary** (counts + estimated cost) is stored in the key-value store under `SUMMARY`.

### Example input

**A list of image URLs, Spanish, with an SEO hint:**

```json
{
  "imageUrls": [
    "https://example.com/products/mug-01.jpg",
    "https://example.com/products/mug-02.jpg"
  ],
  "language": "Spanish",
  "keywordHint": "handmade ceramic mug, product page",
  "style": "descriptive"
}
```

**Single-page check (only images missing alt):**

```json
{
  "startUrls": [{ "url": "https://example.com" }],
  "onlyMissingAlt": true,
  "language": "English",
  "style": "concise",
  "maxLength": 125,
  "maxImages": 200
}
```

### Key options

| Option | Default | Notes |
|---|---|---|
| `imageUrls` | `[]` | Primary use: direct image URLs |
| `startUrls` | `[]` | Single-page check (not a full-site crawl; see Image Alt Text Checker for that) |
| `onlyMissingAlt` | `true` | Single-page check: skip images that already have alt text |
| `language` | `English` | Any language |
| `style` | `concise` | `concise` (WCAG-friendly) or `descriptive` |
| `maxLength` | `125` | Hard character cap |
| `keywordHint` | None | Woven in naturally; no keyword stuffing |
| `detectDecorative` | `true` | Recommends `alt=""` for ornamental images |
| `maxImages` | `200` | Per-run safety cap (controls cost) |
| `model` | `google/gemini-2.5-flash-lite` | Any OpenRouter vision model (e.g. `openai/gpt-5-nano`, `amazon/nova-lite-v1`) |
| `apiBaseUrl` | OpenRouter | OpenAI-compatible base URL: swap for OpenAI/Groq/Together/local |
| `maxPagesPerCrawl` | `1` | Pages to crawl per start URL (same domain) |
| `concurrency` | `5` | Parallel image requests |

### Pricing

Billed **per image processed** (pay-per-event). Failed images are **not** charged. On cheap OpenRouter vision models the underlying cost is roughly **$0.0001–0.0003 per image**. Supported image formats: JPEG, PNG, GIF, WebP (SVG/ICO are skipped).

### Please note (fair use & accuracy)

- **Only scan websites you own or have permission to analyze.** You supply the target; you're responsible for it.
- Alt text is **AI-generated**: review it before publishing, especially in legally-sensitive or compliance-critical contexts.
- Images are processed transiently and are **not stored** beyond the run; your results live in your dataset.

***

### Running / self-hosting

The hosted actor provides the AI backend: you just pay per image. To self-host or run locally:

1. `npm install`
2. Set `OPENROUTER_API_KEY` (env var) or pass `openrouterApiKey` in the input. Get a key at https://openrouter.ai/keys
3. `npx apify-cli run` (or `npm start`). Without a key it runs in **mock mode** (placeholder alt text) so you can test the pipeline.

To use a different provider, set the `apiBaseUrl` input to any OpenAI-compatible endpoint (OpenAI, Groq, Together, a local server) and supply that provider's key.

#### Configure monetization (maintainer)

On the Apify platform, set `OPENROUTER_API_KEY` as an Actor environment secret, and configure a **pay-per-event** price for the event `image-processed` in the Actor's monetization settings. The code calls `Actor.charge({ eventName: 'image-processed' })` once per successfully processed image.

Built with [Apify SDK](https://docs.apify.com/sdk/js/) + [Crawlee](https://crawlee.dev/) + OpenRouter vision models.

# Actor input Schema

## `imageUrls` (type: `array`):

The main way to use this actor: a list of direct image URLs to generate alt text for. Leave empty if you only want the single-page website check below.

## `startUrls` (type: `array`):

Quick single-page check: scans one page's <img> tags and writes alt text for images missing it. Only scan pages you own or have permission to analyze. For crawling an entire site (sitemap-based), use the companion Image Alt Text Checker actor, which also has this AI description add-on.

## `onlyMissingAlt` (type: `boolean`):

In website mode, only generate alt text for images whose alt attribute is empty or missing. Turn off to (re)generate alt text for every image.

## `language` (type: `string`):

Language for the generated alt text (e.g. English, Spanish, French, German).

## `style` (type: `string`):

Concise = short, functional alt text (recommended for accessibility). Descriptive = a richer description.

## `maxLength` (type: `integer`):

Hard cap on alt text length. WCAG guidance favors ~125 characters or fewer.

## `keywordHint` (type: `string`):

Optional context or target keyword to weave in naturally (no keyword stuffing). E.g. 'handmade ceramic mug, product page'.

## `detectDecorative` (type: `boolean`):

Flag purely decorative images (spacers, ornaments) and recommend empty alt text (alt="") instead of a description.

## `maxImages` (type: `integer`):

Safety cap on how many images to process in one run (controls cost).

## `model` (type: `string`):

Any OpenRouter (or OpenAI-compatible) vision model ID. Cheap, reliable defaults: google/gemini-2.5-flash-lite, openai/gpt-5-nano, amazon/nova-lite-v1. Browse all vision models at https://openrouter.ai/models?modality=text+image-%3Etext

## `maxPagesPerCrawl` (type: `integer`):

Single-page check only. How many pages to crawl per start URL (same domain). 1 = just the given page. For larger sites, use the Image Alt Text Checker's 'Scan entire site' toggle instead.

## `concurrency` (type: `integer`):

How many images to describe in parallel. Higher is faster but may hit model rate limits.

## `apiBaseUrl` (type: `string`):

OpenAI-compatible chat-completions base URL. Defaults to OpenRouter. Change to use OpenAI, Groq, Together, or a local server (e.g. https://api.openai.com/v1).

## `openrouterApiKey` (type: `string`):

Optional. Only needed if you self-host this actor. On the hosted actor this is provided for you and you simply pay per image processed. Get one at https://openrouter.ai/keys

## Actor input object example

```json
{
  "imageUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/3/3a/Cat03.jpg"
  ],
  "startUrls": [],
  "onlyMissingAlt": true,
  "language": "English",
  "style": "concise",
  "maxLength": 125,
  "detectDecorative": true,
  "maxImages": 200,
  "model": "google/gemini-2.5-flash-lite",
  "maxPagesPerCrawl": 1,
  "concurrency": 5,
  "apiBaseUrl": "https://openrouter.ai/api/v1"
}
```

# Actor output Schema

## `altText` (type: `string`):

One dataset row per image: imageUrl, altText, flaggedDecorative, charCount, pageUrl, existingAlt, status.

## `summary` (type: `string`):

Counts (processed, decorative, errors) and estimated model cost for the run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "imageUrls": [
        "https://picsum.photos/id/237/400/300",
        "https://picsum.photos/id/1015/400/300"
    ],
    "startUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("raional/ai-alt-text-generator").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "imageUrls": [
        "https://picsum.photos/id/237/400/300",
        "https://picsum.photos/id/1015/400/300",
    ],
    "startUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("raional/ai-alt-text-generator").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "imageUrls": [
    "https://picsum.photos/id/237/400/300",
    "https://picsum.photos/id/1015/400/300"
  ],
  "startUrls": []
}' |
apify call raional/ai-alt-text-generator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=raional/ai-alt-text-generator",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jnRe6yfeJHaU0jB8h/builds/NZ17O83XsOgXcgaEF/openapi.json
