CLI Reference
The @pxdiff/cli package is the main entry point for visual regression testing with pxdiff.
Installation
Section titled “Installation”npm install -g @pxdiff/cliAuthentication
Section titled “Authentication”Interactive login (recommended for local development)
Section titled “Interactive login (recommended for local development)”pxdiff loginOpens your browser to authenticate via GitHub. After login, link a project to your directory:
pxdiff project set myorg/myprojectAPI key (recommended for CI)
Section titled “API key (recommended for CI)”For CI environments, use a project-scoped API key. Pass it via --api-key or set PXDIFF_API_KEY:
export PXDIFF_API_KEY=pxd_your_key_hereAPI keys take precedence over stored login credentials.
Commands
Section titled “Commands”pxdiff storybook
Section titled “pxdiff storybook”Capture and diff a Storybook — either from a static build (cloud capture) or a running dev server (local Docker capture).
pxdiff storybook <dir> [options] # static build → cloud capturepxdiff storybook --port <port> [options] # running dev server → local Docker captureEither a static build directory (<dir>) or --port is required.
| Argument | Description |
|---|---|
dir | Path to the static Storybook build directory |
| Flag | Type | Default | Description |
|---|---|---|---|
--port | string | Port of a running Storybook dev server. Captures via a local Linux Docker runner and follows normal mode detection (CI → CI mode, otherwise local mode). Use --local or --ci to override. Requires Docker. Not supported with --only-changed. | |
--suite | string | "default" | Suite name for grouping snapshots |
--filter | string | Glob pattern to filter discovered stories (e.g. "Button*", "**/primary") | |
--auto-baseline | boolean | false | Set baselines from captured screenshots (no diff) |
--auto-approve | boolean | false | Automatically approve all changes and set baselines |
--skip-diff | boolean | false | Skip automatic diff after capture |
--status | boolean | false | Post a GitHub check run and exit 0 (delegates pass/fail to the check run) |
--threshold | string | Diff threshold 0.0–1.0 | |
--ephemeral | boolean | false | No branch/commit tracking |
--local | boolean | false | Run in local mode (also set via PXDIFF_LOCAL=true) |
--ci | boolean | false | Force CI mode (strict auth, GitHub check runs) |
--framework | string | Framework hint applied to all targets | |
--branch | string | Branch name (auto-detected from git) | |
--commit | string | Commit hash (auto-detected from git) | |
--only-changed | boolean | false | Only capture stories affected by code changes (requires --stats-json Storybook build). Static-build path only — not supported with --port. |
--output | string | "text" | Output format: text or json |
--api-key | string | API key (falls back to PXDIFF_API_KEY) | |
--api-url | string | API URL (falls back to PXDIFF_API_URL) |
Static build workflow (<dir>):
- Tars and gzips the Storybook directory
- Uploads the archive to pxdiff
- Discovers stories automatically
- Explodes stories into capture targets (respecting modes, viewports, parameters)
- Filters targets if
--filteris set - If
--only-changed, traces the Storybook module graph to identify affected stories and skips unchanged ones - Creates the capture on the pxdiff fleet
Local dev server workflow (--port):
- Checks that Docker is available and detects the installed Playwright version
- Pulls or builds a matching
pxdiff-runnercontainer image - Creates a session-scoped capture using the detected mode
- Runs Chromium inside the container, hitting your dev server at
http://host.docker.internal:<port> - Uploads captured snapshots to the session
- Runs the diff locally (unless
--skip-diff/--auto-baseline)
In local mode, captures are ephemeral and scoped to you — they do not update shared baselines or post CI check runs. In CI mode, the --port path can post CI results while still using the local Docker runner for browser rendering.
# Static buildpxdiff storybook ./storybook-static
# Running dev server (Storybook's default port)pxdiff storybook --port 6006
# Filter to specific storiespxdiff storybook ./storybook-static --filter "Button*" --suite ui
# JSON output for CI parsingpxdiff storybook ./storybook-static --output jsonpxdiff ladle
Section titled “pxdiff ladle”Capture and diff a Ladle catalog — either from a static build (cloud capture) or a running dev server (local Docker capture).
pxdiff ladle <dir> [options] # static build → cloud capturepxdiff ladle --port <port> [options] # running dev server → local Docker captureEither a static build directory (<dir>) or --port is required.
| Argument | Description |
|---|---|
dir | Path to the static Ladle build directory |
| Flag | Type | Default | Description |
|---|---|---|---|
--port | string | Port of a running Ladle dev server. Captures via a local Linux Docker runner and follows normal mode detection (CI → CI mode, otherwise local mode). Use --local or --ci to override. Requires Docker. | |
--suite | string | "default" | Suite name for grouping snapshots |
--filter | string | Glob pattern to filter discovered stories (e.g. "Badge*", "*--primary") | |
--auto-baseline | boolean | false | Set baselines from captured screenshots (no diff) |
--auto-approve | boolean | false | Automatically approve all changes and set baselines |
--skip-diff | boolean | false | Skip automatic diff after capture |
--status | boolean | false | Post a GitHub check run and exit 0 (delegates pass/fail to the check run) |
--threshold | string | Diff threshold 0.0–1.0 | |
--ephemeral | boolean | false | No branch/commit tracking |
--local | boolean | false | Run in local mode (also set via PXDIFF_LOCAL=true) |
--ci | boolean | false | Force CI mode (strict auth, GitHub check runs) |
--branch | string | Branch name (auto-detected from git) | |
--commit | string | Commit hash (auto-detected from git) | |
--output | string | "text" | Output format: text or json |
--api-key | string | API key (falls back to PXDIFF_API_KEY) | |
--api-url | string | API URL (falls back to PXDIFF_API_URL) |
Static build workflow (<dir>):
- Tars and gzips the Ladle build directory
- Uploads the archive to pxdiff
- Discovers stories from
meta.json - Explodes stories into capture targets
- Filters targets if
--filteris set - Creates the capture on the pxdiff fleet
Local dev server workflow (--port):
- Checks that Docker is available and detects the installed Playwright version
- Pulls or builds a matching
pxdiff-runnercontainer image - Creates a session-scoped capture using the detected mode
- Runs Chromium inside the container, hitting your dev server at
http://host.docker.internal:<port> - Uploads captured snapshots to the session
- Runs the diff locally (unless
--skip-diff/--auto-baseline)
In local mode, captures are ephemeral and scoped to you — they do not update shared baselines or post CI check runs. In CI mode, the --port path can post CI results while still using the local Docker runner for browser rendering.
# Static buildpxdiff ladle ./build
# Running dev server (Ladle's default port)pxdiff ladle --port 61000
# Filter to specific storiespxdiff ladle ./build --filter "Badge*" --suite components
# JSON output for CI parsingpxdiff ladle ./build --output jsonLadle parameters: You can control capture behavior per-story using the meta.pxdiff field in your Ladle stories:
export const MyStory = () => <Component />;MyStory.meta = { pxdiff: { delay: 500, // Wait 500ms before capture selector: ".wrapper", // Capture specific element cropToViewport: true, // Crop to viewport bounds ignoreSelectors: [".timestamp"], // Hide dynamic elements disable: false, // Set true to skip this story },};pxdiff capture
Section titled “pxdiff capture”Submit screenshot targets from a JSON targets file for capture via the pxdiff fleet.
pxdiff capture <targets-file> [options]| Argument | Description |
|---|---|
targets-file | Path to JSON file containing capture targets (required) |
| Flag | Type | Default | Description |
|---|---|---|---|
--suite | string | "default" | Suite name |
--auto-baseline | boolean | false | Set baselines from captured screenshots (no diff) |
--ephemeral | boolean | false | No branch/commit tracking |
--local | boolean | false | Local mode |
--framework | string | Framework hint for all targets | |
--branch | string | Branch name (auto-detected) | |
--commit | string | Commit hash (auto-detected) | |
--output | string | "text" | text or json |
--api-key | string | API key | |
--api-url | string | API URL |
The targets file is a JSON array of objects:
[ { "name": "homepage", "url": "https://your-app.com", "viewport": { "width": 1280, "height": 720 } }, { "name": "mobile-homepage", "url": "https://your-app.com", "viewport": { "width": 375, "height": 812 } }]pxdiff upload
Section titled “pxdiff upload”Upload a directory of pre-existing PNG files as a capture. This is the “bring your own screenshots” workflow.
pxdiff upload <directory> [options]| Argument | Description |
|---|---|
directory | Directory containing .png files (required) |
| Flag | Type | Default | Description |
|---|---|---|---|
--suite | string | "default" | Suite name |
--auto-baseline | boolean | false | Set baselines from captured screenshots (no diff) |
--ephemeral | boolean | false | No branch/commit tracking |
--local | boolean | false | Local mode |
--branch | string | Branch name (auto-detected) | |
--commit | string | Commit hash (auto-detected) | |
--api-key | string | API key | |
--api-url | string | API URL |
Snapshot names are derived from filenames (minus the .png extension).
pxdiff upload ./screenshots --suite e2epxdiff diff
Section titled “pxdiff diff”Compare a capture against baselines and produce a diff report.
pxdiff diff [options]| Flag | Type | Default | Description |
|---|---|---|---|
--suite | string | "default" | Suite name |
--head-capture | string | Head capture ID (auto-detected from current commit if omitted) | |
--base-capture | string | Base capture ID for capture-vs-capture comparison | |
--baseline-ref | string | Baseline ref to compare against (auto-resolved if omitted) | |
--auto-approve | boolean | false | Automatically approve all changes and set baselines |
--threshold | string | Diff threshold 0.0–1.0 | |
--anti-aliasing | string | Enable anti-aliasing detection (true or false) | |
--manifest | string | Comma-separated snapshot names to include | |
--target-ref | string | Target ref for resolution (repeatable) | |
--output | string | "text" | text or json |
--api-key | string | API key | |
--api-url | string | API URL |
Exit codes:
0— No changes detected1— Changes detected (diff found)2— Error
# Auto-detect head capture from current git commitpxdiff diff --suite storybook
# Explicit capture-vs-capturepxdiff diff --head-capture cap_abc --base-capture cap_xyz
# Custom thresholdpxdiff diff --suite e2e --threshold 0.1pxdiff run
Section titled “pxdiff run”Wrap a command with a pxdiff session. Auto-detects whether to run in CI mode or local mode based on the CI environment variable.
pxdiff run [options] -- <command...>pxdiff [options] -- <command...> # shorthand (same behavior)pxdiff -- <cmd> is shorthand for pxdiff run -- <cmd>.
| Flag | Type | Default | Description |
|---|---|---|---|
--ci | boolean | Force CI mode (overrides auto-detection) | |
--local | boolean | Force local mode (overrides auto-detection) | |
--auto-approve | boolean | false | Auto-approve changed snapshots |
--ref | string | Baseline ref (sets PXDIFF_BASELINE_REF) | |
--docker | string/boolean | Run inside Docker for consistent rendering. Optionally specify a custom image. | |
--api-key | string | API key | |
--api-url | string | API URL |
Everything after -- is the command to run. pxdiff sets PXDIFF_SESSION_ID, PXDIFF_API_KEY, and PXDIFF_API_URL in the child process environment. Suite names come from your test plugins (Playwright, Vitest, Cypress) — not from the CLI.
Mode auto-detection: When the CI environment variable is set (true in GitHub Actions, GitLab CI, and most CI providers), pxdiff runs in CI mode — creating GitHub check runs and managing the session lifecycle. Otherwise, it runs in local mode — ephemeral baselines, no GitHub integration. Use --ci or --local to override.
# Run tests (auto-detects CI vs local)pxdiff -- npx playwright test
# Explicit subcommand form (equivalent)pxdiff run -- npx playwright test
# Run inside Docker for consistent cross-platform renderingpxdiff --docker -- npx playwright test
# Force local mode in CI (e.g., for personal testing on CI runners)pxdiff --local -- npm test
# Auto-approve against a specific baseline refpxdiff --auto-approve --ref main -- npm testWorkflow:
- Generates a session ID and spawns your command with pxdiff environment variables injected
- Plugins upload screenshots and create diffs per-suite using the shared session ID
- On exit, completes all diffs in the session and (in CI mode) posts GitHub check runs
pxdiff approve
Section titled “pxdiff approve”Approve changed snapshots in a diff to update baselines.
pxdiff approve <diffId> [options]| Argument | Description |
|---|---|
diffId | The diff ID to approve (required) |
| Flag | Type | Default | Description |
|---|---|---|---|
--snapshot | string | Snapshot name to approve (repeatable) | |
--all | boolean | false | Approve all changed snapshots |
--api-key | string | API key | |
--api-url | string | API URL |
You must specify either --snapshot (one or more) or --all.
# Approve specific snapshotspxdiff approve diff_abc --snapshot button-primary --snapshot header
# Approve everythingpxdiff approve diff_abc --allpxdiff revoke
Section titled “pxdiff revoke”Revoke approval for snapshots in a diff, reverting baseline updates.
pxdiff revoke <diffId> [options]| Argument | Description |
|---|---|
diffId | The diff ID to revoke (required) |
| Flag | Type | Default | Description |
|---|---|---|---|
--snapshot | string | Snapshot name to revoke (repeatable) | |
--all | boolean | false | Revoke all approved snapshots |
--api-key | string | API key | |
--api-url | string | API URL |
The following first-class commands are read-only inspection commands. They default to human-readable terminal output and support --output json for automation. JSON output is the stable CLI contract; human-readable output is intended for people.
pxdiff suites list
Section titled “pxdiff suites list”List suites in the current project.
pxdiff suites list [options]| Flag | Type | Default | Description |
|---|---|---|---|
--output | string | text | Output format: text or json |
--api-key | string | API key | |
--api-url | string | API URL | |
--project | string | Project context for session auth (org/project) |
pxdiff suites listpxdiff suites list --output jsonpxdiff diffs list
Section titled “pxdiff diffs list”List existing diff reports for a suite. This does not compare screenshots or create a new diff.
pxdiff diffs list --suite <suite> [options]| Flag | Type | Default | Description |
|---|---|---|---|
--suite | string | Suite name (required) | |
--branch | string | Filter by branch. When omitted, returns diffs for all branches. | |
--limit | string | Maximum number of diffs to return | |
--offset | string | Pagination offset | |
--output | string | text | Output format: text or json |
--api-key | string | API key | |
--api-url | string | API URL | |
--project | string | Project context for session auth (org/project) |
pxdiff diffs list --suite storybookpxdiff diffs list --suite storybook --branch mainpxdiff diffs list --suite storybook --output jsonpxdiff diffs get
Section titled “pxdiff diffs get”Inspect an existing diff report.
pxdiff diffs get <diffId> [options]| Argument | Description |
|---|---|
diffId | The diff ID to inspect (required) |
| Flag | Type | Default | Description |
|---|---|---|---|
--summary | boolean | false | Fetch lightweight snapshot summary instead of image details |
--output | string | text | Output format: text or json |
--api-key | string | API key | |
--api-url | string | API URL | |
--project | string | Project context for session auth (org/project) |
pxdiff diffs get diff_abcpxdiff diffs get diff_abc --summarypxdiff diffs get diff_abc --summary --output jsonpxdiff captures get
Section titled “pxdiff captures get”Inspect a capture and its snapshots.
pxdiff captures get <captureId> [options]| Argument | Description |
|---|---|
captureId | The capture ID to inspect (required) |
| Flag | Type | Default | Description |
|---|---|---|---|
--output | string | text | Output format: text or json |
--api-key | string | API key | |
--api-url | string | API URL | |
--project | string | Project context for session auth (org/project) |
pxdiff captures get cap_abcpxdiff captures get cap_abc --output jsonpxdiff baselines list
Section titled “pxdiff baselines list”List baseline refs for a suite.
pxdiff baselines list --suite <suite> [options]| Flag | Type | Default | Description |
|---|---|---|---|
--suite | string | Suite name (required) | |
--output | string | text | Output format: text or json |
--api-key | string | API key | |
--api-url | string | API URL | |
--project | string | Project context for session auth (org/project) |
pxdiff baselines list --suite storybookpxdiff baselines list --suite storybook --output jsonpxdiff baselines metadata
Section titled “pxdiff baselines metadata”Inspect baseline metadata for a suite ref. This does not change the baseline.
pxdiff baselines metadata --suite <suite> --ref <ref> [options]| Flag | Type | Default | Description |
|---|---|---|---|
--suite | string | Suite name (required) | |
--ref | string | Baseline ref, such as main (required) | |
--output | string | text | Output format: text or json |
--api-key | string | API key | |
--api-url | string | API URL | |
--project | string | Project context for session auth (org/project) |
pxdiff baselines metadata --suite storybook --ref mainpxdiff baselines metadata --suite storybook --ref main --output jsonpxdiff billing
Section titled “pxdiff billing”Show read-only billing balance, current period spend, and budget status for the authenticated project.
pxdiff billing [options]| Flag | Type | Default | Description |
|---|---|---|---|
--output | string | text | Output format: text or json |
--api-key | string | API key | |
--api-url | string | API URL | |
--project | string | Project context for session auth (org/project) |
pxdiff billingpxdiff billing --output jsonFor pricing, deposits, and budget behavior, see the billing guide.
pxdiff api get
Section titled “pxdiff api get”Fetch raw JSON from a read-only pxdiff API endpoint. This is a low-level inspection/debug interface for advanced users and coding agents who need endpoints not yet covered by first-class commands. Prefer the inspect commands above for common suites, diffs, captures, baselines, and billing reads.
Only GET requests are supported, and only for /api/v1/* JSON endpoints. This command reuses normal CLI authentication: project API keys work directly, and browser-login sessions work when the current directory is linked to a project or you pass --project. It returns raw API JSON rather than the stable JSON shape of the first-class inspect commands.
pxdiff api get <path> [options]| Argument | Description |
|---|---|
path | API path under /api/v1/* (required) |
| Flag | Type | Default | Description |
|---|---|---|---|
--api-key | string | API key | |
--api-url | string | https://pxdiff.com | API base URL |
--project | string | Project context for session auth (org/project) |
# Inspect a diff payloadpxdiff api get /api/v1/diffs/diff_abc
# Inspect snapshot summary with session auth outside a linked repopxdiff api get /api/v1/suites/storybook/diffs/diff_abc/snapshots/summary --project myorg/my-apppxdiff login
Section titled “pxdiff login”Authenticate the CLI via your browser using GitHub OAuth.
pxdiff login [options]| Flag | Type | Default | Description |
|---|---|---|---|
--api-url | string | https://pxdiff.com | API base URL |
# Login to productionpxdiff login
# Login to a custom instancepxdiff login --api-url http://localhost:3100pxdiff logout
Section titled “pxdiff logout”Clear stored credentials and invalidate the session.
pxdiff logout [options]| Flag | Type | Default | Description |
|---|---|---|---|
--api-url | string | https://pxdiff.com | API base URL |
pxdiff logoutpxdiff whoami
Section titled “pxdiff whoami”Show current authentication status and linked project.
pxdiff whoami [options]| Flag | Type | Default | Description |
|---|---|---|---|
--api-url | string | https://pxdiff.com | API base URL |
pxdiff whoamipxdiff project set
Section titled “pxdiff project set”Link the current git repository to a pxdiff project. Used with session-based auth (pxdiff login).
pxdiff project set <org/project> [options]| Argument | Description |
|---|---|
org/project | Organization and project slug (required) |
| Flag | Type | Default | Description |
|---|---|---|---|
--api-url | string | https://pxdiff.com | API base URL |
pxdiff project set myorg/my-appEnvironment Variables
Section titled “Environment Variables”| Variable | Description | Default |
|---|---|---|
PXDIFF_API_KEY | API authentication key (required for CI, optional when logged in) | |
PXDIFF_API_URL | API base URL | https://pxdiff.com |
PXDIFF_PROJECT | Override project context (org/project) | |
PXDIFF_LOCAL | Enable local mode when set to true | false |
PXDIFF_SESSION_ID | Session ID (set automatically by pxdiff) | |
PXDIFF_AUTO_APPROVE | Auto-approve (set automatically by --auto-approve) | |
PXDIFF_BASELINE_REF | Baseline ref (set automatically by --ref) | |
PXDIFF_BRANCH | Override git branch detection | |
PXDIFF_COMMIT | Override git commit detection |
Git Auto-Detection
Section titled “Git Auto-Detection”When --branch and --commit are not provided, the CLI auto-detects them:
- Branch:
GITHUB_HEAD_REF→GITHUB_REF(stripsrefs/heads/) →CI_COMMIT_REF_NAME→git rev-parse --abbrev-ref HEAD - Commit: GitHub PR event payload →
GITHUB_SHA→CI_COMMIT_SHA→git rev-parse HEAD - Target refs (for
pxdiff diff): IncludesGITHUB_BASE_REFandPXDIFF_BASELINE_REFif set, then queries the API for all refs with baselines and usesgit merge-baseto find which are ancestors of HEAD. See Baseline Resolution for details.
This works automatically in GitHub Actions, GitLab CI, and local development.