Back to Blog

Migrating from Percy to Lastest: A Step-by-Step Guide

Most teams do not leave Percy because it does not work. They leave because the bill grows faster than the test suite, and per-screenshot pricing creates a quiet disincentive to test thoroughly. The migration is mechanical - most of the concepts map one-to-one - but a sloppy cutover can leave you running both tools in parallel for weeks. This guide is the version that keeps both pipelines green until the day you flip the switch.

Migration flow Percy project snapshot · home · 1280 snapshot · home · 375 snapshot · pricing · 1280 +12 more percy export --all lastest import-percy map widths → viewports map snapshots → tests hash + sign baselines preserve approvals Lastest project test · home · 1280 test · home · 375 test · pricing · 1280 +12 baselines locked
Percy export → import bridge → Lastest project. Baselines, viewports, and approvals carry over.

Why teams migrate

  • Per-snapshot pricing. Percy meters every screenshot. Adding a viewport doubles your bill. Adding dark mode doubles it again.
  • Browser limits on lower tiers. Cross-browser coverage is gated behind higher plans.
  • Cloud-only. Compliance teams that prohibit screenshots leaving the network cannot use Percy.
  • One diff engine. Pixel-only diffing produces avoidable false positives on font rendering and antialiasing.
  • Two-column comparison: Percy (red) charges from $199/mo plus per-snapshot overage, meters every screenshot, ships one pixel diff engine, and is cloud-only; Lastest (teal) is $0 self-hosted or $299/mo Cloud, unlimited screenshots, three diff engines (pixel/SSIM/Butteraugli), and never leaves your network
    Line by line, Lastest removes the four reasons teams outgrow Percy: metering, price, one engine, and cloud-only.

Step 1: Map the concepts

The mental model is almost identical, but the names differ.

  • Percy "snapshot" → Lastest "test". Same idea: a named capture of a URL or DOM state.
  • Percy "build" → Lastest "run". A CI invocation that produces a set of screenshots.
  • Percy "approved baseline" → Lastest "locked baseline". The reference image future runs are diffed against. Lastest hashes baselines (SHA256) so you can prove they have not been altered post-approval.
  • Percy "widths" → Lastest "viewports". Same mechanism, configured per-test or per-suite.
  • Percy "responsive scrolling" → handled automatically by Lastest's stabilization layer.

Step 2: Export and import baselines

Run Percy's export against your project to pull every approved baseline as a tarball. Then point Lastest's importer at it.

# Export from Percy
percy export --project my-org/web --output percy-baselines.tar.gz

# Import into Lastest
lastest import-percy \
  --archive percy-baselines.tar.gz \
  --project web \
  --map-widths 375=mobile,768=tablet,1280=desktop

The importer creates one Lastest test per Percy snapshot, preserves approval history as comments, and signs each baseline. After this step you have a frozen reference set; a Lastest run against the same git SHA should produce zero diffs.

Five-step migration flow: map concepts, import baselines, update CI, then a cautioned dual-mode sprint where both tools run, then cut over to Lastest as the required check, with a note that both pipelines stay green until the final step so you can roll back
The cutover is sequential and safe: both pipelines stay green until step 5, so you can roll back at any point.

Step 3: Update CI

Replace the Percy step with the Lastest action. Keep the Percy step for one or two weeks so you can compare diffs side by side.

CI · before vs. after .github/workflows/ci.yml - before - run: pnpm build - run: pnpm test:unit - run: percy exec -- pnpm test:visual # meter: 14k snaps / month # cost: $199 + overage PERCY_TOKEN: required .github/workflows/ci.yml - after - run: pnpm build - run: pnpm test:unit - uses: las-team/lastest/ action@main # meter: unlimited # cost: $0 LASTEST_RUNNER_TOKEN ✓
Drop the Percy exec wrapper, add the Lastest action. Same job slot, no metering.

Step 4: Run dual mode for one sprint

Both Percy and Lastest run on every PR. Lastest is informational; Percy is still required to merge. After a week you will see exactly which engine produces fewer false positives, and whether any baselines disagree.

Common findings during dual-mode:

  • Lastest's structural and perceptual engines suppress font-antialiasing diffs that Percy flags. That is expected and desired.
  • A handful of dynamic regions show up as diffs in Lastest because masks were defined Percy-side. Port the masks; the runs converge.

Step 5: Cut over

Make Lastest the required check, mark the Percy check as informational, then remove it the following sprint. Cancel the Percy plan after the next billing cycle so the baselines remain accessible if you need to roll back.

What you keep, what you gain

  • Keep: approved baselines, viewport config, snapshot names, mental model, CI structure.
  • Gain: three diff engines, AI test generation for stories you never bothered to add, on-prem deployment option, no per-snapshot fee, signed baselines, branch-aware approval flow.

Most teams complete the migration over a single sprint. The big win is not day-one parity - it is that the next time you add dark mode, a new viewport, or a new product line, the cost of the additional coverage is zero.