DevTools you didn't open. Privacy-first passive capture for bug reports.
A Chrome (MV3) extension that silently records browser activity in the background — network requests, console errors, user actions — so when something breaks, you can scrub back through what just happened and share a complete, faithful bug report.
No backend, no signup, no telemetry. Open source under MIT.
Status: M4 milestone shipped at v0.4.0 (May 2026). The
killer-differentiator standalone HTML replay bundle, recording mode
with Tier 4 captures, multi-destination sharing hub (Slack / Discord /
Teams webhooks + GitHub Issue / mailto web intents), ZIP-everything
export, "Replay this request" and a privacy preview modal are all
live. M5 is pre-launch polish (perf + a11y + security audits, CWS
public submission).
The capture system is organized into four tiers (PRD §6.1.1). The extension's M1 build only activates Tier 1; the rest light up as their respective milestones land.
| Tier | Events | Default | M1 | M2 | M3 | M4 |
|---|---|---|---|---|---|---|
| 1 — Essential | fetch, XMLHttpRequest, page navigations, console errors / unhandled rejections |
on | ✅ fetch / XHR | + console + nav | refine | refine |
| 2 — Important | Clicks, form input changes, WebSocket frames, console warn/info | on | — | ✅ | refine | refine |
| 3 — Conditional | Page screenshots on error, performance long tasks, layout shifts, Server-Sent Events | trigger | — | — | ✅ | refine |
| 4 — Recording mode | Periodic screenshots, cursor trail, scroll, DOM mutations, tab focus | opt-in | — | — | — | ✅ |
Captured events are stored per tab in chrome.storage.local under
sessions/{tabId}/events (PRD §6.1.3). The buffer holds the most recent
200 events per tab by default (50 / 200 / 500 / 2000 user-selectable in
Settings → Capture); FIFO eviction past that. Closing a tab moves its
session into archives/recent with a 7-day TTL. Storage writes batch
at 250 ms (PRD §13.2). The Tier 2 capture families can be turned off
collectively in Settings → Capture; Tier 1 cannot.
Three architectural commitments (PRD §4):
- No lossy cleanup — captures are stored as-is; we never denoise,
re-order, or "smart-summarize" them. Explicit, documented size caps
do apply at capture time for stability and bounded storage (see
Capture limits), but a capped value is cut at a
fixed length with a visible
…[truncated]marker — never a silent edit — and the per-tab buffer is a rolling window whose omitted count is reported in every export. - Your data does not leave your machine unless you choose — the extension makes zero outbound requests of its own. Webhooks, web intents, and file downloads are user-initiated only.
- Zero setup, useful from minute one — defaults work; settings exist for power users.
Sensitive values are replaced with ***MASKED*** at capture time,
inside the service worker, before anything is written to storage. The
original value is never persisted and cannot be recovered.
Default rules:
- Headers —
Authorization,Cookie,Set-Cookie,X-API-Key,X-Auth-Token,Proxy-Authorization(case-insensitive). - Body content — TCKN (Turkish national ID with checksum validation), credit card numbers (with Luhn validation; 13–19 digit runs).
- Form fields (active when Tier 2 input capture ships in M2) —
<input type="password">,autocomplete^="cc-", and names matchingpassword|secret|token|ssn|pin.
Custom regex patterns and a per-domain blocklist are configured under Settings → Privacy. Both ship in M1.
Every event in the popup detail view shows a Privacy panel summarising what was masked. The HAR / JSON export reflects the same masked values — there is no second pass at export time, because there is nothing to mask: the data was already clean when it landed in storage.
Captures are stored as-is, but bounded — a single service worker and one
chrome.storage.local back it, so unbounded capture across many active
tabs would slow the browser and crash the extension. The caps below are
generous (a 200 KB body dwarfs almost any real payload); a value over a
cap is cut at a fixed length with a visible …[truncated] marker (never
silently dropped), and the per-tab buffer is a rolling window — the
oldest events age out and every export reports how many were omitted.
| Cap | Value | Applies to |
|---|---|---|
| Body | 200 KB | each request / response body |
| Form-input value | 10 KB | a field's value per keystroke |
| Console argument | 10 KB | each console argument |
| Per-tab rolling buffer | 200 events (Settings → up to 2000) and 2 MB, first to hit | live buffer per tab |
| Closed-tab archive | 30 sessions, 7-day TTL | archived (closed) sessions |
These are stability/storage bounds, distinct from masking (above), which removes sensitive values entirely and irreversibly.
Hindsight is live on both stores: Add to Chrome · Add to Firefox.
To run a local build instead of the store version:
# 1. Install deps
nvm use # picks up Node 20 from .nvmrc (Node ≥20 works)
npm install
# 2. Produce a load-unpackable build
npm run build # writes dist/
# 3. Load in Chrome
# chrome://extensions → Developer mode → Load unpacked → select dist/Useful scripts during development:
npm run dev # Vite + CRXJS with HMR for the popup / settings UIs
npm run lint
npm run format:check
npm run typecheck
npm test # Vitest unit suite
npm run bench # PRD §13.1 fetch/xhr/masking/filter gates (CI-blocking)
npm run bench:multitab # real-Chromium 20-tab storage/crash gate (on-demand)CI (.github/workflows/ci.yml) runs all of the above on every push and
PR to main, plus uploads the built dist/ as an artifact for each
commit so reviewers can load-unpack a PR build without checking out.
The full plan lives in Hindsight-PRD-v0.1.md
§18. M1 has just closed.
| Milestone | Theme | Status |
|---|---|---|
| M1 — Foundation | TS port, CapturedEvent model, manifest §9.2 baseline, masking engine, Settings + Privacy UI, HAR export, perf gate | ✅ v0.1.0 |
| M2 — Context capture | Tier 2 events (clicks, inputs, console, nav, WebSocket, SPA routes), narrative engine v1, batched writes, archive, Capture settings | ✅ v0.2.0 |
| M3 — Side panel + visual timeline | chrome.sidePanel migration, scrubber, screenshot capture, detection rule engine, cluster grouping, recent-archive viewer |
✅ v0.3.0 |
| M4 — Replay bundle + sharing hub | Standalone HTML viewer, recording mode, multi-destination sharing (Slack / Discord / Teams / GitHub / Linear / email / Notion) | ✅ v0.4.0 |
| M5 — Pre-launch polish | Performance optimization (capture-pipeline + storage hardening), WCAG AA audit, security audit, CWS submission | 🚧 v0.7.x |
AI / LLM integration is explicitly deferred to v2+ (PRD §22.1).
┌─ Page world (MAIN) ──────────────┐
│ interceptor.ts │
│ • createFetchPatch │ window.postMessage
│ • createXhrPatch │──────────────────┐
│ (src/lib/network-patch.ts) │ │
└──────────────────────────────────┘ ▼
┌─ Isolated world ─┐
│ bridge.ts │
└─────────┬────────┘
│ chrome.runtime
▼
┌─ Service worker ──────────────────────────────────────┐
│ service-worker.ts │
│ • Privacy: maskHeaders + maskBody + origin blocklist │
│ • Envelope minter: id / sessionId / sequence / ts │
│ • Storage: appendEvent → chrome.storage.local │
│ (src/lib/storage.ts · src/lib/masking.ts) │
└────────────────────┬──────────────────┬───────────────┘
│ │
▼ ▼
┌─ Popup ──────────────────┐ ┌─ Settings (options_ui) ─┐
│ • Filtered list │ │ • General (theme) │
│ • Detail view │ │ • Privacy │
│ • Privacy panel │ │ — default chips │
│ • Copy / Download / │ │ — custom patterns │
│ HAR export │ │ — origin blocklist │
└──────────────────────────┘ │ — test sandbox │
└─────────────────────────┘
The PRD anchors used most often:
src/types/events.tsimplements PRD §6.1.2 (CapturedEvent model)manifest.jsonmatches PRD §9.2 baselinesrc/lib/storage.tsis PRD §6.1.3 (per-tab keys, eviction)src/lib/masking.tsis PRD §11.2 (capture-time PII masking)bench/fetch-overhead.bench.tsenforces PRD §13.1 (perf budget)
See CLAUDE.md for contributor conventions.
MIT. See LICENSE (added at first public push).
Osman Unal · solo project · built part-time at 5–8 hours/week.