Qaid
ARTICLE

Console Error Capture: Debug Without Asking

Automatically capture JavaScript console errors with user feedback to debug issues faster.

Qaid Team

Bug reports arrive missing the one thing you need. The user says the page broke. You ask what they clicked, whether an error came up, whether it happens every time. They don't know. Nobody reads the browser console. So the Qaid embed reads it for them.

The embed wraps console.error, warn and log

When the embed loads, it replaces those three console methods with its own. Each call gets recorded and then handed to the original, so your logging still prints the way it always did.

// Recorded during the user's session, and still printed to the console
console.error("Failed to load user profile");
console.warn("Deprecated API endpoint used");
console.log("User clicked checkout button");

It holds the last 20 messages. When a 21st arrives the oldest one drops off, so a chatty page can't grow the buffer.

Nothing to switch on

Console capture has no config flag. Load the embed and it starts:

<script
  src="https://unpkg.com/@qaiddev/thumbs-embed/dist/embed.js"
  data-endpoint="/api/feedback"
></script>

Every submission from that page now carries the buffer with it.

Reading the log in the dashboard

Open a feedback item and the messages sit in the details panel. Each one has its text, its level and the time it landed:

[14:32:15] [ERR] TypeError: Cannot read property 'name' of undefined
[14:32:15] [ERR]     at UserProfile.render (profile.js:142)
[14:32:14] [WRN] API response slower than expected: 2340ms
[14:32:10] [LOG] Fetching user data for id: 12345

Read it from the bottom. Your user asked for their profile, the API took 2.3 seconds to answer, and the render then hit data that never arrived. You asked nobody anything.

Errors show red, warnings yellow, plain logs grey.

What this looks like on a real bug

A user reports the app crashed while uploading a file. Their log:

[10:15:32] [LOG] Starting file upload: report.pdf (2.4MB)
[10:15:33] [WRN] File size exceeds recommended limit
[10:15:35] [ERR] RangeError: Maximum call stack size exceeded

A 2.4MB file blew the stack, so the bug is in how you chunk the file. That took fifteen seconds. Reproducing it by hand would have taken the afternoon.

Sometimes the log clears you completely:

[09:22:14] [ERR] ChatWidget: Failed to initialize - invalid API key
[09:22:14] [WRN] ChatWidget: Falling back to offline mode

Not your code. Your chat provider's API key expired.

Escalation rules can match the captured text

A rule that watches for TypeError|ReferenceError|SyntaxError can post to your engineering channel the moment one shows up in a report. One that watches for payment|stripe|checkout can page whoever is on call. The setup is in escalation rules.

Log things worth capturing

The embed records what you write, so write logs that still make sense to somebody else next week:

// Tells you nothing
console.error("Error");

// Tells you which document, and why
console.error(`Failed to save document ${docId}: ${error.message}`);

Keep console.error for real failures and console.warn for the near misses. If you use both for the same thing, the colours in the dashboard stop helping you.

One thing changes now that logs travel. Anything you print to the console during a session can end up attached to a report, so a stray token log is a token you shipped to your own server. Guard it:

if (process.env.NODE_ENV === 'development') {
  console.log('Debug: user token', token);
}

Capture runs from the moment the embed loads until the user submits. Nothing goes anywhere unless they choose to send it, and nothing from an earlier visit is in the buffer.

Back to all articles