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”Upload a Storybook build, discover stories, and capture screenshots in one step.
pxdiff storybook <dir> [options]| Argument | Description |
|---|---|
dir | Path to the static Storybook build directory (required) |
| Flag | Type | Default | Description |
|---|---|---|---|
--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) |
--ephemeral | boolean | false | No branch/commit tracking |
--local | boolean | false | Run in local mode (also set via PXDIFF_LOCAL=true) |
--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) |
--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) |
Workflow:
- 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
# Basic usagepxdiff storybook ./storybook-static
# 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”Upload a Ladle build, discover stories, and capture screenshots in one step.
pxdiff ladle <dir> [options]| Argument | Description |
|---|---|
dir | Path to the static Ladle build directory (required) |
| Flag | Type | Default | Description |
|---|---|---|---|
--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) |
--ephemeral | boolean | false | No branch/commit tracking |
--local | boolean | false | Run in local mode (also set via PXDIFF_LOCAL=true) |
--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) |
Workflow:
- 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
# Basic usagepxdiff ladle ./build
# 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 CI session. Creates a GitHub check run and manages the session lifecycle.
pxdiff run [options] -- <command...>| Flag | Type | Default | Description |
|---|---|---|---|
--auto-approve | boolean | false | Auto-approve changed snapshots |
--api-key | string | API key | |
--api-url | string | API URL | |
--docker | string/boolean | Run inside Docker for consistent rendering. Optionally specify a custom image. |
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.
# Wrap a Playwright test runpxdiff run -- npx playwright test
# Wrap all tests (multi-suite — each plugin declares its own suite)pxdiff run -- npm test
# Run inside Docker for consistent cross-platform renderingpxdiff run --docker -- npx playwright 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 posts GitHub check runs
pxdiff local
Section titled “pxdiff local”Run a command in local development mode with pxdiff environment configured.
pxdiff local [options] -- <command...>| Flag | Type | Default | Description |
|---|---|---|---|
--auto-approve | boolean | false | Set PXDIFF_AUTO_APPROVE=true |
--ref | string | Baseline ref (sets PXDIFF_BASELINE_REF) | |
--docker | string/boolean | Run inside Docker for consistent rendering. Optionally specify a custom image. |
# Run Playwright tests locally with pxdiffpxdiff local -- npx playwright test
# Auto-approve against mainpxdiff local --auto-approve --ref main -- npm test
# Run inside Docker for consistent cross-platform renderingpxdiff local --docker -- npx vitest runpxdiff 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 |
pxdiff 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 run and local commands) | |
PXDIFF_AUTO_APPROVE | Auto-approve (set automatically by run --auto-approve and local --auto-approve) | |
PXDIFF_BASELINE_REF | Baseline ref (set automatically by local --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 - Baseline ref:
GITHUB_BASE_REF→PXDIFF_BASELINE_REF
This works automatically in GitHub Actions, GitLab CI, and local development.