How to get console errors from users
Why asking a customer to open DevTools does not work, and the two browser events that collect the error for you instead.
The request goes out in every support thread: press F12, click the Console tab, and send me a screenshot. What comes back, if anything comes back, is a photograph of the Network panel.
Why the ask fails
It fails for three separate reasons, and fixing any one of them does not help.
The person does not know what DevTools is. The instructions differ by browser and by operating system, and yours were written for whichever one you use. And by the time they open the console, the page has often been reloaded, which clears it — so even a successful attempt captures nothing.
There is a fourth reason that matters more than the other three: the error happened before they decided to report anything. Whatever collects it has to have been listening already.
The two events that matter
You do not need an SDK or a build step to catch a browser error. Two standard events cover almost everything a user will hit:
window.addEventListener('error', (event) => {
// event.message, event.filename, event.lineno, event.colno, event.error.stack
});
window.addEventListener('unhandledrejection', (event) => {
// event.reason — the async failures the first listener never sees
});The second one is the half most hand-rolled implementations forget. A rejected promise from a failed fetch does not fire error, and in a modern application that is where a large share of real failures live.
What to keep, and how much
A few practical constraints, learned the boring way:
- Keep a ring buffer, not a list. A tab open all afternoon accumulates errors. The most recent ten are worth far more than the first ten.
- Truncate the stack. Two thousand characters is enough for the frames that matter and stops a pathological recursion from filling your database.
- Keep source, line and column separately. Those three are what a search in your editor actually needs.
- Do not read the console.
console.logoutput is not the same as an error, and monkey-patchingconsoleto capture it is intrusive and surprising. The two events above are the honest surface.
Then attach it to a person
An error on its own is what error monitoring already gives you, in far greater volume. What makes a user-reported error worth more is that a human is attached to it, saying what they were trying to do.
That pairing — the exception plus the intent — is the thing neither a support inbox nor an APM produces on its own.
Where source maps come in
Errors arrive as the browser reported them, which on a production build means minified file names and unhelpful line numbers. That is not a limitation of the collection; it is a property of your bundle.
If you want frames that name your real files, ship source maps to production and let the browser resolve them, or upload them to whatever tool resolves them for you. It is a one-time build configuration and it changes every stack trace you receive afterwards.