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 credit balance has reached zero. New captures and diffs are blocked until you deposit more credits.

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

See Billing & Credits 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.

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 run --docker -- npx playwright test
pxdiff local --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 run 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 run 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.

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