ScreenshotNeo

BlogHow-to

How to Save Website Screenshot History for Visual Change Audits

Build a repeatable screenshot audit workflow with Playwright baselines, CI artifacts, trace review, and a clear retention policy.

By the ScreenshotNeo team4 October 202610 min read

To save website screenshot history for visual change audits, keep reviewed baseline screenshots in version control, capture the same routes in a consistent browser environment, and retain each CI run’s screenshots and reports for a defined period. Use Playwright Test’s screenshot assertions for comparison, GitHub Actions artifacts for short-term run evidence, and traces to investigate differences. For history that must outlast artifact retention, preserve approved baselines or export run evidence to an archive governed by your own retention and access policy.

This workflow separates two useful records: the approved reference image for a given code revision, and the evidence produced by each audit run. A baseline answers “what should this page look like?” A CI artifact answers “what did this run capture, and what failed?”

1. Decide what screenshot history means for your team

Before writing tests, choose the history you need. A visual audit can mean a versioned set of approved reference images, temporary evidence for investigating a failed build, or a longer-lived record across releases. These have different retention needs.

Record Good fit Where it lives Retention consideration
Baseline snapshots Reviewing intended visual changes and detecting regressions Test repository, committed with code Version control preserves the baseline history as long as those commits are retained.
Per-run screenshots and reports Debugging a specific CI run or reviewing recent failures CI artifacts Artifacts expire according to repository, organization, or enterprise policy.
Long-horizon audit evidence Keeping selected evidence beyond normal CI artifact retention Approved baselines or a separately governed archive Set access, retention, and cleanup rules to match your team’s policy.

Do not treat every captured image as an approved baseline. A failed visual comparison may represent either a deliberate redesign or a regression. Review baseline changes with the same care as code changes.

2. Add Playwright screenshot assertions

Playwright Test’s toHaveScreenshot() creates reference screenshots on an initial run and compares later captures against them. Keep the generated snapshot directory under version control when practical. Name tests and projects so that snapshot names identify the route, state, viewport, and browser context.

Install Playwright Test

npm init -y
npm install --save-dev @playwright/test
npx playwright install

Configure a stable browser project

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  outputDir: 'test-results',
  reporter: [['list'], ['html', { outputFolder: 'playwright-report', open: 'never' }]],
  use: {
    baseURL: 'http://127.0.0.1:3000',
    ...devices['Desktop Chrome'],
    // Keep the viewport and browser context consistent across runs.
    viewport: { width: 1440, height: 900 },
    colorScheme: 'light',
    locale: 'en-US',
    timezoneId: 'UTC',
    // Record a trace on retry so a failed capture can be investigated.
    trace: 'on-first-retry',
  },
  projects: [
    { name: 'chromium-linux', use: { ...devices['Desktop Chrome'] } },
  ],
});

Choose a project name that describes your CI browser environment. Playwright’s snapshot naming incorporates the browser/platform or configured project name, which helps prevent captures from different projects being confused.

Write a visual audit test

// tests/visual-audit.spec.ts
import { test, expect } from '@playwright/test';

test('home page visual baseline', async ({ page }) => {
  await page.goto('/');
  await page.getByRole('heading', { name: 'Welcome' }).waitFor();

  // Hide only regions known to be volatile, such as a live clock.
  await expect(page).toHaveScreenshot('home-page.png', {
    fullPage: true,
    animations: 'disabled',
    caret: 'hide',
    style: `
      .live-clock, [data-visual-test="volatile"] {
        visibility: hidden !important;
      }
    `,
  });
});

Use a reliable readiness condition before capture, such as a heading or a page-specific selector. Waiting for a generic network-idle condition can be a poor fit for applications with polling, analytics, or persistent network requests. When a page has known dynamic content, use screenshot styling to suppress only those regions rather than masking broad parts of the page.

Create and review the baseline

  1. Run npx playwright test in the same browser environment you use for CI.
  2. Inspect the generated reference images in the Playwright snapshot directory, commonly named tests/visual-audit.spec.ts-snapshots/.
  3. Commit the snapshots after reviewing that they represent the intended page state.
  4. Run the test again. Playwright compares the capture against the committed reference and reports visual differences.

When an intentional design change updates a baseline, use Playwright’s snapshot update mode, then inspect every changed image before committing it:

