Crowdin
/Blog
Engineering
10 min read

How to automate screenshots for localization with Crowdin skills

Strings reach Crowdin one at a time, sorted by file, without the screen they came from. Translators see them that way, and so do AI models.

A screenshot gives that screen back: upload one, and Crowdin tags every string visible on it. The new generate-screenshots skill automates screenshots for localization: your AI coding agent takes them for you – across web, mobile, and desktop apps – and keeps them current after every release.

Why visual context matters – for translators and for AI

For example, in Headway, the learning app by Headway Inc, “Continue” heads the Library section with the summaries you’ve already started. In onboarding, it’s the button to the next screen. In Spanish, the first becomes “Seguir leyendo” (“Keep reading”) and the second “Continuar”.

Headway onboarding screen in English and Spanish: the "Continue" button becomes "Continuar"

Headway app Library in English and Spanish: the "Continue" section heading becomes "Seguir leyendo"

Without the screen, a translator has to guess which “Continue” this is, and so does an AI model. The difference is that a translator can ask in a comment, while a model picks an option and moves on – across thousands of strings in one run.

A good model with nothing to go on will still guess, so almost everything we’ve built is about telling it what each string actually is.

Claudio López Stoeckl, Globalization Manager, Headway Inc

At Headway Inc, a string like “Continue” with no screenshot gets flagged for a person to decide. Read the full story in the Headway Inc case study. In Crowdin, one screenshot serves both readers: translators see the tagged string on the screen in the Editor, and AI translation can use the same screenshot as visual context.

Why most projects still have so few screenshots

Teams know screenshots improve translation accuracy, but making them by hand is slow: someone opens the app, walks through every screen, names and uploads each file, and checks the tags, then does it again after the next release. The hardest states, like a validation error or the confirmation dialog before an account is deleted, rarely get captured at all.

Meet generate-screenshots skill

generate-screenshots is one of the Crowdin Skills – a set of instructions an AI coding agent loads to work with Crowdin. It runs from the terminal on your project’s own code, captures your app’s screens, and attaches them to the right strings in Crowdin. It works with Claude Code, Cursor, Codex, Gemini CLI, GitHub Copilot, and other agents that load Agent Skills.

  • Web, mobile, and desktop. Any web stack; iOS, Android, React Native, and Flutter; desktop apps the agent can operate on screen.
  • Captures the states people skip. The agent brings the app into states that rarely get a manual screenshot – a form showing its error messages, an open dialog or menu – and captures each one as its own screen.
  • Runs again in two commands. The capture setup lives in your repository, and each re-run updates screenshots in place.
  • Measures itself. Every run starts and ends with a count of strings that still have no screenshot.

How screenshot automation works in five steps

The agent does the repetitive work, and the developer stays in control of the decisions. Nothing is written to Crowdin or the repository before the developer approves the plan. Green steps are yours, purple ones are the agent’s.

Inventory

  • Asks Crowdin which strings have no screenshot yet
  • Groups them into screens using your app's routes and navigation

Review the plan

  • Shows you the screens it plans to capture
  • You drop the ones that don't matter, and nothing runs before your yes

Sign in once

  • You sign in to your app in the browser or simulator
  • Your password never passes through the agent

Write the capture

  • Writes one test or flow per screen: Playwright, Maestro, or XCUITest
  • Commits it to your repo, ready for the next release

Capture and upload

  • Runs the capture and checks a sample for spoiled shots
  • Uploads every image to Crowdin and auto-tags the strings on it

Skill plans one screenshot per screen, so a thousand strings collapse into a few dozen screens. Tabs, open menus, and form error states count as screens of their own. That’s how the hard-to-reach strings get covered.

When the upload is done, the count runs again. Every string that still has no screenshot lands in one of four groups:

  • Placeholder and plural strings. They are on screen, but auto-tag reads the rendered text and can’t match it to a string with placeholders. You can tag them by hand in the Editor.
  • Strings that never appear as pixels, such as alt text.
  • Reachable states not captured yet. They become new screens for the next run.
  • Strings the app never renders, such as emails and feature flags.

The finish line is a clear list of what’s left and why. Some of those strings need one more screenshot, and some never will.

What a run looks like

We ran the skill on a demo web app whose Crowdin project had no screenshots yet. The whole session took about 20 minutes – far less than a developer would need to walk through 82 screens by hand. After the plan was approved, it came down to a few commands:

Terminal window
$ crowdin string list --croql 'count of screenshots = 0' -o toon
1100 strings
$ crowdin screenshot list
No screenshot found
$ npx playwright codegen --save-storage=.crowdin/auth.json http://localhost:3000
(the developer signs in and closes the window)
$ npx playwright test -c playwright.crowdin.config.ts
$ crowdin screenshot upload .crowdin/screenshots --auto-tag
...
82 screenshots uploaded
$ crowdin string list --croql 'count of screenshots = 0' -o toon
488 strings

The agent's report after the first pass: 82 screenshots uploaded, uncovered strings down from 1,100 to 488, and two spoiled shots fixed

