Checked against the official Android Developers and Android Open Source Project debugging documentation. Confirm current tool options before standardising a process around them.
A vague bug report costs more than it saves. “Upload is broken” says nothing about the screen, the build, the device, or what happened before the failure. The report bounces back for clarification, the tester has moved on, and the fix waits. A report another person can follow is faster to write than the argument that follows a bad one.
This guide gives you a format to copy, two worked examples, and a triage-and-retest workflow. The closed-testing feedback guide covers a whole test cycle; this one narrows in on one report.
Quick answer: make the report repeatable
The short version
- One issue per report. Combined reports get fixed in part, or not at all.
- Title the symptom, not your guess at the cause.
- Record app version, device, and Android version. Those three remove most round trips.
- Number the steps from a known starting state, then separate expected from actual.
- State frequency honestly: always, sometimes with counts, or once.
- No template is a Google Play requirement, and none guarantees production access.
What makes a bug report reproducible
A report is reproducible when a different person, on a comparable setup, can make the same thing happen by following the text. That is the whole test. It does not require a perfect explanation of the cause.
- A known starting state: a specific account type, screen, and content. If the bug needs a fresh install, say so.
- Exact steps in order, with the input used — the code entered, the file size, the text typed.
- An observable symptom. “The progress bar stops at 100% with no error” is observable. “It fails” is an interpretation.
- The environment: app version, device, Android version, and any condition that plausibly changes behaviour.
- Frequency, because “sometimes” and “always” are different investigations.
Essential information to collect
| Field | Why it matters | Example |
|---|---|---|
| App version and build | Many reports describe a build already replaced. | 2.4.1 (versionCode 214) |
| Device manufacturer and model | Firmware, power management, and hardware vary. | Pixel 7a, Galaxy A54 |
| Android version and API level | Permission and background rules change by version. | Android 15 (API 35) |
| Preconditions | A state-dependent bug looks random without them. | Signed in, one item in cart |
| Expected result | The contract the app failed to meet. | “The total drops and shows a discount line.” |
| Actual result | The observable failure, including any message. | “Total unchanged, no message.” |
| Frequency | Separates a consistent defect from an intermittent one. | Always (5 of 5 attempts) |
| Impact | Drives severity and says who is affected. | Blocks checkout for every user |
A Logcat excerpt or a full device bug report is optional and usually requested by the developer; the next sections explain when each one earns its place.
Add network state, permission results, locale, or font size only when they plausibly changed what the tester saw.
A copy-and-paste Android bug report template
Copy the block into a form, an issue tracker, or a shared document. Adapt the optional section to your app, and delete fields that do not apply rather than guessing at them.
Bug title: App version / build: Device manufacturer and model: Android version (and API level, if shown): Date and time (with time zone): Preconditions / starting state: Steps to reproduce: 1. 2. 3. Expected result: Actual result: Frequency (always / sometimes / once, with counts): Impact (who is affected and what they cannot do): Attachments (screenshot / recording / logs): Reporter and contact: Additional notes: Optional - include only what you verified: Account type or plan: Network state (Wi-Fi / mobile data / offline): Permissions granted or denied: Battery saver or background restrictions: Locale, font size, display size: Accessibility services enabled:
Write expected and actual from the user's point of view, not the code's. Anything you did not observe belongs in Additional notes marked “unverified”, so a reader can tell a fact from a theory.
Weak report versus useful report
Both examples are illustrative, written for this guide. They are not customer incidents and they do not describe measured results.
Example 1 — a reproducible functional bug
Weak version: “Discount code is broken. Please fix.”
Useful version:
Bug title: Checkout total does not update after a valid discount code App version / build: 2.4.1 (versionCode 214) Device: Google Pixel 7a Android version: Android 15 (API 35) Preconditions: Signed in; one item in the cart; no prior discount Steps to reproduce: 1. Open the cart with one item. 2. Tap "Apply code" and enter SAVE10. 3. Tap "Apply". 4. Wait for the confirmation toast, then view the cart summary. Expected result: A discount line appears and the total drops by the advertised amount. Actual result: The toast confirms the code and the discount line appears, but the total is unchanged. Removing and re-adding the item corrects it. Frequency: Always, 5 of 5 attempts. Impact: Every discounted order shows the wrong total at checkout. Attachments: 11-second recording of steps 2 to 4. Additional notes: Support believes payment charges the discounted amount. Unverified.
Why it works: the steps start from a state anyone can rebuild, the input is exact, and the results describe the screen rather than a theory.
Example 2 — an intermittent, device-specific issue
Bug title: App closes when switching from Wi-Fi to mobile data App version / build: 2.4.1 (versionCode 214) Device: Samsung Galaxy A54 5G (SM-A546B) Android version: Android 14 (API 34), One UI build Preconditions: Signed in; an episode playing in the background Steps to reproduce: 1. Start playback over Wi-Fi. 2. Send the app to the background for 30 seconds. 3. Turn Wi-Fi off so the device switches to mobile data. 4. Return to the app. Expected result: Playback continues, or a buffering state appears. Actual result: The app closes with no error message. On reopening, playback restarts from the beginning. Frequency: 3 of 9 attempts. Two failures had the screen locked; all three followed a network handover. Impact: Listeners lose their position; reach not yet known. Additional notes: Hypothesis, unverified - a background-thread callback. No stack trace yet.
Why it works: it gives the exact device build, the attempt count, and the conditions that coincided with each failure — and labels a hypothesis instead of presenting it as a diagnosis.
How to write precise reproduction steps
- Start from a state you can rebuild: “fresh install”, “signed in as a free account”, “cart contains one item”.
- One action per line. Merged actions hide the step that breaks.
- Use the visible label: tap “Apply”, not “confirm the change”.
- Include the exact input: the code entered, the file size, the quantity.
- Keep interpretation out. “The app freezes” belongs in Actual result, not in step 4.
If a flow is long, check whether the report is really about one screen. A direct-navigation precondition — a deep link, a saved state — often turns ten steps into three.
Severity versus priority
Severity describes how much the defect damages the product. Priority describes the order in which the team will work on it. They can point in opposite directions: a crash on a screen nobody reaches is severe but low priority; a wrong price label is minor but urgent.
| Situation | Severity | Priority | Why |
|---|---|---|---|
| Checkout fails for every user | High | Immediate | Blocks revenue and the core task. |
| Wrong price on the main product page | Medium | Immediate | Affects money and trust without a crash. |
| Crash in an unreachable internal screen | High | Low | A real defect with no user exposure. |
| Label wraps at 130% font size | Low | Medium | Cosmetic, but visible to accessibility users. |
| Session expires silently after 30 minutes | Medium | High | Recoverable, but it interrupts work repeatedly. |
Testers usually judge severity best, because they see the impact. Priority needs release context, so a developer or product owner sets it. If your team does not separate the two, use one impact field and describe who is affected.
What to do when a bug is intermittent
“Could not reproduce” is a result, not a failure — as long as the attempt is recorded.
- Record attempts as a ratio. “3 of 9 attempts” says more than “sometimes”.
- Note what differed on failures: screen locked, low battery, background data, another app in front.
- Capture the moment, not the memory. A screenshot taken immediately beats a description written an hour later.
- Ask for the smallest extra evidence that exists — a crash timestamp, an error code, a recording. Logs only if the team explains how to collect them.
- Do not close it without a retest plan. State what would change the conclusion.
This is where symptom and cause separate most sharply. Android's bug-report documentation notes that the main-thread stack in an ANR trace shows only what that thread was doing at that moment, and may not be the real cause. A report that presents a stack frame as the reason can send a fix the wrong way.
When screenshots, recordings, Logcat, or a full bug report help
These are different tools with different costs. None is mandatory for every report.
| Evidence | Best for | Limitation |
|---|---|---|
| Screenshot | Layout, wording, wrong values, missing elements. | No timing, sequence, or anything off-screen. |
| Short screen recording | Sequences, gestures, the timing of a failure. | May capture personal data; rarely proves cause alone. |
| Logcat excerpt | Exceptions, crash traces, SDK errors near a known time. | Needs a capture tool; noisy without a time window. |
| Device bug report | ANRs, deadlocks, dumpsys output, device logs. | Needs Developer options or adb; large, full of personal data. |
| Play Console crash and ANR data | What real users hit, including stack traces. | Aggregated, delayed, and without a reproduction path. |
Android Studio's bug-reporting guidance asks for exact steps, the expected and observed outcome, a descriptive title, and — for Studio issues — a diagnostic bundle. That shows proportion: Google asks for a bundle for Studio bugs, not a system dump from every tester of your app.
A full device bug report is a developer task. It needs Developer options, or adb bugreport from a machine with the platform tools. The archive holds dumpsys, dumpstate, and logcat output — right for an ANR or framework failure, overkill for a mislabelled button.
Privacy and security: redact before you share
Diagnostic evidence is user data. A logcat capture, recording, or device bug report can contain email addresses, phone numbers, message contents, account identifiers, and session tokens.
- Never ask for passwords, OTPs, or access tokens. Issue a dedicated test account if a flow needs credentials.
- Redact before uploading: names, emails, card digits, and anything not needed to reproduce the issue.
- Check the whole screenshot, including the notification shade and status bar.
- Do not post bug-report archives, or links to them, publicly. Share them privately.
- Keep retention short, and delete attachments when the issue closes.
- Plan deobfuscation. For a minified build, traces are readable only with the matching mapping file.
A report can be perfectly reproducible and still be unsafe to circulate. Check both.
How developers review, reproduce, prioritise, and retest
- Triage on arrival. Confirm it is one issue, check for duplicates, set severity from impact.
- Reproduce on the reported build first. A newer build proves the bug existed, not that it still does.
- Reply with what you tried, naming the device and build so the tester can narrow the difference.
- Confirm the cause before fixing. A plausible cause and a confirmed one need different amounts of rework.
- Ship to the same track and ask the original reporter to retest. Confirmation by another tester on another device is weaker evidence.
- Record the outcome: version, date, reporter, result.
A practical checklist for a closed-testing team
- ☐ One reporting channel, agreed before day one, with a link testers can find.
- ☐ Testers know the current version code and where to find it.
- ☐ The template sits where testers work: a pinned message, a form, or a shared doc.
- ☐ Demo accounts exist so nobody shares real credentials.
- ☐ A named person triages daily and replies, even to say “cannot reproduce”.
- ☐ Every fix has a retest owner, and attachments have a deletion date.
The 14-day closed-testing checklist covers the rest of the cycle. For crash and ANR data, see Android Vitals explained. For a wider device and OS spread, the compatibility testing guide explains how to build one.
Frequently asked questions
Does Google Play require a specific bug-report format?
No. Play requires closed testing and a summary of the feedback you received; it does not prescribe fields, a template, or a tool.
Do testers need to enable Developer options?
Not by default. Only a full device bug report needs Developer options or adb. Most closed-test reports work with a description, a screenshot, and a version number.
Should testers include a suspected root cause?
Only when it is labelled as a hypothesis. An unlabelled guess in the title or the actual-result field makes a report look more certain than it is.
Can a recording replace logs?
Sometimes, when the symptom is visual and repeatable. A recording cannot show a stack trace, so for crashes and ANRs the log or crash report is better evidence.
Official sources
- Android Developers — Report a bug — steps, expected versus observed outcome, titles, diagnostic attachments.
- Android Developers — Capture and read bug reports — capture methods and archive contents.
- Android Developers — Logcat — buffers, priorities, filtering.
- Android Open Source Project — Read bug reports — log structure, ANR traces, and the limits of a stack at failure time.
The report is the unit of quality
A reproducible report is short, literal, and honest about what is unknown. It separates symptom from hypothesis, expected from actual, and severity from priority. Do that consistently and developers fix instead of asking, while testers get an answer instead of a silent backlog.
If you need real testers for a closed test, 12 Testers Community provides that service. It does not replace a clear reporting process, and no testing service can guarantee production access.