Breadcrumbs: the Poor Man's Session Replay
An error report lands in your tracker: TypeError: Cannot read properties of undefined (reading 'id'), thrown from a checkout component. The stack trace tells you where the code died. It tells you nothing about the thirty seconds before — what the user clicked, which requests failed, what warnings hit the console. Breadcrumbs, error tracking’s answer to exactly that question, are something you’re probably already collecting without having thought much about what they are.
Breadcrumbs: error tracking’s short-term memory
A breadcrumb is a small timestamped record of one thing that happened before an error. The SDK in your app quietly appends them to a rolling buffer as the user works: a click here, a navigation there, a fetch, a console warning. The buffer is capped — commonly the last 100 entries — and old crumbs fall off the back. Nothing is sent anywhere until an error actually fires; then the whole trail is attached to the report and shipped together.
A trail for our checkout error might end like this:
[
{ "timestamp": "12:03:41", "category": "ui.click", "message": "button#apply-coupon" },
{ "timestamp": "12:03:42", "category": "fetch", "message": "POST /api/coupons", "data": { "status": 500 } },
{ "timestamp": "12:03:42", "category": "console", "message": "coupon lookup failed, using fallback" },
{ "timestamp": "12:03:44", "category": "ui.click", "message": "button#place-order" }
]
Suddenly the TypeError isn’t a mystery. The coupon endpoint 500’d, some fallback path left state half-initialized, and the next click walked off the end of it. Four lines of trail did what the stack trace couldn’t: reconstructed the sequence.
The typical categories are clicks and other UI interactions, route navigations, network request summaries (method, URL, status — not bodies), console output, and custom crumbs you add yourself (breadcrumb("cart-migrated-to-v2") — cheap and disproportionately useful).
The ceiling
Breadcrumbs are a receipt, not security footage. A receipt proves what was purchased and when, and for a lot of disputes that settles it. But if the question is what happened in the store — what the customer looked at, where they hesitated, what the shelf actually displayed — the receipt has nothing for you. Every limitation of breadcrumbs is a version of that gap.
No DOM state. A crumb says click on button#place-order. It cannot tell you what the button said, whether the price above it was wrong, or whether a modal was covering half the form. The page’s actual state at each moment simply isn’t recorded.
Truncation. The rolling buffer means a bug whose cause is 200 interactions upstream has already scrolled off. Long sessions keep only their tail. Individual crumbs get truncated too — long URLs and messages are cut at a few hundred characters, and request/response bodies were never captured in the first place.
Only-on-error. The trail ships when an exception fires. The sessions where a user silently struggled, hit a dead button five times, and left — no error, no crumbs, no record at all.
Interpretation is on you. Reading a trail is reading a transcript with the video missing. Two engineers can reconstruct two different stories from the same twenty crumbs, and there’s no way to check either one against what the screen showed.
When breadcrumbs are honestly enough
Quite often, is the honest answer — and this is the part vendors of heavier tools tend to skip.
If your errors are mostly logic errors — a null that shouldn’t be null, an API contract violation, a state machine in an impossible state — the sequence of events is usually the whole story, and breadcrumbs carry it. Backend-ish frontend bugs, where the trigger is “this request failed and we handled it badly,” practically solve themselves from a trail like the one above.
They’re also nearly free. A ring buffer of small objects in memory, zero network traffic until an error, negligible CPU. There is no serious performance argument against breadcrumbs, which is not something session replay can claim.
And they reward a little investment. Most teams run with whatever the SDK auto-collects, but the custom crumb API is where trails get genuinely diagnostic: drop a breadcrumb at every state transition your app considers meaningful — cache invalidated, retry scheduled, feature flag evaluated — and your future self reads error reports annotated in your own domain language instead of raw clicks and URLs. Ten minutes of instrumentation, permanent payoff.
My rule of thumb: if, for your last ten frontend bugs, “what happened, in order” would have cracked the case, breadcrumbs are enough and you should spend your complexity budget elsewhere.
The upgrade path
The cases that blow past the ceiling are the ones where seeing the page is the evidence: layout bugs, wrong data rendered to the screen, users fighting a UI that technically threw no errors. When you’re staring at a trail thinking “I know what they clicked, but I cannot picture what they were looking at” — that’s the signal.
The upgrade isn’t a different philosophy, it’s the same buffer trick with richer contents. Replay tools record DOM snapshots and mutations into a rolling buffer and, in buffered modes, only persist it when an error fires — breadcrumbs with the page state included. Same receipt, plus the footage. What that recording actually contains (and pointedly doesn’t) is its own topic: see what session replay actually records.
Start with breadcrumbs. Let the bugs that breadcrumbs can’t crack — not a feature list — tell you when to upgrade.
See the bug the way your user did
LogReplay captures session replays, console output, network requests, and errors in one timeline — so you stop guessing what happened before the ticket arrived.
Try LogReplay free