The first pass delivered:

  • 82 new screenshots in Crowdin
  • Strings without a screenshot down from 1,100 to 488
  • A tag on every image: 5 to 43 tags each, 1,913 in total
  • Two spoiled shots caught and re-shot: the agent reviewed 13 of the 82 images and found a form heading hidden under a sticky header and an accordion captured mid-animation

Screenshots tab in Crowdin with 82 uploaded screenshots and a tag count on each

Some of the most useful shots are ones a person rarely thinks to take. The agent submitted forms empty to bring up their error messages and opened the confirmation dialog before deleting an account. Each state became its own screenshot, so strings that appear only when something goes wrong got context too.

Invite dialog with an email validation error

Contact form showing required-field error messages

The report then sorted the remaining 488 strings by cause:

What’s leftExamples from the runMore screenshots?
Tabs and dropdowns that weren’t openedFeature tabs past the first one; status and sort optionsYes, a few extra shots
Validation messages beyond the empty formInvalid email, text too long, mismatched passwordsYes, several form states
Other content pagesMore blog posts, careers roles, pricing dataYes, at lower value
Toasts”Link copied”Yes, though they disappear quickly
Alt text and accessibility labelsLogo and map descriptionsNo, they never appear as pixels
Plural and interpolated strings”2 projects selected”No, they are already on screen; tag them by hand in the Editor

The next step is clear from the table: a few more screens for the reachable states, manual tags for plurals, and nothing for the strings that never appear on screen.

Built for the next release

File name is a screenshot’s identity in Crowdin. Upload settings-profile.png again, and the new image replaces the old one in place and keeps its ID. A re-run after a redesign creates no duplicates and needs no deletions. The same screen on two platforms gets two names, such as settings-ios.png and settings-android.png. The upload folder holds only the screens captured in the current run, so screenshots nobody re-shot keep their tags.

The capture itself stays in your repository. Spec file records which screens exist and how to reach them, and it goes through pull request review like any other code. After the next release, you run the same two commands for the screens that changed.

Skill captures with your platform’s own tooling and picks what your project already has:

PlatformEngineWhen the skill uses it
WebPlaywrightDefault for any web app. One test per screen, with its own config, so your normal test run never sees it.
MobileMaestroDefault for iOS, Android, React Native, and Flutter apps without UI automation of their own. One YAML flow per screen.
Native iOSXCUITestOnly when the project already has a UI test target.
ExposcreenmapOnly when the project already uses it.
DesktopComputer useFor desktop apps, a few one-off states, or teams that want no test code. Nothing lands in the repo, so each re-run needs a new session.

Any engine that writes named PNGs into the folder works, so teams on Detox, Espresso, or Flutter integration tests keep their tooling. When no engine can run on the machine, the skill switches to publish-only: you drop your own screenshots into the folder, named after the plan, and the skill uploads them and reports coverage.

Where teams use it

  • First screenshots ever. A project with hundreds of strings and no screenshots gets a few dozen screens in one session, plus a committed capture to keep them current.
  • After a redesign. A top-up run captures only the new and changed screens. Same file names, so old images are replaced, and nothing is duplicated or deleted.
  • Mobile on two platforms. The same Maestro flows run on iOS and Android. Captures carry a platform suffix, so translators see both layouts where they differ.
  • Onboarding to Crowdin. The i18n-setup skill offers screenshots as an add-on at the end of setup, right after strings are uploaded and textual context is written.
  • Screen-by-screen translation. Screens Translation shows screenshots instead of files on the language page, so translators work one screen at a time. This skill keeps those screens current.
  • Desktop apps without test code. For an Electron app, for example, an agent with computer use walks the app itself and captures it with the machine’s own commands. The report keeps the screen list, so the next run starts from a plan.

How to get started

To run the skill, you need:

  • A project connected to Crowdin through the Crowdin CLI, with crowdin.yml holding the project ID and strings already uploaded
  • A terminal with the CLI authorized
  • An app that runs locally
  • An AI coding agent that loads Agent Skills, such as Claude Code, Cursor, Codex, Gemini CLI, or GitHub Copilot

Install it with the rest of the Crowdin Skills, or on its own:

Terminal window
npx skills add crowdin/skills --skill generate-screenshots

generate-screenshots is part of crowdin/skills. Its sibling skills cover the rest of the setup: crowdin-cli for every CLI command, context-extraction for textual string context, and i18n-setup for the path from hardcoded strings to a connected project.

More guides on working with Crowdin from your coding agent:

Give every string its screen

A string without its screen leaves translators and AI models to guess. With generate-screenshots, your coding agent captures the screens, Crowdin links each one to the strings on it, and the next release takes two commands. Translators see where every word lives, AI translation gets the same visual context, and people stay in control of the calls that need their judgment.

Install the skill from crowdin/skills and run it on your next release. New to Crowdin? Start a free trial.

Localize your product with Crowdin

Automate content updates, boost team collaboration, and reach new markets faster.
Free 14-day Trial
Crowdin Team

Crowdin Team