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>.pngvisual_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.htmltest_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:
- If a Figma baseline exists → use it
- Else if a runtime baseline exists → use it
- Else → capture and create runtime baseline (controlled by
baseline.create_if_missing)
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 totest_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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file visualcheck-0.2.1.tar.gz.
File metadata
- Download URL: visualcheck-0.2.1.tar.gz
- Upload date:
- Size: 17.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2fbc821ac53d3c05254182e97875befb4512ebc3b198e3f63e9127f7090f3c3
|
|
| MD5 |
a0521fc902e05645527b426ab4cdbe77
|
|
| BLAKE2b-256 |
4af3cd2b517d41471def4d4bec8aafe894a059fa03492500a17b0e8af4048848
|
File details
Details for the file visualcheck-0.2.1-py3-none-any.whl.
File metadata
- Download URL: visualcheck-0.2.1-py3-none-any.whl
- Upload date:
- Size: 18.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
849886fafd6b34db72ae85330ade482b99c0be3724159d648fcdb18b24be3dd2
|
|
| MD5 |
a95cac3298a392ccc8686a1495795d9a
|
|
| BLAKE2b-256 |
157a0818fdfbbaea4f5d46c41c60ac435d9437df5d6b3f738de1ebb95b73de61
|