snapfail Documentation
snapfail is a context capture layer for AI-assisted debugging. When your app crashes in the browser, snapfail captures the full evidence and packages it so your AI agent (Claude Code, Cursor, Copilot) can diagnose the root cause directly.
How it works
snapfail explain <id> and receives the root cause + fix prompt.Quick start
One command installs and configures everything.
1. Install
# npm
npm install -g @snapfail/cli
# or bun
bun add -g @snapfail/cli 2. Initialize in your project
snapfail init snapfail init does everything automatically:
- Detects your framework (Astro, Vite, Next.js)
- Opens the browser for authentication
- Injects the browser SDK into your framework config
- Writes
SNAPFAIL_PROJECT_KEYto your.env - Generates
.agents/skills/snapfail/SKILL.mdfor your AI agent
3. Ask your AI to investigate
# List unresolved incidents
snapfail incidents
# Full diagnosis for an incident
snapfail explain <id> snapfail init
Sets up snapfail in your project. You only need to run this once.
snapfail init What it does
| Step | Description |
|---|---|
| Detect framework | Scans package.json to identify Astro, Vite, or Next.js |
| Authenticate | Opens the browser for login/register. Token is saved to ~/.snapfail/auth.json |
| Create project | Creates or selects a project on app.snapfail.com |
| Inject SDK | Modifies astro.config.mjs, vite.config.ts, or next.config.js |
| Write .env | Adds SNAPFAIL_PROJECT_KEY to your .env file |
| Generate SKILL.md | Creates .agents/skills/snapfail/SKILL.md with context for your AI |
snapfail incidents
Lists incident groups for your project.
snapfail incidents [options] Options
| Flag | Default | Description |
|---|---|---|
--status | unresolved | unresolved ยท resolved ยท ignored ยท all |
--json | โ | JSON output without ANSI colors (for LLM use) |
--pk <key> | from .env | Override the project key |
--json to avoid ANSI characters in the output.Example output
{"groups": [
{
"id": "inc_8f2a",
"title": "TypeError: cannot read 'total' of undefined",
"severity": "critical",
"status": "unresolved",
"count": 1284,
"affectedUsers": 312,
"lastSeen": "2025-06-01T18:30:00Z",
"environments": ["prod"]
}
]} snapfail incident <id>
Detail for a group: summary + representative sample.
snapfail incident <id> [--sample <n>] [--json] Options
| Flag | Description |
|---|---|
--sample <n> | Sample index (0-based). Useful for comparing different occurrences of the same error. |
--json | Structured output without visual formatting |
--pk. snapfail resolves the project automatically from your session.snapfail explain <id>
The primary command for AI diagnosis. Emits the full structured evidence from up to 3 samples, ready for the LLM to reason about the root cause.
snapfail explain <id> The output includes:
- group โ normalized title, severity, count, affected users
- samples[].stackFrames โ call stack at error time, frames from your app highlighted
- samples[].consoleEntries โ console logs before the error
- samples[].networkEntries โ network requests with status, duration, and headers (no auth)
- samples[].timeline โ sequence of user interactions
- samples[].device โ user agent, viewport, language
snapfail explain directly and reason about the root cause. Do not delegate to another model โ the evidence is sufficient to diagnose.snapfail suppress
Manage suppression rules to filter known noise (browser errors, bots, healthchecks).
# List active rules
snapfail suppress list
# Create a rule
snapfail suppress add --field message --pattern "ResizeObserver loop*"
# Delete a rule
snapfail suppress delete <rule-id> Available fields
| Field | Description |
|---|---|
message | Glob pattern on the error message |
useragent | Pattern on the user agent (useful for filtering bots) |
url | Exact URL or pattern (e.g. /healthz) |
script_origin | Origin of the script that threw the error |
Browser SDK
The SDK runs in the end user's browser. It captures errors in real time using four event-driven collectors that write to an in-memory ring buffer.
window.onerror, unhandledrejection, and 4xx/5xx network errorsconsole.error/warn/log to capture the last N logs before the errorfetch wrapper and XMLHttpRequest patch + PerformanceObserverMutationObserver + click, input, scroll, and navigation listenersWhen an error occurs, the SDK freezes the buffer, assembles the IncidentSample, scrubs sensitive data in the browser before sending, and transmits to the cloud endpoint.
Framework adapters
snapfail init installs the correct adapter automatically. You can also do it manually:
Astro
import { defineConfig } from 'astro/config';
import snapfail from '@snapfail/astro';
export default defineConfig({
integrations: [snapfail()]
}); Vite
import snapfail from '@snapfail/vite';
export default { plugins: [snapfail()] }; Next.js
const snapfail = require('@snapfail/next');
module.exports = snapfail({ /* next config */ }); Configuration
The SDK is configured with the project key and environment options.
snapfail("proj_xxxxxxxxxxxxxxxxx", {
endpoint: "https://app.snapfail.com", // ingest URL
env: "prod", // "dev" | "prod"
replay: true, // DOM replay (default: true)
storage: false, // storage snapshot (default: false)
}); | Option | Type | Default | Description |
|---|---|---|---|
endpoint | string | โ | Base URL of the ingest server |
env | string | "prod" | Environment tag. Use "dev" during development |
replay | boolean | true | Capture DOM replay (MutationObserver) |
storage | boolean | false | Include localStorage/sessionStorage inventory |
Incidents & groups
snapfail groups occurrences of the same error by fingerprint โ a deterministic signature derived from the normalized message + stack trace.
IncidentGroup
Aggregates all occurrences of the same error. Has count, affected users, first and last seen, and up to 50 samples.
IncidentSample
A specific occurrence with full evidence: stack, console, network, timeline, device. Samples are chosen with reservoir sampling to maximize diversity.
Fingerprint normalization
| Pattern | Replaced with |
|---|---|
| UUIDs | [uuid] |
| Hex hashes โฅ8 chars | [hash] |
| Numbers โฅ6 digits in paths | [id] |
JWTs (eyJ...) | [token] |
| Dynamic path segments | /users/[id] |
Sampling
snapfail uses reservoir sampling with diversity to keep a maximum of 50 samples per group. Instead of saving the first N identical occurrences, it prioritizes:
- Samples from different time periods
- Different environments (
devvsprod) - Different devices and browsers
This ensures that when analyzing samples, the LLM sees variety โ not 50 identical occurrences from the same user on the same device.
Privacy & scrubbing
Scrubbing happens in the end user's browser, before anything leaves the network. No sensitive data ever reaches the server.
Network headers โ full drop
Query params โ value replaced with [redacted]
Console
- JWTs (
eyJ...) โ[token] - API keys with prefixes (
sk-,pk_live_,Bearer) โ[api-key]
Replay / DOM
input[type=password]โ valueโโโโโโ- Inputs with name/id in
password|token|secret|card|cvv|ssnโ masked - Card number pattern โ
[card]
storage: true.SKILL.md
snapfail init automatically generates .agents/skills/snapfail/SKILL.md โ a context file your AI agent reads so it can use snapfail without you having to explain anything.
It contains:
- Project summary (detected framework, routes, endpoints)
- Incident format and how to interpret it
- CLI commands and when to use them
- The project-specific fix prompt pattern
To activate it in Claude Code, import the skill from your CLAUDE.md:
import .agents/skills/snapfail/SKILL.md Reading evidence
When your AI runs snapfail explain <id>, it receives structured evidence from up to 3 samples. Here's how to interpret each field:
| Field | How to use it |
|---|---|
group.title | Normalized error message โ the starting point for diagnosis |
sample.stackFrames | Look for frames with app: true โ those are from your code, not libraries |
sample.consoleEntries | Read in chronological order โ logs before the error reveal the state at the time of failure |
sample.networkEntries | Look for requests with status 0, 4xx, or 5xx โ these are often the root cause |
sample.timeline | Replay the user's steps โ useful for intermittent reproduction bugs |
sample.device | Critical for mobile- or browser-specific bugs |
Fix prompts
After diagnosing, snapfail explain generates a fix prompt ready to paste into Cursor, Claude Code, or your preferred agent.
In Cart.jsx:42, the component reads `cart.total` assuming `cart`
always exists, but `/api/cart` can respond with an empty body.
Fix:
1. Guard the access with `cart?.total ?? 0`
2. Add empty-state handling before rendering the checkout
3. Verify the `/api/cart` contract โ it should return `{ items: [] }`
instead of an empty body when the cart is empty The fix prompt includes:
- Exact file and line of the error
- Technical root cause
- Concrete fix steps
- API contract context if applicable
snapfail init in your project.