Skip to main content

Visual regression checking with figma-first baselines, pixel+SSIM diffing, ignore regions, and HTML reports.

Project description

visualcheck

Visual regression checking with:

  • Figma-first baselines (optionally synced via Figma API)
  • Runtime baselines (auto-create when missing; never overwrite by default)
  • Pixel diff % + SSIM (with optional resize-on-mismatch + WARN)
  • Ignore regions (mask dynamic areas via selectors + explicit rects)
  • Self-contained HTML report + report.json

Install

pip install visualcheck
playwright install chromium

Config (visualcheck.yaml)

project: consumer_website
suite: daily_sanity

envs:
  prod: "https://example.com"

views:
  desktop_profiles: ["desktop_1440x900", "macbook_1440x900"]
  mobile_devices: ["iPhone 15 Pro Max", "iPhone 13 mini", "Pixel 7"]

pages:
  - id: home
    url: "/"
    wait_for: "body"
    full_page: true

# Optional flows (multi-step user journeys)
flows:
  - id: search_flow
    start_url: "/"
    steps:
      - action: click
        selector: "text=Search"
      - action: wait
        ms: 500
    snapshots:
      - id: after_search
        wait_for: "body"
        full_page: true

baseline:
  # Locked resolution order:
  # figma -> runtime -> create runtime baseline (if enabled)
  priority: ["figma", "runtime"]
  create_if_missing: true
  never_overwrite: true
  on_created: "INFO"  # INFO|WARN|FAIL

compare:
  resize_on_mismatch: true
  mismatch_level: "WARN"  # WARN|FAIL
  thresholds:
    max_pixel_diff_pct: 0.10
    min_ssim: 0.995

ignore_regions:
  global:
    selectors: ["#cookie-banner", ".chat-widget"]
  by_snapshot:
    home:
      rects:
        - {x: 0, y: 0, width: 300, height: 120}

# Optional Figma sync (writes into visual_baseline/<project>/<suite>/figma/...)
# figma:
#   token_env: FIGMA_TOKEN
#   file_key: "<FIGMA_FILE_KEY>"
#   frames:
#     - id: home
#       node_id: "123:456"
#       view_id: "desktop_1440x900"   # optional

Commands

Run full check

visualcheck run --env prod

Outputs:

  • Baselines:
    • visual_baseline/<project>/<suite>/figma/<view>/<snapshot>.png
    • visual_baseline/<project>/<suite>/runtime/<view>/<snapshot>.png
  • Run artifacts:
    • test_report/<project>/visual_runs/<run_id>/current/...
    • test_report/<project>/visual_runs/<run_id>/diff/...
    • test_report/<project>/visual_runs/<run_id>/report/report.html
    • test_report/<project>/visual_runs/<run_id>/report/report.json

Capture only

visualcheck capture --env prod --out current

Diff only

visualcheck diff --baseline visual_baseline/myproj/mysuite/runtime --current current --out report

Sync Figma baselines

export FIGMA_TOKEN="..."
visualcheck figma-sync

Approve current run as runtime baseline (explicit)

visualcheck approve --env prod --run-id 20260207_235500
# Overwrite existing runtime baselines only with:
visualcheck approve --env prod --run-id 20260207_235500 --force

Baseline rules (locked)

For each snapshot + view:

  1. If a Figma baseline exists → use it
    • visualcheck will attempt a best-effort figma-sync when figma is listed in baseline.priority so remote Figma baselines are consulted before falling back.
  2. Else if a runtime baseline exists → use it
  3. Else → capture and create runtime baseline (controlled by baseline.create_if_missing)

Notes on configuration and behavior

  • baseline.priority controls the preference order. Example: priority: ["figma","runtime"] (default in examples) — visualcheck will try Figma first.
  • By default a Figma baseline is used directly for comparison (reported baseline path will point at .../figma/...).
  • If you want Figma to become the authoritative runtime baseline (copied into the runtime/ folder and then used), set:
baseline:
  figma_authoritative: true
  • This avoids accidental comparisons against an old runtime image when Figma is the source of truth.
  • If a figma baseline is missing locally and figma appears in priority, visualcheck will attempt to fetch it via the Figma API (best-effort). If the fetch fails (token/permission), it falls back to runtime per priority.

Use from code (framework integration)

