Auto-generate alt text for images
Describe a folder of Northwind images for accessibility — one prompt per image.
Published Oct 14, 2025
Northwind’s marketing site has hundreds of images and almost none of them have alt text. Writing a one-sentence description for every image is the kind of accessibility job that is genuinely important and reliably never gets done — it is slow, repetitive, and easy to defer.
This script clears the backlog. It walks a Drive folder of images, sends each one to Claude’s vision model, and asks for a concise one-sentence description. The results land in a sheet — filename, alt text, and a link to the image — so a person can skim them, fix anything off, and paste the descriptions into the site. The slow part is done; the review is fast.
What you’ll need
- A Google Drive folder containing the images you want described.
- A Google Sheet to collect the results — the script appends to its first tab.
- An Anthropic API key saved as
ANTHROPIC_API_KEYin Script Properties — see Store API keys and secrets securely. - The folder ID and sheet ID, which you pass to the function when you run it.
The script
// Claude vision model used to describe each image.
const VISION_MODEL = 'claude-haiku-4-5-20251001';
// The instruction sent with every image.
const ALT_TEXT_PROMPT = 'Write a concise alt text for this image, 1 sentence.';
/**
* Walks a Drive folder, asks Claude to describe every image, and writes
* the filename, alt text, and image URL to a sheet.
*
* @param {string} folderId The Drive folder of images to describe.
* @param {string} sheetId The spreadsheet that collects the results.
*/
function generateAltText(folderId, sheetId) {
const files = DriveApp.getFolderById(folderId).getFiles();
const sheet = SpreadsheetApp.openById(sheetId).getSheets()[0];
let count = 0;
// 1. Step through every file in the folder.
while (files.hasNext()) {
const file = files.next();
// 2. Skip anything that is not an image — PDFs, docs, and so on.
if (!file.getMimeType().startsWith('image/')) continue;
// 3. Read the image bytes and base64-encode them for the API payload.
const b64 = Utilities.base64Encode(file.getBlob().getBytes());
// 4. Ask Claude's vision model for a one-sentence description.
const alt = callClaudeWithImage(ALT_TEXT_PROMPT, b64, file.getMimeType());
// 5. Record the result: filename, alt text, and a link to the image.
sheet.appendRow([file.getName(), alt, file.getUrl()]);
count++;
}
Logger.log('Described ' + count + ' images.');
}
/**
* Sends one image plus a text prompt to the Anthropic API and returns
* the model's reply. The API key lives in Script Properties.
*
* @param {string} prompt The instruction to send with the image.
* @param {string} b64 The base64-encoded image bytes.
* @param {string} mime The image MIME type, e.g. "image/png".
* @return {string} The model's text reply.
*/
function callClaudeWithImage(prompt, b64, mime) {
const key = PropertiesService.getScriptProperties()
.getProperty('ANTHROPIC_API_KEY');
const res = UrlFetchApp.fetch('https://api.anthropic.com/v1/messages', {
method: 'post',
contentType: 'application/json',
headers: { 'x-api-key': key, 'anthropic-version': '2023-06-01' },
payload: JSON.stringify({
model: VISION_MODEL,
max_tokens: 100,
messages: [{
role: 'user',
content: [
{ type: 'image', source: { type: 'base64', media_type: mime, data: b64 } },
{ type: 'text', text: prompt },
],
}],
}),
muteHttpExceptions: true,
});
return JSON.parse(res.getContentText()).content[0].text.trim();
}
How it works
generateAltTextopens the Drive folder and the results sheet, then steps through every file in the folder one at a time.- It checks each file’s MIME type and skips anything that does not start with
image/, so stray PDFs or documents in the folder are ignored. - For each image it reads the raw bytes and base64-encodes them — the format the Anthropic API expects for inline images.
- It calls
callClaudeWithImage, which sends the encoded image and the prompt to Claude’s vision model and returns a one-sentence description. - It appends a row to the sheet with the filename, the generated alt text, and a Drive link to the original image, so a reviewer can compare description to picture in one place.
callClaudeWithImagereads the API key from Script Properties, builds a multi-part message (the image then the text), and returns the trimmed reply.
Example run
Point the script at a folder of three product photos and an empty results sheet. After a run, the sheet’s first tab holds:
| Filename | Alt text | Link |
|---|---|---|
| header-banner.jpg | A team of four collaborating around a laptop in a bright office. | drive.google.com/… |
| product-shot-1.png | A blue ceramic mug on a wooden desk beside an open notebook. | drive.google.com/… |
| warehouse.jpg | Rows of tall storage shelves stacked with cardboard boxes. | drive.google.com/… |
A reviewer reads three sentences instead of writing them, tweaks the one that is slightly off, and the alt text is ready for the site.
Run it
This is an on-demand job — you run it when a batch of images needs describing:
- In the editor, add a small wrapper that passes your IDs, or run
generateAltTextfrom a custom function call with the folder and sheet IDs. - Click Run and approve the authorisation prompt the first time.
- Open the results sheet and review the descriptions.
function runAltText() {
generateAltText('1abcFolderId', '1abcSheetId');
}
Watch out for
- Each image is a separate API call, so a large folder means a long run. Apps
Script caps a single execution at six minutes — for hundreds of images,
process the folder in batches or move already-done files to a
processedsubfolder so reruns skip them. - Vision API calls cost more than text calls and use your token budget. Check Anthropic’s pricing before running this over a very large library.
- The script appends rather than de-duplicates. Running it twice on the same folder writes every image again — clear the sheet first, or track processed files, if you plan to rerun.
- Very large images can push the request size up and slow things down. Resize oversized photos before describing them if calls start timing out.
- Generated alt text still needs a human eye. The model describes what it sees, but it cannot know the image’s purpose on the page — a reviewer should always skim the results before they go live.
muteHttpExceptionskeeps the loop from crashing on a single bad response, but it also means a failed call returns junk. Log and check the output if a row’s alt text looks wrong.
Related
Generate and test email subject lines
A/B test AI-written Northwind subject lines for open rate — outputs ranked by past performance.
Updated Mar 3, 2026
Build retrieval-augmented Q&A over your data
Answer Northwind questions grounded in your own Sheet data — pass relevant rows as context.
Updated Feb 27, 2026
Build an AI weekly-report narrator
Turn Northwind metrics into a written executive summary — numbers in, prose out.
Updated Feb 23, 2026
Build a multi-step AI agent workflow
Chain Claude prompts to complete a Northwind task end to end — research → draft → critique → finalise.
Updated Feb 11, 2026
Adapt marketing copy per region
Localise Northwind tone and references by market with AI — same message, regional flavour.
Updated Jan 30, 2026