Bug reporting
This page documents the Bugsee Android SDK 7.0.0. For the previous major version, see the 6.x documentation.
Bug reports cover something that is wrong but did not crash the app. Your users can raise one with a gesture, or you can open the report dialog — or submit a report silently — from your own code. (Crashes and handled errors are covered separately, in Crash & error reporting.)
Built-in report triggers
The SDK can surface the report dialog through two user-facing gestures. Both are controlled by manifest options (or programmatic overrides at Bugsee.launch(...) time):
| Option | Manifest key | Default |
|---|---|---|
ReportingTriggerByShake | com.bugsee.option.reporting.triggers.shake | true |
ReportingTriggerByScreenshot | com.bugsee.option.reporting.triggers.screenshot | false |
ReportingTriggerByNotification | com.bugsee.option.reporting.triggers.notification-bar | true |
ReportingTriggerByBroadcast | com.bugsee.option.reporting.triggers.broadcast | false |
Disable the shake trigger in AndroidManifest.xml:
<meta-data
android:name="com.bugsee.option.reporting.triggers.shake"
android:value="false" />
Or override at launch time:
- Java
- Kotlin
Map<String, Serializable> options = new HashMap<>();
options.put(Options.ReportingTriggerByShake, false);
options.put(Options.ReportingTriggerByScreenshot, true);
Bugsee.launch(application, "<your-app-token>", options);
val options = HashMap<String, java.io.Serializable>()
options[Options.ReportingTriggerByShake] = false
options[Options.ReportingTriggerByScreenshot] = true
Bugsee.launch(application, "<your-app-token>", options)
Show the report dialog
Bugsee.showReportDialog(...) opens the standard reporting UI. The user can edit any pre-filled values before submitting.
static void showReportDialog();
static void showReportDialog(String summary, String description);
static void showReportDialog(String summary, String description, IssueSeverity severity);
static void showReportDialog(String summary, String description, IssueSeverity severity, ArrayList<String> labels);
- Java
- Kotlin
Bugsee.showReportDialog();
// Pre-fill summary and description; user can still edit them.
Bugsee.showReportDialog("Checkout is frozen", "The spinner never stops.");
// Pre-fill everything including severity.
Bugsee.showReportDialog(
"Checkout is frozen",
"The spinner never stops.",
IssueSeverity.Blocker);
Bugsee.showReportDialog()
// Pre-fill summary and description; user can still edit them.
Bugsee.showReportDialog("Checkout is frozen", "The spinner never stops.")
// Pre-fill everything including severity.
Bugsee.showReportDialog(
"Checkout is frozen",
"The spinner never stops.",
IssueSeverity.Blocker)
There is no severity-only overload. To set severity without pre-filling the text fields, pass null for both summary and description.
Silent upload
Bugsee.upload(...) submits a report without showing any UI. Use this when you already collected the details in your own UI.
static void upload(String summary, String description);
static void upload(String summary, String description, IssueSeverity severity);
static void upload(String summary, String description, IssueSeverity severity, List<String> labels);
static void upload(Report report);
static void upload(Report report, Callback1<Boolean> callback);
- Java
- Kotlin
Bugsee.upload("Checkout frozen", "Spinner never stops", IssueSeverity.High);
ArrayList<String> labels = new ArrayList<>();
labels.add("checkout");
Bugsee.upload("Checkout frozen", "Spinner never stops", IssueSeverity.High, labels);
Bugsee.upload("Checkout frozen", "Spinner never stops", IssueSeverity.High)
val labels = arrayListOf("checkout")
Bugsee.upload("Checkout frozen", "Spinner never stops", IssueSeverity.High, labels)
Do not call upload(...) from automated error paths. For programmatic exception reporting use Bugsee.logException(...) — this keeps traces grouped and rate-limited correctly.
Default severities
Crash, error, and bug reports get a default severity unless one is specified or set from a ReportHandler. Override via manifest:
| Option | Manifest key | Default |
|---|---|---|
ReportingDefaultCrashPriority | com.bugsee.option.reporting.defaults.crash-priority | IssueSeverity.Blocker |
ReportingDefaultErrorPriority | com.bugsee.option.reporting.defaults.error-priority | IssueSeverity.High |
ReportingDefaultBugPriority | com.bugsee.option.reporting.defaults.bug-priority | IssueSeverity.High |
Customize reports with ReportHandler
ReportHandler is the idiomatic way to inspect or rewrite reports before they are uploaded. It runs for every outgoing report — crashes and errors included, not just bug reports.
Two callbacks are provided as default methods on the interface:
onBeforeReportCreated(Report, boolean isTerminating, Runnable completionCallback)— runs before the report payload is assembled.onAfterReportCreated(Report, boolean isTerminating, Runnable completionCallback)— runs after assembly, ideal for attachments.
You must invoke completionCallback.run() for the pipeline to proceed — unless isTerminating is true, in which case the pipeline continues regardless (the process is about to exit).
- Java
- Kotlin
Bugsee.setReportHandler(new ReportHandler() {
@Override
public void onBeforeReportCreated(Report report, boolean isTerminating, Runnable completionCallback) {
report.setSummary("[" + BuildConfig.FLAVOR + "] " + report.getSummary());
report.setSeverity(IssueSeverity.High);
completionCallback.run();
}
@Override
public void onAfterReportCreated(Report report, boolean isTerminating, Runnable completionCallback) {
Attachment attachment = report.createAndAddAttachment("config")
.setName("config")
.setFileName("config.json")
.setMimeType("application/json");
try (OutputStream out = attachment.openStream()) {
if (out != null) {
out.write(loadConfigSnapshot());
}
} catch (IOException ignored) {
}
completionCallback.run();
}
});
Bugsee.setReportHandler(object : ReportHandler {
override fun onBeforeReportCreated(report: Report, isTerminating: Boolean, completionCallback: Runnable) {
report.summary = "[${BuildConfig.FLAVOR}] ${report.summary}"
report.severity = IssueSeverity.High
completionCallback.run()
}
override fun onAfterReportCreated(report: Report, isTerminating: Boolean, completionCallback: Runnable) {
report.createAndAddAttachment("config")
.setName("config")
.setFileName("config.json")
.setMimeType("application/json")
.openStream()?.use { it.write(loadConfigSnapshot()) }
completionCallback.run()
}
})
Attachments
Add attachments from onAfterReportCreated. Report.createAndAddAttachment(name) returns a mutable Attachment that you populate with fluent setters and write to via its output stream:
Attachment setName(String)— display name shown in the dashboard.Attachment setFileName(String)— file name (with extension) used for the download.Attachment setMimeType(String)— MIME type (e.g."application/json").OutputStream openStream()— opens the (truncating) stream to write the attachment bytes; may returnnullif the attachment cannot be opened. The caller owns closing the stream and should buffer writes.
The setters return the same Attachment, so they can be chained. Reports allow up to 3 attachments × 3 MB; enforce it inside your own handler if relevant.
Callback timeout
The SDK waits at most ReportHandlerCallbackTimeout seconds (default 30) for completionCallback to fire. Tune via manifest:
<meta-data
android:name="com.bugsee.option.config.report-handler-callback-timeout"
android:value="10" />
Programmatic report creation
When you need to build a report, customize it, and upload it on your own schedule (instead of letting showReportDialog(...) / upload(summary, ...) do it in one shot), use Bugsee.createReport(...) to obtain a Report object, mutate it, then hand it to Bugsee.upload(report).
static void createReport(ReportCreationListener listener);
ReportCreationListener has a single callback, onCreated(Report report), invoked on the main thread with the created report — or null if creation failed (for example, the SDK is not launched). The report carries a screenshot (when available) and can be used to request a video export.
The Report you receive is mutable. The most commonly used members:
setSummary(String)/setDescription(String)— the report's title and body text.setSeverity(IssueSeverity)— one ofVeryLow,Medium,High,Critical,Blocker.addLabel(String)/addLabels(List<String>)/setLabels(List<String>)/clearLabels()— dashboard labels.getAttachments()returns the currentList<Attachment>;createAndAddAttachment(name)adds a new one (see Attachments above).
The same Report is what ReportHandler.onBeforeReportCreated(...) / onAfterReportCreated(...) hands you, so the same mutators apply there.
- Java
- Kotlin
Bugsee.createReport(report -> {
if (report == null) {
return; // SDK not launched, or creation failed
}
report.setSummary("Checkout frozen");
report.setSeverity(IssueSeverity.High);
report.addLabel("checkout");
Bugsee.upload(report);
});
Bugsee.createReport { report ->
report ?: return@createReport // SDK not launched, or creation failed
report.summary = "Checkout frozen"
report.severity = IssueSeverity.High
report.addLabel("checkout")
Bugsee.upload(report)
}
Severity values
IssueSeverity values: VeryLow, Medium, High, Critical, Blocker. See the configuration reference — Enums for each value's meaning.