Most users who hit a bug say nothing. They tap the button again, find a workaround, or close the tab and quietly think a little less of your app. A small minority — the unusually invested or the unusually annoyed — will hunt down your support email and write it up. Everyone else is invisible. Why users don't report bugs isn't a mystery, it's a price list: every report costs time and attention, and pays nothing. The fix isn't asking harder. It's deleting every step between "that's broken" and "sent."
How many users actually report bugs?
A small minority — and a biased one. The closest well-studied number comes from Nielsen Norman Group's participation-inequality research: in online communities, roughly 90% of users lurk, 9% contribute occasionally, and 1% account for most contributions. Filing a bug report is contribution at its least rewarding — no karma, no audience, only unpaid QA for software that has just wasted your time — so there's no reason to expect reporting to beat those numbers.
Decades of customer-complaint research point the same direction: most dissatisfied customers never tell the company anything. They tell their friends, or nobody, and they stop showing up.
That has two ugly consequences for anyone triaging by inbox:
- Volume lies. One report can mean one affected user or a thousand. Silence doesn't mean health — it means friction won.
- The sample lies too. The reports you do get come from your 1%: power users, fellow developers, people with patience. The confused majority who hit the same bug and bounced are exactly the people you never hear from.
Why don't users report bugs?
Because reporting costs too much and pays nothing. Every unit of user-feedback friction converts an almost-report into silence. Look at the ledger for a classic "email us at support@" bug report:
- Stop what they were doing — which was, notably, not "testing your app."
- Find the right channel. Footer link? Help center? The contact form hidden behind two menus?
- Describe the bug in writing, from memory, possibly in their second language.
- Take a screenshot, crop it, attach it.
- Dig out the version number, browser, OS — things they don't know and shouldn't have to.
- Write repro steps, like it's their job. It is not their job.
Every step sheds people. The user owes you none of this — they're not QA, they're someone who wanted to finish a task and couldn't. The handful who push through all six steps are doing you a genuine favor, and the form usually thanks them with "we'll respond within 3–5 business days."
(Honest aside: if you have a dozen users, skip the tooling. Email them, watch them use the app, say thanks. Frictionless reporting starts to matter once you can no longer talk to everyone personally.)
What silent users cost you
A bug nobody reports doesn't get fixed — it gets discovered, months later, by you, in the worst possible venue.
- Bugs live for weeks. Without reports, a broken flow survives until a teammate trips over it or an invoice doesn't add up.
- Prioritization runs on the loudest voice. When reports are scarce, one angry email from a big account outweighs the checkout bug silently hitting a hundred small ones. You end up ranking by who complains, not by what's broken.
- Reviews and churn become your error tracker. The feedback eventually arrives — as a two-star review with no repro steps, or as a cancelled subscription with no note at all. Both are bug reports. Both arrive too late to act on.
How do you get users to report bugs? Delete the steps
You don't get more bug reports by asking more often. You get them by making a report cost one gesture and zero context switches. In practice that means two mechanisms, because bugs come in two kinds.
Let crashes report themselves
Anything that throws shouldn't need a human reporter at all. An error-tracking SDK catches the exception, keeps the stack trace, groups duplicates into one issue, and counts how many users it hit — the report files itself, with better detail than any user could type. With Catch that's an npm install and an access token; the getting-started guide takes about five minutes. It matters double when you're shipping fast with AI assistance — we wrote about why in error tracking for AI-generated apps.
One gesture for everything an exception can't see
Most of what frustrates users never throws. The total that's wrong. The button that does nothing. The screen that looks off. No exception, no stack trace — the only sensor that detects this class of bug is a human, so the human's report has to be effortless. That's what in-app bug reporting is for.
On mobile, the trigger is a gesture users already know: shake the phone to report, and the SDK captures the current screen on the spot (the iOS and Android CatchDev SDKs are in early access — and they capture feedback, not crashes). On the web there's no shake, so the trigger is a floating button, a keyboard shortcut, or any UI of yours:
import { CatchDev } from '@catch.dev/feedback';
CatchDev.start('ck_your_key', {
environment: 'production',
appVersion: '1.4.0',
shortcut: 'ctrl+shift+f', // optional, alongside the floating button
});
// attach identity so you can follow up
CatchDev.setUser('user-123', 'sam@example.com');
That snippet starts the web feedback SDK — @catch.dev/feedback, currently in early access. A small launcher appears in the corner; when a user clicks it, they capture a screenshot of the tab, draw on it to circle the problem, type a note, and hit Send. Screenshots use the browser's own getDisplayMedia screen-capture API, which requires HTTPS, a user gesture, and an explicit tab-share prompt. The SDK captures and sends nothing until the user opts in and taps Send. Where capture isn't available (mobile browsers, a declined prompt), the reporter falls back to a text-only note. The whole widget is about 8 kB gzipped with zero runtime dependencies, rendered in a Shadow DOM so it can't fight your CSS.
The flow is identical on every platform: trigger → screenshot → annotate → note → send. One gesture, one sentence, done — the user never leaves the screen the bug is on.
What a good bug report contains — when the SDK does the work
Don't lower your standards for reports. Move the work from the user to the SDK. Here's who supplies what in a feedback report:
| Field | Who provides it |
|---|---|
| Screenshot of the exact screen | SDK — captured at trigger time |
| Annotation circling the problem | User — one drag |
| The note ("total is wrong after applying a coupon") | User — one sentence |
| App version and build | SDK — on web you pass it to start |
| OS and device | SDK |
| Locale | SDK |
| Environment | Your code — via setEnvironment |
| User identity | SDK — via setUser |
| Custom context (plan, feature flags) | Your code — via setMetadata |
The user typed one sentence and drew one circle. Everything you'd normally beg for across a five-email support thread — version, device, which screen, which user — arrives attached, and the report lands in your dashboard under App → Feedback.
Close the loop — reporters are renewable
When a report arrives, answer it. The people who report bugs are your 1%; a short "fixed in today's release, thanks for the screenshot" turns them into people who report the next one too. A delivery callback even lets you say thanks in-app the moment the report goes out. Reporting begets reporting. Silence begets silence.
The usual objection: "won't we drown in feedback?" Only if triage is expensive. A report that ships with a screenshot, an annotation, and full device context takes seconds to route or close — the expensive reports are the vague ones, and those are exactly what this kills. More signal from the silent 90% is the whole point.
Users don't report bugs because we've made reporting a chore and offered nothing back. Make it one shake or one click, do the paperwork for them, and reply when they do. Catch is free for hobby apps — wire it up and find out what the silent majority has been hitting all along.