No more images without ALT in your docs

Alt Text BYOK is a GitHub Action: on every pull request it finds the images in your Markdown, MDX, HTML, JSX and TSX files whose ALT is missing, empty or a placeholder (image, screenshot, IMG_2041, the file name…), looks at the image itself and writes a real description — committed to the PR, or proposed as one-click review suggestions. It runs in your own Actions runner with your own vision AI key: no server of ours, no credits, no monthly plan. The accessibility gate is free; Pro is $39 per year per organization, no auto-renewal.

Get the Pro key — $39/year Install free

The problem

Screenshots go into READMEs and docs as ![](screenshot.png) or <img src="hero.png">, because writing a description is the step nobody has time for in a PR. Screen-reader users hear “image” or a file name, image search sees nothing, and accessibility audits (WCAG 1.1.1, the European Accessibility Act) flag every one of them.

This action fixes it where it starts: in the same pull request. Before and after, on a README:

README.md   before
- ![](docs/img/dashboard.png)
- ![screenshot](docs/img/settings.png)
- <img src="docs/img/logo.svg" alt="">

README.md   after (commit by github-actions[bot])
+ ![Dashboard showing weekly signups as a bar chart, with a 12% increase highlighted](docs/img/dashboard.png)
+ ![Settings page with the API key field and the provider dropdown set to OpenAI](docs/img/settings.png)
  <img src="docs/img/logo.svg" alt="">      ← alt="" is decorative (WCAG): left alone

Example output. The paragraph before each image is sent as context, so the description fits the text around it. alt={t('…')} and other code-generated ALT are left alone; SVG, images over 8 MB and dynamic src={var} are listed in the job summary instead.

Install in 2 minutes

Add your provider key as the repository secret AI_API_KEY, then save this as .github/workflows/alt-text.yml.

.github/workflows/alt-text.yml
# .github/workflows/alt-text.yml
name: Alt text
on:
  pull_request:
    paths: ['**.md', '**.mdx', '**.html', '**.jsx', '**.tsx']
permissions: { contents: write, pull-requests: write }
jobs:
  alt-text:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { ref: "${{ github.head_ref }}" }
      - uses: lumnika/alt-text-action@v1
        with:
          mode: fix              # or: suggest (review comments), check (gate only)
          provider: openai       # anthropic, gemini, openrouter, groq, mistral, custom
          ai-api-key: ${{ secrets.AI_API_KEY }}
          # language: Italian                          # free: one fixed language
          # license-key: ${{ secrets.LICENSE_KEY }}   # Pro: no limit + language: auto

Just want the gate? No AI key, no write permission — the job fails with one annotation per image without ALT:

      - uses: actions/checkout@v4
      - uses: lumnika/alt-text-action@v1
        with: { mode: check }

Marketplace listing coming soon: until then the action is distributed directly to customers — write to deus@lumnika.com for early access.

Free vs Pro

FreePro
check gate (any number of images)yesyes
fix (commit) and suggest (review suggestions)yesyes
Providers: OpenAI, Anthropic, Gemini, OpenRouter, Groq, Mistral, any OpenAI-compatibleyesyes
Images described per run20 (the rest on the next run)no limit
Languageone, fixedlanguage: auto — each document in its own language
Pricefree$39 per year per organization

Get the Pro key

The license key is shown right after payment. Save it as the repository or organization secret LICENSE_KEY and uncomment the license-key line in the workflow. From the next pull request on: every image described in one run, in the language of each document.

$39 per year, per organization, no auto-renewal
Get the Pro key

🔒 Secure checkout by Stripe, your card details never touch our servers · 7-day money-back guarantee, no questions asked (deus@lumnika.com) · no account required.

What 100 images cost

One short vision call per image. Token counts per image from the providers' documentation, plus about 150 tokens of instructions and context in and 60 tokens out:

Option100 imagesPer year, at 100 images a month
Gemini 2.5 Flash-Lite, your key ($0.10 / $0.40 per 1M tokens)≈ $0.01≈ $0.11 + $39 Pro
OpenAI gpt-4.1-nano, your key ($0.10 / $0.40)≈ $0.02≈ $0.28 + $39 Pro
OpenAI gpt-4.1-mini, your key ($0.40 / $1.60)≈ $0.07≈ $0.78 + $39 Pro
Claude Haiku 4.5, your key ($1 / $5)≈ $0.15≈ $1.78 + $39 Pro
AltText.ai Bronze (100 credits/month)$5$60
ImageSEO Starter (100 credits/month)€4.99≈ €60

Your own numbers, every provider: alt text cost calculator (official prices with sources, checked 30 September 2026). Under 20 images per pull request the free tier is enough and you only pay your tokens. On private repositories the job also uses your GitHub Actions minutes.

FAQ

Will it rewrite ALT text a human wrote?
No. Only missing, empty-in-Markdown or placeholder ALT (image, photo, a file name…) is touched. alt="" in HTML/JSX means decorative and is left alone, and so is any ALT built in code.
Which files does it scan?
On a pull request, only the files the PR changed (only-changed: false scans the whole repository, e.g. on a weekly schedule). Code fences, inline code and HTML comments are ignored.
Where do my images go?
Only to the AI provider you configured, from your own runner. The Pro license check receives only the license key and the repository name.
Commit or suggestions?
fix commits to the PR branch as github-actions[bot]; suggest posts one review with a suggestion per line, accepted with one click; check only reports and fails the job.
What if the AI provider or the license check fails?
Transient AI errors are retried once and never fail the build: the remaining images wait for the next run. A missing or invalid license runs the free mode; the action never fails your build because of the license.
Is this a subscription?
No auto-renewal: $39 buys a key valid for one year for your organization's repositories. You pay your AI provider only for the tokens you use.

Get the Pro key — $39/year

Images in a WordPress media library rather than a repository? The Alt Text BYOK WordPress plugin fills missing ALT in bulk and on upload, with the same bring-your-own-key model.