Skip to content
DocsAgents and CI
Docs / Screenshots / Screenshots from agents and CI

Screenshots from agents and CI

Let your coding agent capture and compose store screenshots over MCP, keep the recipe in demotake.json, and regenerate every size in CI when the UI changes, skipping screens that didn't.

MCP toolsdemotake CLISteps: DemoTake Agent

Screenshots are made for automation. An agent can open the right screen, capture it, write the headline and export every size in one conversation. And the same recipe can live in your repository as code, so CI regenerates the screenshots on every release.

Ask your agent

With DemoTake connected (see Connect your agent), ask in plain words:

Take App Store screenshots of the dashboard and settings screens of the app we just built, with a headline on each, and export iPhone, iPad and Google Play sizes.

  1. screenshot_formatssizes and ids
  2. screenshot_captureper screen
  3. screenshot_composeheadlines · frame · previews
  4. screenshot_exportexact sizes + manifest
The tools an agent calls, in order.

In DemoTake Agent, screenshot_capture can reach the screen first with steps, in the same vocabulary as demo specs:

screenshot_capture
{
  "target": "app:com.example.Tidewell",
  "shot": "Settings",
  "headline": "Alerts your way",
  "steps": [{ "key": "cmd+," }, { "wait": "General" }]
}

During a recorded take, take_checkpoint with screenshot: true captures the scene's stable screen into a set named after the take, so one run gives you a demo video and its store screenshots. See the MCP tool reference for every parameter.

Screenshots as code

Add a screenshots section to demotake.json. Each shot names a screen, the steps that reach it, and its words. A spec can have only screenshots, only takes, or both.

demotake.json
{
  "version": 1,
  "target": { "bundle_id": "com.example.Tidewell" },
  "screenshots": {
    "set": "Tidewell store screenshots",
    "formats": ["iphone", "ipad", "play", "og"],
    "style": { "background": "midnight", "device_frame": "auto", "typography": "modern" },
    "shots": [
      {
        "name": "Dashboard",
        "headline": "Every metric at a glance",
        "steps": [{ "click": "Overview" }, { "wait": "Good morning" }]
      },
      {
        "name": "Settings",
        "headline": "Alerts your way",
        "steps": [{ "key": "cmd+," }, { "wait": "General" }],
        "redact_regions": [{ "x": 0.62, "y": 0.08, "width": 0.3, "height": 0.05 }]
      },
      { "name": "Phone", "capture": { "target": "sim:6C1F0B7E-3A2D-4F4B-9C1E-2B7D5A8E9F10" } }
    ]
  }
}
Shot field What it does
name Identifies the shot across runs and names its files
headline, subheadline The words on the screenshot
setup, steps Steps that reach the screen: click, type, key, scroll, wait and the assert_* checks
capture The target window (default), "display", a target id such as "sim:<UDID>", or { "rect": { "x", "y", "width", "height" } } in screen points
redact Secret Guard on the capture (default true)
redact_regions Regions to hide, 0 to 1 of the capture
formats Formats for this shot only

The set-level formats, style, headline, subheadline, file_type (png or jpeg) and setup apply to every shot. demotake schema prints the full JSON Schema for editor completion.

Run it

Terminal
demotake screenshots validate demotake.json
demotake screenshots run demotake.json --out store-screenshots
demotake screenshots run demotake.json --out store-screenshots --only-changed --junit reports/screenshots.xml
demotake screenshots formats
Terminal
$ demotake screenshots run demotake.json --out store-screenshots --only-changed
✓ PASS  Tidewell store screenshots  4.2s
    = Dashboard  unchanged, footage kept
    ✓ Settings  0.9s · UI changed
8 screenshot(s) in store-screenshots (2 written, 7 unchanged)
  • --out copies the export tree and manifest.json into a folder (default screenshots). Files whose bytes didn't change aren't rewritten, so your repository only sees real changes.
  • --only-changed compares each new capture with the last one of the same shot, with the same perceptual diff demo specs use, ignoring hidden regions. Shots whose screen didn't change keep their capture and their files, byte for byte.
  • --shot Home,Settings and --formats iphone,og run part of the spec; --file-type jpeg exports JPEG.
  • --junit writes a JUnit report with one test case per shot.

Exit codes are the same as the other demotake commands: 0 ok, 1 a shot failed or the spec is invalid, 2 usage error, 3 DemoTake isn't reachable, 4 DemoTake reported an error. If a shot fails, nothing is exported, so a broken build never overwrites good screenshots.

In CI

Run it on the same self-hosted Mac runner as your demo specs (see Demo specs and CI): build and launch the app, then run demotake screenshots run … --only-changed and upload the folder as an artifact or commit it. Specs whose shots have no steps also run in DemoTake Studio; steps need DemoTake Agent, which operates the app.

Tip:

Keep the screenshots folder in the repository. With --only-changed and byte-stable rendering, a pull request that doesn't touch the UI doesn't change a single screenshot file.

Was this page helpful?