# Image Caption & Alt Text Generator – AI, Bulk, No API Key (`gazidev/image-captioner`) Actor

AI alt text and image captions in bulk: accessible alt text (≤125 chars), detailed caption and SEO file name for image URLs, or audit a web page's <img> tags and flag missing/poor alt. Florence-2 runs inside the Actor, no API key. $6 per 1,000 images.

- **URL**: https://apify.com/gazidev/image-captioner.md
- **Developed by:** [Cemal Atakli](https://apify.com/gazidev) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 1,000 image describeds

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Image Caption & Alt Text Generator

Generate **alt text and image captions in bulk** with AI. Give the Actor a list of image URLs, or the URL of a web page, and it returns for every image:

- a short, accessible **alt text** (125 characters or less by default, no "image of..." filler),
- a **detailed caption** (1–3 sentences) or a longer **paragraph description**,
- an **SEO-friendly file name** suggestion such as `gray-wolf-standing-snow-trees.jpg`,
- for web pages: the **current alt text** of every `<img>`, a grade (`missing`, `empty`, `poor`, `short`, `ok`) and a ready-to-paste `<img ... alt="...">` snippet.

The vision model (Microsoft **Florence-2-base**) runs inside the Actor on CPU. You do **not** need an OpenAI, Google or other API key, and your images are not sent to a third-party AI service.

### What can it do?

| Feature | Details |
|---|---|
| Bulk alt text generator | Thousands of image URLs per run. Paste a list or CSV, or read URLs from another Apify dataset (e.g. an e-commerce or image scraper). |
| Image caption generator | Short caption + detailed caption, or a long paragraph (colours, background, layout). |
| Alt text audit for a website page | Collects every `<img>` (also `srcset`, `<picture>` and lazy-loaded `data-src`), reads the existing alt, flags missing / empty / poor alt text and writes a new one. Option to describe only the images that need it. |
| SEO file names | Lower-case, hyphenated, stop words removed, original extension kept. |
| Formats | JPG, PNG (transparency flattened to white), WebP, GIF (first frame), BMP, TIFF, HEIC/HEIF (iPhone), AVIF, and `data:image/...;base64` URIs. |
| Fair billing | Failed downloads, 404s, HTML pages, SVGs, icons below 32 px and skipped images are **free**. |

### Use cases

- **Accessibility (WCAG 2.x, ADA, European Accessibility Act):** find images without alt text and fill them in.
- **SEO for images:** descriptive alt text and file names for product photos, blog images and galleries.
- **E-commerce catalogues:** describe thousands of product images from a Shopify, WooCommerce or marketplace scraper.
- **CMS migrations and DAM tagging:** add captions to an image library before importing it.
- **AI agents and RAG:** turn images into text that an LLM or a search index can use.

### Input example

```json
{
  "imageUrls": [
    "https://raw.githubusercontent.com/xinntao/Real-ESRGAN/master/inputs/wolf_gray.jpg",
    "https://raw.githubusercontent.com/xinntao/Real-ESRGAN/master/inputs/children-alpha.png"
  ],
  "pageUrls": ["https://en.wikipedia.org/wiki/Gray_wolf"],
  "maxImagesPerPage": 20,
  "onlyImagesNeedingAlt": true,
  "captionDetail": "detailed",
  "altTextMaxLength": 125,
  "seoFilenames": true,
  "quality": "standard"
}
```

With an empty input the Actor describes two demo images, so you can see the output with one click.

### Output example

```json
{
  "url": "https://thumb.wikimedia.org/wikipedia/commons/thumb/6/68/Eurasian_wolf_2.jpg/250px-Eurasian_wolf_2.jpg?utm_source=en.wikipedia.org&utm_campaign=parser&utm_content=thumbnail",
  "pageUrl": "https://en.wikipedia.org/wiki/Gray_wolf",
  "altStatus": "missing",
  "width": 250,
  "height": 194,
  "format": "jpeg",
  "fileSizeBytes": 19457,
  "status": "ok",
  "altText": "A gray wolf standing in the snow next to trees.",
  "altTextLength": 47,
  "caption": "The image shows a gray wolf standing in the snow, surrounded by trees. The wolf is a light brown color with darker brown patches on its fur. Its eyes are alert and its ears are perked up, giving it an inquisitive look.",
  "shortCaption": "A gray wolf standing in the snow next to trees",
  "seoFilename": "gray-wolf-standing-snow-next-trees.jpg",
  "altNeedsFix": true,
  "htmlSuggestion": "<img src=\"https://thumb.wikimedia.org/wikipedia/commons/thumb/6/68/Eurasian_wolf_2.jpg/250px-Eurasian_wolf_2.jpg?utm_source=en.wikipedia.org&utm_campaign=parser&utm_content=thumbnail\" alt=\"A gray wolf standing in the snow next to trees.\">",
  "processingSeconds": 2.07,
  "model": "Florence-2-base@512px"
}
```

The dataset has three views: **Alt text & captions**, **Page alt text audit** and **Details**. Export to JSON, CSV, Excel or HTML, or use the API. A run summary (images described, errors, CPU seconds per image) is saved as `SUMMARY` in the key-value store.

#### Alt text grades (web pages)

| Grade | Meaning | `altNeedsFix` |
|---|---|---|
| `missing` | No `alt` attribute at all | yes |
| `empty` | `alt=""`, fine only for decorative images | yes, unless the image is marked `role="presentation"` / `aria-hidden` |
| `poor` | Generic or file-name alt: "image", "photo", "IMG_1234", "banner.jpg", alt = file name, under 5 characters, or over 250 characters | yes |
| `short` | One word ("Telephone"): fine for icons and buttons, usually too vague for photos | no |
| `ok` | Looks like a real description | no (skipped when `onlyImagesNeedingAlt` is on) |

### Pricing

Pay per event, no subscription. You pay only for images that were described.

| Event | Price |
|---|---|
| Image described (alt text + caption + SEO file name, any caption detail) | **$0.006** per image ($6 per 1,000) |
| High-detail add-on (only with `quality: high`, 768 px analysis) | $0.003 per image |
| Actor start | $0.00005 per run |

Comparison with other alt text / caption Actors in the Apify Store (prices as listed in October 2026):

| Actor | Price per image |
|---|---|
| **This Actor** | **$0.006** ($0.009 with high detail) |
| seemuapps/image-captioner | $0.012 |
| myexcelsolution alt text generator | $0.01 |
| bewitching alt text generator | $0.006 |
| raional alt text generator | $0.005 |

Set **Maximum cost per run** in the run options to cap your spend: the Actor stops cleanly when the limit is reached and lists what was not processed in the summary.

### Model and license

- Model: [Florence-2-base](https://huggingface.co/microsoft/Florence-2-base) by Microsoft (0.23 B parameters). We use the native Transformers checkpoint [`florence-community/Florence-2-base`](https://huggingface.co/florence-community/Florence-2-base).
- License: **MIT**, which allows commercial use. The weights are baked into the Docker image. Nothing is downloaded from Hugging Face at run time.
- Runs on CPU. About 2 seconds per image at the default 4 GB memory (1 CPU core), plus about 5 seconds to load the model once per run.

### FAQ

**Which languages are the captions in?** English only. Florence-2 was trained on English captions.

**How accurate is it?** The short alt text is usually right about the main subject, scene and colours. Detailed captions and especially paragraphs can invent small details, such as a tail position or a brand name. Review alt text for important pages, as you would with any AI tool. It does not identify people, read long text reliably or know product names.

**Does it work for pages built with JavaScript?** It reads the HTML the server sends. Images that only appear after JavaScript runs (some galleries and infinite-scroll pages) are not found. In that case, scrape the image URLs with another Actor and pass them in `imageUrls` or `datasetId`.

**What about SVG, icons and tracking pixels?** SVGs are skipped. Images smaller than 32 px (change this with `minImageSidePx`) are skipped for free.

**Is "high" quality worth it?** It analyses the image at 768 px instead of 512 px. It helps with busy scenes and small details, but it takes about 1.8 times the CPU, so it costs an extra $0.003. For alt text, `standard` is enough in most cases.

**How fast is it?** At 4 GB, about 30 images per minute. More memory gives more CPU cores and faster runs at the same price per image.

**Can I keep my images private?** Images are downloaded and processed inside your Apify run and never sent to an external AI API.

### Use with AI agents / Apify MCP

The Actor works as a tool in the [Apify MCP server](https://mcp.apify.com) (`gazidev/image-captioner`), so Claude, ChatGPT, Cursor and other MCP clients can call it. Agents can pass `data:image/...;base64,` URIs in `imageUrls`. A typical call:

```json
{"imageUrls": ["https://example.com/product.jpg"], "captionDetail": "alt"}
```

You can also call it from the API, from Make, n8n or Zapier, or chain it after an image scraper with `datasetId`.

# Actor input Schema

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

Direct links to images (JPG, PNG, WebP, GIF, BMP, TIFF, HEIC, AVIF), one per line. `data:image/...;base64,` URIs also work (handy for AI agents). Leave empty and use `Web pages` to audit the images of a page instead.

## `pageUrls` (type: `array`):

Web page URLs. The Actor collects every <img> on the page (src, srcset, lazy-load data-src), reads the current alt text, grades it (missing / empty / poor / ok) and writes a new alt text for each image. Only images in the HTML are found (no JavaScript rendering).

## `onlyImagesNeedingAlt` (type: `boolean`):

For `Web pages`: images whose current alt text already looks good are listed as `skipped` and not described or charged.

## `maxImagesPerPage` (type: `integer`):

Stop collecting images from one page after this many.

## `captionDetail` (type: `string`):

`alt`: alt text only (fastest). `detailed` (recommended): alt text plus a 1–3 sentence caption. `paragraph`: alt text plus a longer paragraph (colours, background, layout). Same price for all three.

## `altTextMaxLength` (type: `integer`):

Alt text is cut at a word boundary to fit. 125 is the common screen-reader / SEO recommendation.

## `seoFilenames` (type: `boolean`):

Add a descriptive, hyphenated file name (e.g. `wolf-sitting-snow-looking-camera.jpg`).

## `quality` (type: `string`):

`standard` (recommended): the image is analysed at 512×512 px. `high`: 768×768 px (the model's native size), notices more small details and text but takes about 1.8x the CPU time, so it adds the `high-detail-addon` event per image.

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

0 = no limit. You can also cap the cost with the run's Maximum cost setting: the Actor stops cleanly when it is reached.

## `minImageSidePx` (type: `integer`):

Icons, spacers and tracking pixels below this width or height are skipped (not charged).

## `maxFileSizeMb` (type: `integer`):

Larger downloads are stopped and reported as errors (not charged).

## `bulkText` (type: `string`):

Paste many image URLs (one per line) or CSV text with a `url` column.

## `datasetId` (type: `string`):

ID or name of an Apify dataset (e.g. from an image or product scraper) that contains image URLs.

## `datasetField` (type: `string`):

Field name in the dataset items (a string or an array of strings).

## `proxyConfiguration` (type: `object`):

Usually not needed. Use it only if image hosts block data-centre IPs.

## Actor input object example

```json
{
  "imageUrls": [
    "https://raw.githubusercontent.com/xinntao/Real-ESRGAN/master/inputs/wolf_gray.jpg",
    "https://raw.githubusercontent.com/xinntao/Real-ESRGAN/master/inputs/children-alpha.png"
  ],
  "pageUrls": [],
  "onlyImagesNeedingAlt": false,
  "maxImagesPerPage": 50,
  "captionDetail": "detailed",
  "altTextMaxLength": 125,
  "seoFilenames": true,
  "quality": "standard",
  "maxImages": 0,
  "minImageSidePx": 32,
  "maxFileSizeMb": 20,
  "datasetField": "url",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `audit` (type: `string`):

No description

## `results` (type: `string`):

No description

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

No description

# 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://raw.githubusercontent.com/xinntao/Real-ESRGAN/master/inputs/wolf_gray.jpg",
        "https://raw.githubusercontent.com/xinntao/Real-ESRGAN/master/inputs/children-alpha.png"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("gazidev/image-captioner").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://raw.githubusercontent.com/xinntao/Real-ESRGAN/master/inputs/wolf_gray.jpg",
        "https://raw.githubusercontent.com/xinntao/Real-ESRGAN/master/inputs/children-alpha.png",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("gazidev/image-captioner").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).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://raw.githubusercontent.com/xinntao/Real-ESRGAN/master/inputs/wolf_gray.jpg",
    "https://raw.githubusercontent.com/xinntao/Real-ESRGAN/master/inputs/children-alpha.png"
  ]
}' |
apify call gazidev/image-captioner --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gazidev/image-captioner"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

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