Local visual regression testing with reviewed git baselines, inspectable reports, and optional model-assisted analysis. On the default compare path, pixel comparison is the pass/fail signal. Model classification is advisory and unmeasured. Experimental frontguard run --mode judge --experimental is a separate opt-in and is not that path.
Frontguard gives frontend teams a local, inspectable screenshot comparison loop without requiring a hosted account.
multi-browser · optional AI vision analysis · local-first · MIT
Current test, source, version, and bundle metrics are derived by
scripts/stats.ts. Seescripts/stats.jsonfor the canonical snapshot.

📽️ Demo: frontguard init → doctor → run → AI classification.
Published packages are listed in CHANGELOG.md. The first validation run is documented in
validation/results-v0.2.md: 39 of 43 route rechecks completed across 2 of 5 fixture repositories on one macOS host, with AI disabled. It is not an AI-accuracy or cross-OS benchmark.
The MIT-licensed repository contains the CLI, optional AI pipeline, cloud API source, integrations, MCP server, and Docker renderer source. The local CLI is the supported product path. Hosted, MCP, GitHub App, and Docker Compose onboarding remain pre-release; see the launch audit for the unresolved acceptance work.
AI is optional; without it, the CLI performs local pixel comparison and writes local reports. Cloud source and the self-host guide are available for evaluation, not as a verified production quick start.
- 🧠 Optional model-assisted analysis — When configured, sends screenshot evidence to your selected OpenAI or Anthropic account and returns a classification, confidence, and explanation for review.
- 🎯 Configurable consensus — Opt into multiple renders per route when a project needs protection from transient screenshot variation.
- 🤖 Pre-release MCP interface —
@frontguard/mcpcan query a verified API deployment; there is no live hosted default, and cloud approval does not yet promote screenshots. - 🐳 Pinned renderer source — The renderer is currently repository-source-only and must be built with the documented npm tarball preparation. Cross-host byte equivalence has not yet been validated and no registry image is published.
- 🔓 Open-source CLI — CLI-first, free forever. No per-screenshot pricing cliff, no dashboard lock-in, BYO AI key. Cloud components are available in the repository but their hosted and Docker quick starts are still pre-release.
Developer runs Frontguard → Pages render → Pixels compare to reviewed baselines →
Console, JSON, and HTML evidence are written → Optional AI assists with changed screenshots
- Detect — Pixel comparison finds changes above the configured threshold
- Understand — Optional AI returns a confidence-scored explanation for human review
- Fix — Experimental CSS suggestions and sandbox verification are separate opt-ins
Prerequisites: Node.js 22+, a git repository, and an origin remote if CI should compare against published baselines. Frontguard stores screenshots on the frontguard-baselines orphan branch.
# One-time per machine: install the Chromium browser Frontguard uses to render pages
npx -p @frontguard/cli playwright install --with-deps chromium
# Generate frontguard.config.ts (--yes skips prompts).
# Add --ci only if this repo already has package.json, a start script,
# and a supported lockfile (set package.json "packageManager" if more than
# one lockfile exists) — otherwise `init --ci` writes nothing.
npx -p @frontguard/cli frontguard init --yes
npx -p @frontguard/cli frontguard doctor
# Commit only the files init wrote. The published CLI needs a clean tree
# to create the baseline branch.
git add frontguard.config.ts .gitignore && git commit -m "Add Frontguard"App terminal (leave this running): start your app and wait until the baseUrl in frontguard.config.ts responds. Example:
npm run devFrontguard terminal: review the running app, accept baselines, publish the orphan branch, then compare.
npx -p @frontguard/cli frontguard update-baselines
npx -p @frontguard/cli frontguard runLocal run does not need origin. For CI comparisons, publish the orphan branch:
git push origin frontguard-baselinesrun exits 0 when pages match, 1 on a regression or unaccepted new page, and 2 on a tool error.
Full documentation: frontguard.dev/docs · internal notes in
docs/
- Zero-config route discovery — Auto-crawls your app to find all pages
- Multi-browser — Chromium, Firefox, WebKit via Playwright
- Optional AI analysis — BYOK (OpenAI/Anthropic) can classify a pixel change; it does not change pass/fail and has no published accuracy benchmark
- Smart rendering — Dependency graph renders only pages affected by your changes
- Preview deployments — Auto-detects Vercel/Netlify preview URLs
- Git-native baselines — Stored in orphan branch, zero main branch bloat
- Framework detection — Next.js, Remix, SvelteKit, Nuxt, Astro out of the box
- Security hardened — Shell injection prevention, path traversal guards, API key redaction
- Memory managed — Streaming buffers, temp file cleanup, bounded concurrency
- Visual evidence — Baseline/current/diff images are retained in the HTML report; remote thumbnails require an explicit image-upload backend
- Per-route thresholds — Strict on
/checkout, relaxed on/blog— all in one config
| Frontguard | Percy | Chromatic | BackstopJS | Lost Pixel | Argos | |
|---|---|---|---|---|---|---|
| Open source | ✅ MIT | ❌ | ◐ | ✅ | ◐ (read-only) | ✅ MIT |
| CLI-first | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ |
| AI change classification | ✅ optional | ◐ | ❌ | ❌ | ❌ | ❌ |
| AI fix verification | ◐ experimental | ❌ | ❌ | ❌ | ❌ | ❌ |
| Multi-render consensus | ◐ configurable | ◐ | ◐ | ❌ | ❌ | ◐ |
| Runs without a hosted service | ✅ | ❌ | ❌ | ✅ | ◐ | ◐ |
| Free tier | Forever (CLI) | 5k screenshots/mo | 5k snapshots/mo | Free | Sunset | 5k screenshots/mo |
| Hosted entry | Waitlist | $199/mo | $179/mo | n/a | n/a | $100/mo |
| Project status | Active | Active | Active | Low activity observed | Sunset; team joined Figma | Active |
Migrating? See the BackstopJS, Lost Pixel, and Argos guides. Comparisons: Percy · Chromatic · Argos.
Illustrative output only; the published validation run did not measure model accuracy.
✘ /dashboard @ 375px — 2.34% changed
🔴 AI Analysis — Regression (94% confidence)
"The sidebar overlaps the main content on mobile. Review the responsive
layout rules affecting the sidebar and content container."
Suggested fix (unverified): restore column stacking at the mobile breakpoint.
✓ /pricing @ 1440px — 0.8% changed
🟢 AI Analysis — Intentional (91% confidence)
"New 'Enterprise' pricing tier added. Layout intact, content expanded."
// frontguard.config.ts
export default {
version: 1,
baseUrl: 'http://localhost:3000',
// Auto-discover routes (zero config)
discover: {
startUrl: '/',
maxDepth: 3,
exclude: ['/admin/*', '/api/*'],
},
// Or explicit routes
// routes: ['/', '/pricing', '/checkout'],
viewports: [375, 768, 1440],
browsers: ['chromium'],
threshold: 0.1, // changed-pixel ratio: 0.1 = 10%
// AI analysis (optional, BYOK)
ai: {
provider: 'openai',
model: 'gpt-4o',
},
// Ignore dynamic content
ignore: [
{ selector: '.dynamic-timestamp' },
],
};ROUTE DISCOVERY → PLAYWRIGHT RENDER → PIXEL COMPARISON → CONSOLE / JSON / HTML
└──────→ OPTIONAL BYOK AI ANALYSIS
frontguard
🔍 Discovering routes... found 47 routes
📊 12/47 routes affected by changed files
🖥 Rendering 12 routes × 3 viewports
───────────────────────────────────────────
RESULTS 12 routes
───────────────────────────────────────────
✓ / 375 768 1440 PASS
✓ /pricing 375 768 1440 PASS
⚠ /checkout 375 768 1440 WARNING
✘ /dashboard 375 768 1440 REGRESSION
★ /settings 375 768 1440 NEW
───────────────────────────────────────────
✘ /dashboard @ 375px
AI: "At 375px, the current screenshot shows the sidebar overlapping
the main content; the baseline keeps both regions separate."
Guidance: Review responsive stacking for this viewport.
Severity: 🔴 Critical (confidence: 94%)
1 regression · 1 warning · 9 passed · 1 new
Frontguard ships with a plugin architecture (9 lifecycle hooks) and 5 built-in plugins:
| Plugin | Description | Key Features |
|---|---|---|
Figma (packages/cli/src/plugins/figma.ts) |
Design-to-code comparison | Figma API integration, design token extraction, component mapping |
Performance Budgets (packages/cli/src/plugins/perf-budgets.ts) |
Web Vitals & budgets | LCP/CLS/TTFB thresholds, violations correlated with the visual diff |
Accessibility (packages/cli/src/plugins/accessibility.ts) |
axe-core audits | WCAG checks (contrast, alt text, target size, focus, headings) in the same render pass |
Third-Party Scripts (packages/cli/src/plugins/third-party-scripts.ts) |
Script drift detection | Flags ad/analytics/widget origins that appear or disappear between runs |
Monitor (packages/cli/src/plugins/monitor.ts) |
Production visual monitoring (CLI + optional cloud scheduler) | Live-URL checks, threshold alerting, history tracking |
Plugin lifecycle hooks: setup, beforeDiscover, afterDiscover, beforeRender, afterRender, afterCompare, afterRun, onError, teardown
// frontguard.config.ts
import { createFigmaPlugin } from '@frontguard/cli/plugins';
export default {
// ...base config
plugins: [
createFigmaPlugin({ fileKey: 'your-figma-file-key' }),
],
};packages/
├── cli/src/ # @frontguard/cli — discover → render → diff → report
│ ├── cli/ # Commander entry
│ ├── core/ # Pipeline orchestrator, types, config, plugin system
│ ├── discovery/ # Route discovery (crawler + filesystem)
│ ├── render/ # Playwright rendering engine
│ ├── diff/ # Pixel diff + AI vision analysis
│ ├── storage/ # Git orphan branch baselines
│ ├── report/ # Console, JSON, HTML, GitHub PR reporters
│ ├── plugins/ # Figma, perf budgets, a11y, third-party, monitor
│ └── utils/ # Redaction, logging, retry
├── playwright/ # @frontguard/playwright
├── mcp/ # @frontguard/mcp
├── cloud-api/ # Cloudflare Workers + D1 + R2
└── create-frontguard-plugin/
apps/
├── web/ # docs site
└── demo/
integrations/
├── github-app/
├── vercel/
├── netlify/
└── slack-app/
Pipeline: discover → filter → render → diff → analyze → report
Each stage is independent with error boundaries — one page failing doesn't kill the run.
See docs/ for:
- Product deep-dive — Architecture decisions and design rationale
- Launch readiness (v0.2.0) — Go/no-go for the 2026-06-17 release, 20-PR punch list, residual risks
- Adversarial review — The audit we held v0.2.0 to
- Product-completion plan — The frozen IN / ROADMAP / FIX boundary
- Research — Mid-2026 competitive landscape (16 competitors fetched live)
- Validation results — Real harness run, real numbers
See ROADMAP.md for the full milestone history and upcoming plans.
The release flow is documented and reproducible — no hidden steps.
- Tag a version:
git tag -a v0.X.Y -m "..."andgit push origin v0.X.Y. .github/workflows/release.ymlruns on the tag push:scripts/release.sh --dry-runfirst as a sanity check, then real publish withNPM_TOKENfrom repo secrets (provenance signing in CI). Marketplace submissions emit as a workflow summary.scripts/release.shis the single source of truth. Run it locally with--dry-runfor any audit —npm pack --dry-runper package, manifest checks, no state mutated.
Idempotent: already-published versions are skipped automatically. Scoped packages are forced public after publish so org defaults can't silently restrict them.
Anonymous usage telemetry is off by default. Nothing is sent unless you opt in with FRONTGUARD_TELEMETRY=1 or telemetry: true in config.
Opt out with any of --no-telemetry, FRONTGUARD_TELEMETRY=0, DO_NOT_TRACK=1, or telemetry: false.
When enabled, the CLI POSTs one JSON event to https://telemetry.frontguard.dev/v1/events (override with FRONTGUARD_TELEMETRY_ENDPOINT). Fields: command, version, routes, regressions, aiProvider, antiFlake, ci, durationMs, errorType, ts. No URLs, paths, screenshots, or keys. The HTTP peer can see the source IP. There is no published retention period for the default collector.
Full schema: docs/telemetry.md.
# AI Analysis (optional, BYOK — bring your own key, pick one)
FRONTGUARD_OPENAI_KEY=sk-...
FRONTGUARD_ANTHROPIC_KEY=...
# Opt-in anonymous usage telemetry (off unless set)
FRONTGUARD_TELEMETRY=1
FRONTGUARD_TELEMETRY_ENDPOINT=https://telemetry.frontguard.dev/v1/events
DO_NOT_TRACK=1Note: AI keys are optional. Frontguard works without them using local pixel comparison. AI analysis activates only when you configure a provider and sends screenshot evidence directly to that provider. Telemetry is also optional and off by default.
Contributions welcome! See CONTRIBUTING.md for guidelines, development setup, and how to submit PRs.
MIT