Skip to content

Troubleshooting

Your API key or session token was rejected.

  • In CI: Check that PXDIFF_API_KEY is set in your workflow’s environment. Keys start with pxd_ and are project-scoped — make sure the key belongs to the project you’re targeting.
  • Locally: Run pxdiff whoami to check your auth status. If it fails, run pxdiff login to re-authenticate.
  • Wrong project: If you’re authenticated but get 401, you may be hitting a project you don’t have access to. Check pxdiff project set or your PXDIFF_PROJECT environment variable.

Your organization’s balance has reached zero. New captures are blocked until you add funds. Diffs continue to work, since they’re free.

  • Your existing data (screenshots, baselines, diffs, approval history) is still accessible.
  • Service resumes instantly after adding funds — no waiting or support ticket needed.
  • To prevent this in CI, set a monthly budget alert in the billing settings.

See Billing & Pricing for pricing details.

You’ve hit a rate limit. The CLI will show which limit was reached and when it resets.

  • Most limits are per-minute. Wait and retry.
  • If you’re hitting limits consistently, check Rate Limits for the current thresholds.

If the CLI times out waiting for a capture or diff to complete:

  • Large suites: Captures with hundreds of screenshots take longer. The CLI polls for completion — if it times out, the capture is likely still running. Check the review UI for status.
  • Network issues: Ensure your CI runner or local machine can reach pxdiff.com.

If you need to inspect the exact JSON payload for a pxdiff resource before a first-class CLI command exists, use the low-level API passthrough:

Terminal window
pxdiff api get /api/v1/diffs/<diff-id>
  • This command is read-only: it only supports GET requests.
  • It only works for JSON endpoints under /api/v1/*.
  • It uses the same auth resolution as the rest of the CLI. With browser-login auth, make sure the current directory is linked with pxdiff project set, or pass --project org/project.

See the CLI reference for the full command contract.

Font rendering differs between operating systems. macOS uses Core Text, Linux uses FreeType — the same font renders differently at the subpixel level.

Fix: Use --docker to run captures inside a consistent Linux container:

Terminal window
pxdiff --docker -- npx playwright test
pxdiff --docker -- npx vitest run

See Docker for consistent rendering for details.

If your components have CSS transitions or animations, they can be in different states when the screenshot is taken.

Fix: Use the delay parameter to wait for animations to settle:

// Playwright plugin
await expect(page).toMatchPxdiff({ delay: 500 });
// Ladle story meta
MyStory.meta = { pxdiff: { delay: 500 } };

Or disable animations globally in your test setup:

*, *::before, *::after {
animation-duration: 0s !important;
transition-duration: 0s !important;
}

Overlay scrollbar styles vary by OS and can appear inconsistently in captures.

Fix: Hide scrollbars with CSS in your test environment:

*::-webkit-scrollbar { display: none; }
* { scrollbar-width: none; }

Dynamic content (timestamps, avatars, random data)

Section titled “Dynamic content (timestamps, avatars, random data)”

Screenshots that include live timestamps, randomly generated content, or third-party avatars will differ on every run.

Fix: Mock dynamic data in your test environment, or use ignoreSelectors to mask specific elements:

// Ladle
MyStory.meta = { pxdiff: { ignoreSelectors: [".timestamp", ".avatar"] } };

If every diff shows changes even when you haven’t modified the component:

  1. Cross-platform rendering: The most common cause. If your baseline was captured on a different OS or architecture than your current run, subpixel differences will produce diffs. Use --docker and match architectures between local and CI. See Architecture considerations.

  2. Non-deterministic content: Timestamps, random data, or third-party resources that change between runs. See Dynamic content above.

  3. Font loading: pxdiff waits for network inactivity and document.fonts.ready automatically, but if you see fallback fonts in screenshots, check that your font URLs are accessible from the capture environment.

pxdiff uses pixelmatch at threshold 0.063 — the same algorithm and threshold as Chromatic. This correctly handles anti-aliasing without flagging subpixel rendering differences as changes.

You can override the threshold per-diff:

Terminal window
pxdiff diff --threshold 0.1 # More lenient
pxdiff diff --threshold 0.01 # More strict

A higher threshold ignores more subtle differences. A lower threshold catches finer changes but may produce more false positives.

If pxdiff completes but no GitHub check appears on your pull request:

  1. GitHub App not installed: Install the pxdiff GitHub App on your repository. Go to your organization settings in the pxdiff review UI and follow the GitHub installation link.

  2. Permissions: The GitHub App needs checks: write and pull_requests: read permissions on the repository. If you restricted repository access during installation, make sure the target repo is included.

  3. Branch/commit mismatch: The CLI auto-detects branch and commit from the CI environment. If detection fails (e.g., in a custom CI provider), the check run can’t be linked to your PR. Set PXDIFF_BRANCH and PXDIFF_COMMIT explicitly:

    env:
    PXDIFF_BRANCH: ${{ github.head_ref }}
    PXDIFF_COMMIT: ${{ github.event.pull_request.head.sha }}
  4. No diffs in session: Check runs are only created when at least one diff completes in the session. If captures failed or no snapshots changed, no check is posted.

The session may not have been completed. This happens if:

  • The CI job was cancelled or timed out before pxdiff could finish.
  • The child command crashed and the session completion step was skipped.

Subsequent runs on the same PR will create new check runs. Pending checks from abandoned sessions will not resolve automatically — they’re harmless but can be confusing. Re-push to trigger a new run.

A snapshot completed but showed a warning that the story’s play function or stabilization step did not finish within the allotted time.

  • pxdiff automatically retries the capture on a larger (2 GB) Lambda worker called the heavy tier. No action is required — the second attempt usually succeeds and the snapshot is committed.
  • Subsequent captures of the same story route directly to the heavy tier until its play function becomes consistently faster again.
  • If the warning persists even on heavy, shorten the story’s play function or set an explicit delay on the target to give it more time before pxdiff starts stabilizing.

Heavy-tier captures cost roughly 2× what the standard tier costs (1 GB vs 2 GB × duration). See Billing & Pricing.

See the Docker guide troubleshooting section for Docker-specific issues including memory limits, architecture mismatches, and volume problems.

StatusMeaning
400Bad request — invalid parameters or malformed input
401Unauthorized — invalid or missing API key / session token
402Payment required — insufficient credits
403Forbidden — valid auth but no access to the requested resource
404Not found — resource doesn’t exist or belongs to another project
409Conflict — resource already exists (e.g., duplicate snapshot name in a capture)
429Rate limited — too many requests, check Retry-After header
500Server error — unexpected failure, retry once before reporting