If you already navigate with Playwright/Selenium in your own framework and just want visualcheck to capture + baseline + diff + report, use the code API.

Baselines still go to visual_baseline/<project>/<suite>/... and the HTML report goes to test_report/<project>/visual_runs/<run_id>/report/report.html.

Playwright (sync) example

from playwright.sync_api import sync_playwright

# NOTE: API object names may evolve; refer to the package docs in case of changes.
from visualcheck.api import VisualCheck

vc = VisualCheck(
    project="my_project",
    suite="daily_sanity",
    env="prod",
    base_url="https://example.com",
    view_id="desktop_1440x900",
    baseline_priority=["figma", "runtime"],
    create_if_missing=True,
    ignore_selectors=["#cookie-banner", ".chat-widget"],
)

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page(viewport={"width": 1440, "height": 900})

    page.goto("https://example.com/", wait_until="domcontentloaded")
    vc.check(snapshot_id="home", page=page)

    page.goto("https://example.com/pricing", wait_until="domcontentloaded")
    vc.check(snapshot_id="pricing", page=page)

    vc.finalize()
    print("Report:", vc.report_html)

    browser.close()

Selenium example

from selenium import webdriver
from visualcheck.api import VisualCheck

vc = VisualCheck(
    project="my_project",
    suite="daily_sanity",
    env="prod",
    base_url="https://example.com",
    view_id="desktop_1440x900",
)

driver = webdriver.Chrome()
driver.set_window_size(1440, 900)

driver.get("https://example.com/")
vc.check(snapshot_id="home", selenium_driver=driver)

driver.get("https://example.com/pricing")
vc.check(snapshot_id="pricing", selenium_driver=driver)

vc.finalize()
print("Report:", vc.report_html)

driver.quit()

Notes

  • Ignore regions are masked with a solid color before diffing.
  • If screenshot sizes differ and compare.resize_on_mismatch=true, current is resized to baseline size and a warning is recorded.

License

MIT

Library & CLI usage (examples)

Programmatic API (Python)

The package exposes a simple programmatic API to integrate with Playwright or Selenium.

Example (Playwright):

from visualcheck.runner import run_visualcheck
from visualcheck.config import load_config

cfg = load_config(Path('examples/wakefit.yaml'))
result = run_visualcheck(cfg, env='prod', headed=False)
print('Report saved at', result.get('report_html'))

CLI usage

  • Sync Figma baselines:
export FIGMA_TOKEN="<your_token>"
visualcheck figma-sync --config examples/wakefit.yaml
  • Run full check:
visualcheck run --env prod --config examples/wakefit.yaml

Notes on FIGMA token & env handling

  • The library reads Figma token from the environment variable name specified in config (defaults to FIGMA_TOKEN).
  • Keep secrets out of git; use host-level secrets (e.g. ~/.openclaw/secrets.env) or a CI secret store.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

visualcheck-0.2.8.tar.gz (20.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

visualcheck-0.2.8-py3-none-any.whl (21.0 kB view details)

Uploaded Python 3

File details

Details for the file visualcheck-0.2.8.tar.gz.

File metadata

  • Download URL: visualcheck-0.2.8.tar.gz
  • Upload date:
  • Size: 20.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for visualcheck-0.2.8.tar.gz
Algorithm Hash digest
SHA256 925ab06e96e7192abeae53b0dbc1b77a0c103411c31b8b9014124d72d2421514
MD5 405ac41f59cc686e3bbdaddf5a9c669a
BLAKE2b-256 f474546af0e1f60b1d47ba50c86ba077cb4e7b83f4b583244cc03e6b7b90c2e6

See more details on using hashes here.

File details

Details for the file visualcheck-0.2.8-py3-none-any.whl.

File metadata

  • Download URL: visualcheck-0.2.8-py3-none-any.whl
  • Upload date:
  • Size: 21.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for visualcheck-0.2.8-py3-none-any.whl
Algorithm Hash digest
SHA256 679f6fd965c5d65e7a97f2f6f5d3205ec7c7e7d9be47da8bfcc04368fd528e69
MD5 b6ba3593b6c8f0f8d1606322b34b1393
BLAKE2b-256 fcd21ed39ced5d7e5a9d43d92ae6acb12c28143edc94451e6c574ed95bea5331

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page