Crumbtrail documentation
Everything you need to capture complete sessions, detect the moment a user gives up, and hand the reproduction to your coding agent.
Introduction
Crumbtrail has two packages. crumbtrail-core is the browser SDK: it runs the collectors and the silent-signal detectors inside your app. crumbtrail-node is the local server: capture ingest, Express middleware, the CLI, and an MCP server that exposes finished sessions as tools your coding agent can call. Adopt only what you need.
Quickstart
On Crumbtrail Cloud? Create an account and the in-app setup wires your app in one guided pass. The steps below run the local capture server yourself — no account needed.
1. Install and start the server
pnpm add crumbtrail-core crumbtrail-node
# start the local capture + MCP server on :9898
# (sessions land under ~/.crumbtrail/sessions)
npx crumbtrail-server serveOn pnpm 10+? Its supply-chain check queries the registry for every dependency, and a version that was just published can fail a fresh lockfile with ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION until it ages in. If you hit that for crumbtrail-core, add it to minimumReleaseAgeExclude in pnpm-workspace.yaml (pnpm does not read this key from .npmrc).
2. Initialize in the browser
import { Crumbtrail } from "crumbtrail-core";
// "passive" — embedded end-user monitoring: collectors on,
// silent-signal detection enabled, no widget.
Crumbtrail.init("passive");
// …or configure explicitly:
Crumbtrail.init({
httpEndpoint: "http://localhost:9898",
autoFlagOnSignals: true,
});3. Verify end to end
Use your app as normal, then let the doctor prove the pipeline — capture, correlation, and MCP-readability — before you trust it:
npx crumbtrail-server doctorCollectors
A collector subscribes to one source of browser events. Each is a boolean in Crumbtrail.init(); the full, light and passive presets pick sensible sets so you rarely toggle them by hand.
Interactions
Clicks, inputs and route changes, keyed to a stable component signature — not a brittle CSS path.
Keystrokes
Key events with sensitive input types (password, email, tel and more) masked by default.
Console
console.log / warn / error, with level and serialized, redacted arguments.
Network
fetch and XHR — method, URL, status, timing and redacted bodies, with cross-origin correlation headers.
Errors
Uncaught exceptions and unhandled promise rejections, with stacks.
Scroll & visibility
Throttled scroll position plus tab visibility — the raw material of the give-up signal.
Cookies & storage
Cookie changes plus localStorage, sessionStorage, IndexedDB and Cache API writes, value-capped and maskable.
Clipboard
Copy and paste events, length-capped; raw contents off by default.
Performance
Timing marks, so a slow response is a recorded fact instead of a memory.
Environment & flags
Feature flags, config, build and runtime recorded with every session.
Detection
The SDK keeps a rolling buffer of the last five minutes of session events. Four behavioral detectors watch that stream for the signals of a user giving up — none of them requires an exception. When one fires, Crumbtrail flags the reproduction window around it as a bug, automatically.
Rage-click
Four or more clicks on the same target within 1.5 seconds. The button that does nothing.
Retry storm
Four or more requests to the same endpoint within 5 seconds, or repeated failed responses. The user hammering refresh.
Slow response
Three or more responses of 3 seconds or longer inside a 10-second window. The app that feels broken.
Abandoned flow
Two or more filled inputs, then the tab hides with no submit. The form the user walked away from.
Enabled by autoFlagOnSignals — on in the passive and fullpresets. Every threshold above is a config key; tune them to your app's rhythm.
Session format
Each session is a directory of plain files you fully own: events.ndjson (the raw, append-only log), a manifest, and a pre-computed evidence index including a normalized, redacted search.jsonl. Agents read the index; the raw log stays cold.
{"t":1751818000123,"k":"clk","d":{…}}
{"t":1751818000304,"k":"net.req","d":{…}}
{"t":1751818000451,"k":"net.res","d":{…}}
{"t":1751818000460,"k":"err","d":{…}}Every event shares t (Unix milliseconds), k (a kind code — clk, net.req, con, err, db.diff, …) and d, the collector-specific payload.
Integrations
Two ways to get your stack into a bundle — stream it in, or let Crumbtrail pull it at ticket time. Pick per source; most teams run both.
Stream it in — SDK & OTLP
Express / Node
createCrumbtrailExpressMiddleware correlates backend requests to the click that caused them, across origins.
OpenTelemetry / OTLP
Already on Sentry, Datadog, Grafana or Splunk? Point an exporter at the server — crumbtrail-server init --provider <name> prints the exact block.
Headless sessions
startHeadlessSession records backend job runs — imports, syncs, scheduled tasks — as sessions with no browser at all.
Or pull it at incident time — evidence adapters
When a ticket arrives, Crumbtrail queries the observability tools you already run inside the located incident window and folds the hits into the same ranked bundle — no re-instrumentation. Fetches are read-only and zero-copy: only the derived bundle is stored, never the raw provider data. A missing join key degrades to an honest gap, never an error.
Sentry
logscodeErrors and breadcrumbs from the incident window, correlated by trace id, release or URL.
CloudWatch
logsLogs Insights queried by request id or trace id, scoped to the incident window.
Splunk
logsSearch results bounded to the window by trace id, request id or service.
Datadog
logsnetworkLogs and network spans matched by trace id, service or URL.
PostHog
browserflowThe user's own events and session replay, by distinct id, session or URL.
Cloudflare
networklogsEdge request logs and R2-archived Logpush by request id or URL.
See the full capture pipeline for spans, database diffs and MCP.
MCP for agents
The same binary serves MCP over stdio — so your coding agent pulls the evidence itself instead of guessing from a screenshot.
{
"mcpServers": {
"crumbtrail": {
"command": "npx",
"args": ["crumbtrail-server", "serve", "--mcp"]
}
}
}More than thirty tools in total. The ones you'll reach for most: getFixContext (the ranked causal window for one failure), getRegressionContext (what diverged between two releases), getEvidence, listBugs, listSessions and getEvents.
CLI reference
One binary, crumbtrail-server. Run any command with --help for flags.
serveRun the local capture + MCP server (default if no command given).
initInstall the SDK into your project and generate wiring helpers.
doctorVerify capture, correlation and MCP-readability end to end.
scanFlag components and functions missing IDs or logging — coverage gaps.
fix-contextEmit the ranked, correlated, LLM-ready fix-context bundle for a session.
inspectSummarize a finalized session's manifest and artifacts.
compareCompare two recorded sessions or releases.
Self-hosting
The capture server is a single process with no database — it appends plain files to disk. Run it anywhere Node runs; set CRUMBTRAIL_AUTH_TOKEN to require a token on ingest.
CRUMBTRAIL_AUTH_TOKEN=<token> \
npx crumbtrail-server serve --port 9898 --output /var/crumbtrail/sessionsSessions are plain files under the output directory — back them up, rotate them or delete them with ordinary tooling. Crumbtrail is deployment-flexible: run the server wherever your compliance posture wants it.
FAQ
Where do my sessions live?
Wherever you point the SDK. Crumbtrail is deployment-flexible — self-host the capture server, or use the hosted service when you want detection at scale without running infrastructure.
How do I avoid capturing passwords?
Sensitive input types — password, email, tel, number, search, url — are masked by default via maskInputTypes; add ignoreSelectors to skip elements entirely. The redaction engine masks values before an event is ever stored.
Is the SDK really open source?
The self-host core writes to plain files you control — audit exactly what is captured before you ship it. Source access is available on request.
Ready to capture your first session?
Create an account or jump straight into the SDK.