Concepts
Captures
Section titled “Captures”A capture is a set of screenshots taken at a point in time. Every time you run pxdiff storybook, pxdiff ladle, pxdiff capture, pxdiff upload, or a test with toMatchPxdiff, pxdiff creates a capture tied to your current branch and commit.
A diff compares a capture against baselines and produces a report. Each snapshot is classified as unchanged, changed, or new. Changed snapshots show a pixel-level diff overlay highlighting exactly what’s different.
Run pxdiff diff after a capture to generate the comparison, or wrap your test command with pxdiff which handles it automatically.
Baselines
Section titled “Baselines”A baseline is the expected screenshot for a given snapshot name. When you approve a changed or new snapshot (via the review UI or pxdiff approve), that screenshot becomes the new baseline. Future diffs compare against it.
Baselines are scoped per-suite. When a snapshot isn’t captured in the current run, the previous baseline carries forward automatically.
How baselines are found
Section titled “How baselines are found”When you run a diff, pxdiff needs to find the right baseline to compare against. It looks at multiple branches in order — the first match wins:
- Branch baseline — a baseline set directly on the current branch (from a previous approval)
- Target refs — baselines on ancestor branches, resolved via git
Target refs are the key mechanism. Before creating a diff, the CLI (or plugin) asks: “which branches have baselines, and which of those are git ancestors of my current branch?” It does this by:
- Calling the API to get all refs with baselines for the suite (e.g.,
["main"]) - Running
git merge-basefor each to check if it’s an ancestor of HEAD - Sending the matching refs as
targetRefsto the server
This means pxdiff works with any branching model — feature branches, stacked PRs, staging branches, release branches. As long as a baseline ref is a git ancestor, it’s found automatically.
Example: feature branch targeting staging
Section titled “Example: feature branch targeting staging”main (baselines here) └── staging (no baselines) └── feat/x (your PR)When you diff feat/x, the CLI discovers that main has baselines and is a git ancestor. It sends targetRefs: ["staging", "main"]. The server checks staging first (no baselines), then main (found) — your snapshots diff against main’s baselines.
Explicit overrides
Section titled “Explicit overrides”--target-ref main --target-ref staging— specify target refs manually (repeatable flag)--baseline-ref main— shorthand for a single target refGITHUB_BASE_REF— automatically included when set (GitHub Actions sets this on PRs)PXDIFF_BASELINE_REF— environment variable override
Auto-baseline
Section titled “Auto-baseline”Pass --auto-baseline to capture commands (pxdiff storybook, pxdiff ladle, pxdiff capture, pxdiff upload) to set baselines directly from captured screenshots without running a diff. Useful for initial setup or when merging to the default branch.
Auto-approve
Section titled “Auto-approve”Pass --auto-approve to pxdiff diff to automatically approve all changes and set baselines. Unlike --auto-baseline, this still runs the diff so you can see what changed, but all changes are approved immediately.
Suites
Section titled “Suites”A suite groups snapshots with independent baselines. For example, you might have a storybook suite and a playwright suite — each with their own set of baselines that don’t interfere with each other.
Set the suite name via --suite on CLI commands, or in plugin configuration.
Authentication
Section titled “Authentication”Local development: Run pxdiff login to authenticate via your browser, then pxdiff project set myorg/myproject to link your directory to a project.
CI: Use a project-scoped API key. Create one from your project settings, then set it as a repository secret:
export PXDIFF_API_KEY=pxd_your_key_hereAPI keys are prefixed with pxd_ and scoped to a single project. See API Keys for setup, rotation, and security best practices.
Local vs CI
Section titled “Local vs CI”CI mode
Section titled “CI mode”CI captures are tied to a branch and commit. Diffs compare against baselines from the baseline ref (usually main). Approvals update baselines for the whole team. This is the authoritative workflow — when a PR’s visual tests pass, everyone can trust the result.
Local mode
Section titled “Local mode”Local captures are ephemeral — they don’t affect baselines for other users and are displayed separately in the review UI. Use local mode to iterate quickly without impacting the team’s baselines.
pxdiff auto-detects local mode when the CI environment variable is not set:
pxdiff -- npx playwright testLocal behavior by integration
Section titled “Local behavior by integration”Storybook and Ladle always capture against a Linux Chromium environment, so screenshots are pixel-identical regardless of your local OS. There are two supported flows:
- Static build → cloud capture (
pxdiff storybook ./storybook-static,pxdiff ladle ./build) — uploads the built site to pxdiff’s cloud infrastructure for capture. No local prerequisites beyond the CLI. - Running dev server → local Docker capture (
pxdiff storybook --port 6006,pxdiff ladle --port 61000) — captures against a dev server you’re already running, via a local Linux Docker container that uses the same Chromium image as cloud capture. Requires Docker. Always treated as local mode — captures are ephemeral and user-scoped, even whenCIis set. Use the static-build path in CI.
Both paths can diff against CI baselines from any branch — you get real baseline comparison locally.
Test framework plugins (Playwright, Vitest) capture screenshots on your machine. Because different operating systems render fonts and pixels differently, CI baselines (captured on Linux in GitHub Actions) aren’t directly comparable to local screenshots — unless you use the --docker flag.
Without --docker: Local test runs compare against your own previous local runs:
- Run tests locally — first run establishes your local baselines (everything is “new”)
- Make changes, run again — diffs show what changed since your last local run
- Push to CI — the authoritative diff against team baselines happens here
With --docker: Tests run inside a consistent Linux container, producing pixel-identical screenshots to CI. Local runs can diff directly against CI baselines:
pxdiff --docker -- npx playwright testSee the Docker guide for setup details.