npx playwright test --update-snapshots

Updating snapshots changes the references; it does not establish that the UI change is correct. Review the image diff and the related application change together.

3. Make captures reproducible

Visual comparisons only help when differences mostly reflect changes to the page rather than changes to the machine rendering it. Playwright documents that browser rendering can vary with host OS, browser version, settings, hardware, power source, headless mode, and other factors. Keep baseline generation and CI audits as similar as possible.

  • Use the same Playwright browser version and operating system for baseline generation and CI.
  • Pin the CI container image or otherwise control browser installation versions.
  • Keep viewport, device scale factor, color scheme, locale, timezone, and browser project stable.
  • Wait for the page state that matters to the audit; do not capture during loading or transitions.
  • Disable animations and hide only genuinely volatile areas, such as timestamps or rotating content.
  • Use stable test data and avoid depending on third-party content that can change independently.

Playwright’s screenshot comparison supports options such as fullPage, animations, caret, and style. Use the smallest set needed to make captures repeatable. Broadly hiding content can conceal real regressions.

4. Keep CI screenshots and reports as artifacts

Repository snapshots are the reviewable reference. Upload the test output and HTML report as run artifacts so a failed build remains inspectable after its job ends. GitHub Actions artifacts are retained for a configurable period; GitHub documents a 90-day default, with documented configurable ranges of 1–90 days for public repositories and 1–400 days for private repositories. Organization or enterprise policy can impose a lower maximum. Set a duration that fits the repository’s permitted retention.

# .github/workflows/visual-audit.yml
name: Visual audit

on:
  pull_request:
  push:
    branches: [main]

jobs:
  visual-audit:
    runs-on: ubuntu-latest
    container:
      image: mcr.microsoft.com/playwright:v1.XX.X-noble
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npx playwright test
      - name: Save screenshots, test results, and report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: visual-audit-${{ github.run_id }}
          path: |
            test-results/
            playwright-report/
          retention-days: 30

Replace the illustrative v1.XX.X container tag with the exact Playwright version used by the project, and keep it aligned with the installed package. The 30-day setting follows a value shown in Playwright’s CI documentation as an example; it is not a recommended universal period. GitHub defines an artifact as a file or collection of files produced during a workflow run. Artifacts are useful for run evidence, but they expire and should not be the only record if the audit horizon is longer.

Choose what to upload

  • test-results/ contains run output and, depending on test configuration, attachments useful for failures.
  • playwright-report/ contains the HTML report configured above.
  • Keep artifact names unique per run or commit so that evidence can be tied to the exact audit.
  • Use if: always() so the upload step runs after a test failure, too.

5. Inspect differences and diagnose failures

When a screenshot assertion fails, compare the expected image, the actual capture, and the diff. Then use the test report and trace to understand the page state and actions leading up to the screenshot. Playwright Trace Viewer provides a way to inspect expected, actual, and difference images alongside trace information.

  1. Open the CI artifact and inspect the Playwright HTML report.
  2. Review the expected, actual, and diff images for the failing assertion.
  3. Open the trace for the failed or retried test to inspect page actions and state around capture.
  4. Determine whether the difference is an intentional change, unstable content, an environment mismatch, or a real regression.
  5. Update the baseline only after confirming the intended page appearance.

Teams that want a hosted visual review workflow can evaluate Percy’s Playwright integration. Check the service’s current program terms and fit independently; this article does not establish pricing or affiliate availability.

6. Keep the audit trail for the required horizon

Pick a retention schedule based on what the record is for, then write it down. For example, a team may retain every CI report briefly for debugging, preserve approved baselines in source control across releases, and export selected release evidence to an independent archive. The right arrangement depends on the audit horizon, storage and access controls, and the team’s own policies.

  • Short-term diagnostics: CI artifacts can hold screenshots and reports after jobs complete, subject to expiry and organization limits.
  • Versioned visual references: committed baselines make changes reviewable alongside the code that changes the page.
  • Long-term evidence: preserve selected approved baselines or export artifacts to a separately governed archive with explicit retention and access rules.

Artifact documentation does not establish legal or compliance sufficiency. If a record must meet a formal requirement, confirm the applicable retention, integrity, and access expectations with the team responsible for that requirement.

