AI-powered frontend visual regression testing for web teams — detect, understand, and fix visual bugs before they ship to production.
Backend has Datadog, Sentry, PagerDuty — a $20B+ monitoring ecosystem. Frontend gets... manual QA and hoping for the best. Frontguard changes that.
44 test files · multi-browser · AI vision analysis · self-hostable · MIT
Numbers above are derived from source by
scripts/stats.ts(regenerated on everynpm run stats). Seescripts/stats.jsonfor the canonical snapshot.

📽️ Demo: frontguard init → doctor → run → AI classification.
Five packages just shipped to npm:
@frontguard/cli,@frontguard/playwright,@frontguard/mcp,@frontguard/netlify-plugin,create-frontguard-plugin. Full release notes in CHANGELOG.md; go/no-go indocs/launch-readiness.md; first validation run results invalidation/results-v0.2.md(0.0% pixel-only false positives on 43 recheck routes).
Every line of Frontguard is MIT-licensed and lives in this repo. The CLI, the AI vision pipeline, the cloud-api (Cloudflare Workers + D1 + R2), the four integrations (Slack / GitHub / Vercel / Netlify), the MCP server, the Dockerised cross-OS renderer, and the self-host docker-compose are all here. The 21 PRs that built v0.2.0 are all on main — you can read the adversarial review we audited the prior state against, the competitive research that anchored the boundary, and the product-completion plan that defined what "complete" meant. Nothing is hidden behind a "request a demo."
If you'd rather not run your own AI keys, the cloud is opt-in. If you'd rather not use the cloud, the CLI is free forever. If you'd rather run the whole stack on your own machines, the self-host guide is the recipe.
- 🧠 AI-powered analysis — Doesn't just say "pixels differ." It classifies the change (regression vs intentional vs content update), explains why, and suggests a fix. This kills the #1 pain of visual testing: false positives.
- 🎯 Anti-flake rendering — Multi-render consensus eliminates the flaky-screenshot noise that makes teams disable their visual suites.
- 🤖 In-IDE agents via MCP —
@frontguard/mcpexposes "what regressed on this PR" and "give me the suggested fix for diff N" to Claude Code / Cursor / Copilot. - 🐳 Cross-OS byte-equivalent baselines — pinned Docker renderer so a fix that closes the diff on macOS closes it on Linux CI too. No more 428-day flake debugging.
- 🔓 Open-source & self-hostable — CLI-first, free forever. No per-screenshot pricing cliff, no dashboard lock-in, BYO AI key. The self-host guide is a one-command recipe.
Developer pushes code → Frontguard renders every page → Compares to baselines →
AI explains what changed and why → Suggests fixes → Posts PR comment
- Detect — Pixel diff + DOM diff catches what humans miss
- Understand — AI explains why something broke, not just "pixels differ"
- Fix — Verified code fixes, re-rendered to confirm they work (Phase 2)
Prerequisites: Node.js 20+ and npm 9+
# Install
npm install @frontguard/cli
# Initialize config (auto-detects your framework, --ci adds a GitHub Action)
npx -p @frontguard/cli frontguard init --ci
# Verify your environment is ready
npx -p @frontguard/cli frontguard doctor
# Run visual regression tests
npx -p @frontguard/cli frontguard run --url http://localhost:3000
# Accept current screenshots as new baselines
npx -p @frontguard/cli frontguard update-baselinesFull 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
- AI-powered analysis — BYOK (OpenAI/Anthropic) classifies regressions vs intentional changes
- 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
- PR thumbnails — Baseline/current/diff images embedded in PR comments (R2/S3/GitHub artifacts)
- 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 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| AI fix verification | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Anti-flake rendering | ✅ | ◐ | ◐ | ❌ | ❌ | ◐ |
| Self-hostable | ✅ | ❌ | ❌ | ✅ | ◐ | 🟡 |
| Free tier | Forever (CLI) | Trial → $399/mo | Storybook hobby | Free | Sunset | Hobby + unlimited Playwright traces |
| Pro entry | $29/mo (optional) | ~$399/mo | $179/mo | n/a | n/a | $100/mo |
| Actively maintained | ✅ | ✅ | ✅ | ❌ (low activity) | ❌ (Figma acqui-hire 2026-04-22) | ✅ |
Migrating? See the BackstopJS, Lost Pixel, and Argos guides. Comparisons: Percy · Chromatic · Argos.
✘ /dashboard @ 375px — 2.34% changed
🔴 AI Analysis — Regression (94% confidence)
"The sidebar overlaps the main content on mobile. A flex-direction
change in Dashboard.module.css:28 removed the column stacking."
Suggested fix: restore `flex-direction: column` at the < 768px 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,
// AI analysis (optional, BYOK)
ai: {
provider: 'openai',
model: 'gpt-4o',
},
// Ignore dynamic content
ignore: [
{ selector: '.dynamic-timestamp' },
],
};┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ ROUTE DISCOVERY │───▶│ RENDER PAGES │───▶│ PIXEL DIFF │
│ Crawl / Config │ │ Playwright × │ │ pixelmatch │
│ / Filesystem │ │ viewports × │ │ fast gate │
│ │ │ browsers │ │ (90% pass here)│
└─────────────────┘ └──────────────────┘ └────────┬────────┘
│ changed
▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ PR COMMENT │◀───│ AI ANALYSIS │◀───│ DOM DIFF │
│ Visual diffs │ │ GPT-4V / Claude │ │ Structural + │
│ Explanation │ │ Classify + │ │ computed styles │
│ Fix suggestion │ │ explain + fix │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
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: "Sidebar overlaps main content on mobile.
flex-direction change in Dashboard.module.css:28"
Severity: 🔴 Critical (confidence: 94%)
1 regression · 1 warning · 9 passed · 1 new
Frontguard ships with a plugin architecture (6 lifecycle hooks) and 5 built-in plugins:
| Plugin | Description | Key Features |
|---|---|---|
Figma (src/plugins/figma.ts) |
Design-to-code comparison | Figma API integration, design token extraction, component mapping |
Performance Budgets (src/plugins/perf-budgets.ts) |
Web Vitals & budgets | LCP/CLS/TTFB thresholds, violations correlated with the visual diff |
Accessibility (src/plugins/accessibility.ts) |
axe-core audits | WCAG checks (contrast, alt text, target size, focus, headings) in the same render pass |
Third-Party Scripts (src/plugins/third-party-scripts.ts) |
Script drift detection | Flags ad/analytics/widget origins that appear or disappear between runs |
Monitor (src/plugins/monitor.ts) |
Production visual monitoring (CLI + optional cloud scheduler) | Live-URL checks, threshold alerting, history tracking |
Plugin lifecycle hooks: beforeDiscover, afterDiscover, afterRender, afterCompare, afterRun, onError
// frontguard.config.ts
import { createFigmaPlugin } from '@frontguard/cli/plugins';
export default {
// ...base config
plugins: [
createFigmaPlugin({ fileKey: 'your-figma-file-key' }),
],
};src/
├── cli/ # CLI entry point (Commander.js)
├── 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, accessibility, third-party scripts, monitoring
└── utils/ # Redaction, logging, retry
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.
# AI Analysis (optional, BYOK — bring your own key, pick one)
FRONTGUARD_OPENAI_KEY=sk-...
FRONTGUARD_ANTHROPIC_KEY=...
# GitHub PR comments
GITHUB_TOKEN=ghp_...Note: AI keys are optional. Frontguard works without them — pixel diff and DOM diff run locally. AI analysis (classification, explanations, fix suggestions) activates only when a key is provided.
Contributions welcome! See CONTRIBUTING.md for guidelines, development setup, and how to submit PRs.
MIT