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 workflowsblinkdiff run <flow>drive one flow, diff, write the report; --open opens itblinkdiff ci [dir|flow ...]every flow, combined report, summary, results.json; what the Action callsblinkdiff approve <flow>promote a flow's staged screenshots to baselineblinkdiff promotepromote every staged flow; what the approve bot callsblinkdiff report <flow>rebuild the HTML report from the latest runblinkdiff doctorcheck Xcode, xcodegen, simulators, cacheblinkdiff license [key]store a key, or show the current license stateExit 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.