7. Options when the review workflow grows

Approach Review model Strength Trade-off to plan for
Playwright snapshots in the repository Review image changes with code changes Versioned references and direct connection to source changes Requires disciplined baseline review, naming, and repository management.
CI artifacts Inspect output from an individual run Convenient failure evidence and reports Expires according to retention settings and policy.
Trace Viewer Inspect screenshot differences with test context Helps explain what happened around a capture Trace and artifact retention still need a policy.
Percy integration Hosted visual review flow An option when a team wants hosted review tooling Assess current service terms and operational fit separately.

Start with repository baselines and run artifacts if they meet the review and retention needs. Add hosted review or a separate archive when the team has a clear requirement the current workflow does not satisfy.

8. Troubleshooting common problems

Symptom Likely cause Fix
Snapshots differ on every run Dynamic content, animation, late loading, or unstable test data Wait for the relevant page state, disable animations, stabilize test data, and use screenshot styling for narrowly defined volatile regions.
Local baseline passes but CI fails Different OS, browser version, viewport, device scale factor, fonts, or headless environment Generate and compare baselines in the same pinned browser/container environment; align project and viewport settings.
Screenshot is blank or incomplete Capture happened before the page or target element rendered Wait for a meaningful page-specific selector or heading before calling the screenshot assertion.
Full-page image misses content loaded while scrolling Lazy-loaded content was not ready when the page was captured Make the page load the content needed by the test before capture, and verify the resulting full-page image. Avoid relying on timing alone.
Snapshot update creates many unexpected changes Environment drift or overly broad screenshot test coverage Check browser/container versions and project settings first; review each route and state before accepting any updated reference.
GitHub artifact upload says no files were found Output path differs from the workflow configuration, or tests did not create the report Check outputDir, reporter output folder, and artifact paths; inspect the job log and upload the directories that actually exist.
Artifact disappeared before the audit window ended Configured, repository, organization, or enterprise retention limit is shorter than expected Check effective retention policy. Preserve durable baselines or export needed evidence to an archive with the required horizon.
Visual diff includes a large text shift Font availability, browser differences, or layout timing changed Use the same environment, ensure fonts are available before capture, and wait for layout-relevant content to settle.

9. Performance, reliability, and cost

Each visual assertion adds browser work and produces image data. Keep the audit suite focused on high-value routes and states; split tests across CI workers if the suite becomes slow, while ensuring each worker uses the same pinned browser setup. Full-page captures and multiple viewport/browser projects create more output and storage than a small set of viewport captures, so include only the dimensions that serve a real audit need.

For reliability, treat baselines as reviewed source changes and CI artifacts as temporary evidence. Test the artifact workflow by inspecting a failed-run report, confirm its retention settings under repository policy, and make sure a run can be identified by commit and workflow run. For long-lived history, keep an independent preservation path rather than assuming CI artifacts remain indefinitely.

Playwright and GitHub Actions costs depend on the infrastructure and plan your team uses; the research sources here do not establish a price comparison. Consider browser execution time, CI storage, artifact volume, and any archive or hosted review service as separate budget items.

Or skip the browser setup

If you need repeatable captures without maintaining browser setup, ScreenshotNeo is a website screenshot API and MCP server. Its API takes a URL in one GET request, and its documentation covers the available options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie banners are accepted and removed before the shot; newsletter popups and chat widgets are removed, with each cleanup step configurable.
  • Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Responses indicate the page verdict and billing status in headers.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
  • The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan.

Sign up free for 1,000 screenshots a month, with no card required.

FAQ

Should screenshot baselines be committed to Git?

When practical, yes: committed snapshots are versioned and can be reviewed with the code or design change that updates them. Keep run-specific reports and screenshots as CI artifacts separately.

How long do GitHub Actions screenshots stay available?

They remain available according to the artifact retention setting and repository or organization policy. GitHub documents a 90-day default and configurable limits, but an organization can impose a lower ceiling.

Can I use screenshots alone as a compliance record?

The workflow described here does not establish compliance sufficiency. Confirm requirements for retention, integrity, and access with the team responsible for the applicable policy.

Do I need to save every screenshot from every run?

No. Preserve the references and run evidence needed for your audit purpose. Define which failures, releases, or approved changes require longer retention, then apply that policy consistently.