iOS · macOS · native or React Native

Every screen in your app, checked on every PR

blinkdiff drives your app through a handful of declared journeys on every pull request, screenshots the checkpoints, diffs them against baselines committed in your repo, and comments with what moved. Intended changes are approved with one comment. It runs as a GitHub Action on your CI against your installed build, one to two minutes per flow.

baseline current 3.1% diff

How it works

  1. 01

    Declare a journey

  2. 02

    Drive, capture, diff

  3. 03

    Comment, approve, merge

A short YAML file: bundle id, a few taps and types, screenshot checkpoints. Elements are addressed by accessibility label or identifier (a React Native testID). Ten lines covers a screen.

blinkdiff launches your installed build on the simulator and walks it through the journey, step by step. At each checkpoint it waits for the screen to settle, captures it, and compares the pixels to the committed baseline for that device and OS.

The PR gets one comment that updates in place: a table per flow and a link to every changed screenshot shown as baseline, current, and diff. Intended change? Comment /blinkdiff approve and blinkdiff commits the new baselines to the branch. The check goes green.

{ } name: checkout platform: ios steps: - tap: Products - tap: Item - tap: Add to cart - tap: Cart - tap: Checkout - tap: Pay - screenshot: paid tap tap tap tap 010203040506
1. DRIVE 2. CAPTURE 3. DIFF start BASELINECURRENT = = = = PASS FAIL 0102030405
comment flow / shot changed status 01onboarding 02sign_in 03add_to_cart 04checkout 05confirmation pull request review approve merge

Why it works for any app

Native and React Native look the same to blinkdiff. SwiftUI, UIKit, AppKit and React Native apps are all driven the same way, from the same flow file, with the elements named the way your team already names them.

Baselines are PNGs in your git repo, keyed by device and OS, so they get history, blame and revert like everything else you commit.

{ } name: checkout steps: - tap: Products - tap: Item - tap: Add to cart - screenshot: cart one flow file SwiftUI React Native same capture
{ } name: signin steps: - launch - waitFor: Welcome - tap: Sign in - type: id: email text: jake@ex.io - screenshot: name: filled mask: [status] - dump: home - terminate tap type screenshot + mask dump labels + ids

Flows

A flow is the test. The steps are tap, type, clear, scroll, waitFor, menu and key on macOS, and screenshot, with optional ignore masks for regions that legitimately vary.

To write a flow for an unfamiliar screen, add - dump: home and blinkdiff writes that screen's accessibility tree next to the screenshot, listing every label and id you can tap.

Defaults for every flow live in one blinkdiff.yaml: device, appearance, thresholds, retries, masks.

Determinism

What blinkdiff pins

The simulator and OS, its appearance, and the parts of the screen that change on their own. Every capture waits for the screen to settle first. Two runs of an unchanged app come back identical, on the same machine or across machines.

What you pin

Seed the account. Mock the clock and network inside the app (launch args and env are passed through for exactly this). Mask what is legitimately volatile. Same rules as any snapshot test.

Retries

retries: 1 reruns a flow that failed to match. A one-off wobble passes on the second attempt; a real change fails every attempt and is reported.

Runs where your app already builds

blinkdiff is a GitHub Action. Your workflow builds the app for the simulator (or hands over the build from a job you already have), then the action boots the simulator, drives the flows, diffs, uploads the report and posts the comment. A second action handles /blinkdiff approve.

The runner, the artifacts and the baselines all live in your GitHub account.

Cost: macOS runner minutes you are mostly already paying for. Roughly one to two minutes per flow once the app is built, and blinkdiff can reuse the build from your existing job.

blinkdiffcommented blinkdiff: FAIL 1 of 12 screenshots differ from baseline. FLOWDEVICESHOTSSAMECHANGED signiniPhone 17541 walletiPhone 17770 signin / validation-emptychanged (3.1%) screenshots full report commit 9d8b8ea you /blinkdiff approve signin blinkdiff approve baselines pushed to branch

Pricing

Per repository. Unlimited flows, unlimited runs, every platform. Runs on your infrastructure, so there is no usage meter.

Free

$0

one repository

  • One flow
  • Full CLI, action and report
  • Enough to prove it in an afternoon
Start

Team

$249/mo

or $2,490/yr

  • Up to 5 repositories
  • Unlimited flows
  • Priority email support, one business day
Subscribe

Buy outright

$1,500

one payment · unlimited repos $4,900

  • Perpetual license, up to 5 repositories
  • One year of updates included
  • Then $600/yr for updates, optional
  • Skip it and keep the versions you have
Buy

Enterprise: invoicing, procurement paperwork, and a named person on email. $12,000/yr. info@blinkdiff.com

Questions

How is this different from Meticulous / Chromatic / Percy?
Those are web tools: they work from a DOM and a preview deploy. blinkdiff does the same job for iOS and macOS apps and runs on your CI. Meticulous records and replays real sessions; blinkdiff runs declared journeys, which is what makes its results deterministic.
How is this different from Maestro, Detox, Appium, or an AI test runner?
Those answer "does the app still work?" blinkdiff answers "does the app still look right?" It is a visual regression gate, and it sits alongside a functional test framework.
Does it work with React Native / Expo?
Yes. Elements are addressed by accessibility label or testID. Build the app for the simulator (a Release build, so no Metro is needed on the runner); from there it is identical to native.
Real devices? Android?
Simulator and macOS today; that's where determinism lives. Android is on the roadmap.
What about passwords in screenshots?
Password fields appear empty in screenshots by design. It is the same every run, so it compares clean, and screenshots stay free of passwords.
What does it cost to run?
Your own macOS runner minutes. On GitHub, macOS minutes count 10× against the free allowance and cost about $0.08 per minute beyond it. A typical check adds one to two minutes per flow on top of the app build you already run, and blinkdiff can reuse that build.
Where do the screenshots live?
In your repo, as PNGs, keyed by device and OS. Reports and comparison images go to your workflow artifacts and a branch in the same repo.