Visual regression in Playwright comes from snapshot tests: expect(page).toHaveScreenshot('home.png') captures the page and compares it to a stored baseline, while expect(locator).toHaveScreenshot('card.png') limits the diff to a single component. These are powerful but unforgiving, so the strategy is to pick a small set of high-value pages or components, fix their viewport, theme, and color scheme in the config, disable animations via CSS injection or prefers-reduced-motion, and snapshot them regularly. The smaller and more focused the snapshot, the easier it is to interpret a diff.
Dynamic regions break baseline comparisons, so Playwright supports a mask option that ignores volatile elements when computing the diff: expect(page).toHaveScreenshot({ mask: [page.getByTestId('clock')] }). Other volatile areas worth masking include timestamps, user avatars, ad slots, and charts that re-render with live data. For data regressions instead of visual ones, fetch JSON via the request fixture or page.request and use toMatchSnapshot() on the parsed object so the diff highlights exact field changes rather than pixel noise.
Baselines are updated with npx playwright test --update-snapshots, which is a sensitive operation. Agents should never update snapshots unless explicitly asked; instead they should attach the diff (or the failing screenshot) and propose the change with rationale, citing the ticket or PR that explains the intentional UI change. A safe workflow for intentional UI changes is to update assertions and test IDs first, refresh the snapshot second, and record the reason in the commit message so future diffs are explainable. For comparing across versions, you can check out an older commit in a git worktree, run the same suite, and diff the HTML reports and screenshot artifacts between runs.