Getting started

Seven short steps, about ten minutes, one repository. Everything runs on your Mac first, then the same thing runs in CI.

01 Install

Requirements: a Mac with Xcode, xcodegen, and Node 20 or newer.

brew install xcodegen
npm i -g @blinkdiff/cli
blinkdiff doctor

doctor checks Xcode, xcodegen, and lists the simulators it can use. Green across the board means you are ready.

02 Initialize your repo

cd your-app
blinkdiff init

This writes blinkdiff.yaml (defaults every flow inherits: device, appearance, masks, retries) and flows/example.yaml to edit into your first journey. A .blinkdiff/.gitignore keeps runs and reports out of git; only baselines get committed.

03 Put your app on the simulator

blinkdiff drives an installed build by bundle id, so build and install the way you already do:

# React Native / Expo
npx expo run:ios --configuration Release --no-bundler

# native
xcodebuild -scheme YourApp -sdk iphonesimulator -configuration Release build
xcrun simctl install booted path/to/YourApp.app

04 Write a flow

A flow is a short YAML file: the bundle id, a few steps, and screenshot checkpoints. Elements are addressed by accessibility label or identifier (a React Native testID works as an id).

name: signin
platform: ios                 # ios | macos
app: com.example.app          # bundle id
steps:
  - launch
  - waitFor: Welcome
  - screenshot: welcome
  - tap: Sign in                          # label, title, or identifier
  - type: {target: Email, text: a@b.c}
  - tap: {id: submit}                     # RN testID
  - screenshot: {name: validation, mask: [{x: 0, y: 0, w: 1, h: 0.06}]}
  - terminate

Steps: launch, waitFor, tap, type, clear, scroll, dismissKeyboard, screenshot, terminate, plus menu and key on macOS. A mask hides a region that legitimately varies, like a status bar. To see every label and id on an unfamiliar screen, add - dump: home and blinkdiff writes that screen's accessibility tree next to the screenshot.

Want light and dark? Add appearance: both to the flow (or to blinkdiff.yaml for all flows) and each run captures both, with separate baselines.

05 Create baselines and commit them

blinkdiff run flows/signin.yaml     # first run creates the baseline
blinkdiff run flows/signin.yaml     # PASS · 4/4 unchanged
git add .blinkdiff/baseline flows blinkdiff.yaml
git commit -m "blinkdiff: first baselines"

Change something in the app and run again: changed screenshots are listed with the percentage of pixels that moved, the run exits non-zero, and blinkdiff run --open shows baseline, current, and diff side by side with a before/after slider. If the change is intended:

blinkdiff approve flows/signin.yaml

06 Add it to GitHub Actions

blinkdiff init --github

This adds two workflows: the PR check, and the handler for the /blinkdiff approve comment. Add your app build step where the workflow marks it, push, and every pull request gets one sticky comment: a table per flow, what changed, and a link to the report with every screenshot. Comment /blinkdiff approve and the bot commits the new baselines to the branch; the check goes green.

The runner, the artifacts, and the baselines all stay in your GitHub account. Budget one to two minutes of macOS runner time per flow once the app is built.

07 License key

The free tier runs one flow per run. A key lifts that for the repository it is activated on:

# on your Mac
blinkdiff license <key>

# in CI: add the key as a repository secret named BLINKDIFF_LICENSE
- uses: jakefleming/blinkdiff@main
  with:
    license: ${{ secrets.BLINKDIFF_LICENSE }}

Keys are checked against the license server and cached for seven days; a runner that cannot reach the server keeps working on a previously valid key. blinkdiff license with no argument shows the current state. Pricing explains what each plan covers.

Commands

blinkdiff init [--github]scaffold config, an example flow, and optionally the workflows
blinkdiff run <flow>drive one flow, diff, write the report; --open opens it
blinkdiff ci [dir|flow ...]every flow, combined report, summary, results.json; what the Action calls
blinkdiff approve <flow>promote a flow's staged screenshots to baseline
blinkdiff promotepromote every staged flow; what the approve bot calls
blinkdiff report <flow>rebuild the HTML report from the latest run
blinkdiff doctorcheck Xcode, xcodegen, simulators, cache
blinkdiff license [key]store a key, or show the current license state

Exit codes: 0 match, 1 changed, 2 usage error, 3 infrastructure (simulator, build) error.

Stuck? info@blinkdiff.com. Include the .blinkdiff/runs/<flow>/<timestamp>/ folder from a failing run and we can usually see the problem.