BugTape docs
Privacy proof checklist (before a capture key)
Prove scrubbing on your own screens before production.
Gate: Do not paste a live bt_live_* / bt_test_* capture key into an app that shows named clients, revenue, FX margin, or similar grids until this checklist is green.
Transmit model (honest): the SDK keeps a rolling buffer in memory until submit or automatic report. On submit / auto-report, scrubbed events — including DOM snapshots when recording is on — are stored on BugTape (Fly + Neon) for the plan event-retention window. Inputs are masked by default. Visible page text and tables are still recorded unless you block those nodes. Do not claim “raw data never leaves.”
Machine summary: /llms.txt · Privacy page: /privacy/ · Fixture: examples/privacy-fixture/
Built-in selectors (SDK defaults)
The browser SDK’s DOM recorder always uses these block / mask selectors (packages/sdk/src/security/capture-privacy.ts). There is no custom blockSelector init option today — mark nodes in the page:
| Mechanism | Selector / option | Effect |
|---|---|---|
| Block node (omit from replay) | [data-bugtape-ignore], .bugtape-ignore, .rr-block | Node (and subtree) excluded from rrweb |
| Widget / capture UI | #bugtape-widget, [data-bugtape-capture-ui] | Always blocked |
| Mask editable text | inputs / textareas / selects / [contenteditable] / .rr-mask | Values not shown as typed text |
| Disable DOM entirely | init({ disableDomRecording: true }) | No replay; keep for client-data surfaces when unsure |
| Disable network bodies path | init({ disableNetworkRecording: true }) | No fetch/XHR waterfall events |
| PII regex scrub | pii: { enabled: true } (default) | Emails, cards, SSNs, JWTs, keys, IPs — not enough for OFX-style client names in table cells |
Checklist (pass every row before a key)
| # | Step | Pass | Fail |
|---|---|---|---|
| 1 | Keep pii.enabled true (default). | Scrub left on | Scrub disabled “to debug” |
| 2 | Mark every client / revenue / margin / PII table or panel with data-bugtape-ignore (or .bugtape-ignore / .rr-block) on the container that holds the sensitive text. | Containers marked | Only CSS-hidden; text still in DOM without block attrs |
| 3 | Confirm network recording does not need request/response bodies for your use case. SDK records URL/method/status/timing — turn disableNetworkRecording: true if query strings carry client ids. | Query strings clean or network off | Client ids in URLs still recorded |
| 4 | For regulated / client-data apps where DOM scrub is unproven: set disableDomRecording: true or use server-only ingest (platform: "server") instead of the browser SDK. | DOM off or server-only | Browser SDK on live client grids without proof |
| 5 | Run the privacy fixture (or your twin page). Submit one report. In console replay / event JSON, search for the fixture’s forbidden strings. | Zero hits | Any forbidden string in replay or event payloads |
| 6 | Document the selectors you used in the app’s AGENTS.md / runbook so the next agent does not re-enable unmarked tables. | Selectors listed | “We’ll add ignore later” |
Green = every row Pass. Red = any Fail → no capture key on that surface.
Fixture proof (local)
- Open
examples/privacy-fixture/index.htmlvia any static server (or open the file and use the Setup / demo host that serves/docs/examples/privacy-fixture/). - Sensitive tables use
data-bugtape-ignoreand the documenteddata-testidvalues. - Control table is not blocked — its marker string must appear if DOM recording is on (proves the recorder works).
- Pass/fail strings and selectors: see the fixture README.
Screenshots of console replay are optional evidence; hosted PNG storage is unavailable — do not block this checklist on screenshot upload.
Server-path redaction (pairs with Python example)
Never put SQL, parquet paths with client ids, or row samples in description / metadata without an allowlist scrubber. Use examples/server/bugtape_report.py (redacts query text and table-like tokens by default).