Configuration reference for the Bugsee Android Gradle plugin.
Minimums: AGP 8.6.0, Gradle 8.7, Bugsee Android SDK 7.x. The public docs have the full requirements & compatibility page.
Gradle 9 is supported from plugin 4.0.3.
| Plugin | Gradle 8.x | Gradle 9.x |
|---|---|---|
| 4.0.0 – 4.0.2 | ✅ | ❌ |
| 4.0.3 and newer | ✅ | ✅ |
Plugin 4.0.0 – 4.0.2 call ProjectDependency.getDependencyProject(), which
Gradle 9.0 removed. On Gradle 9, the consumer's build fails during configuration:
A problem occurred configuring project ':app'.
> Failed to notify project evaluation listener.
> 'org.gradle.api.Project org.gradle.api.artifacts.ProjectDependency.getDependencyProject()'
ProjectDependencyCompat fixes this in 4.0.3 by resolving the dependency's
project reflectively (commit 2066da5).
Each combination below was built with plugin 4.0.7 as a minified release
build (R8), checking bytecode instrumentation, BUILD_UUID manifest injection
and the mapping upload. Plugin 4.0.3 – 4.0.6 were also verified on Gradle 9.8.0
with AGP 9.4.1. Verified September 2026.
| Gradle | AGP | Configuration cache | Result |
|---|---|---|---|
| 9.8.0 | 9.4.1 | ✅ | ✅ Also verified on a multi-module app (library module, product flavors, Compose, NDK) |
| 9.7.0 | 9.4.1 | ✅ | ✅ |
| 9.1.0 | 9.0.1 | Not tested | ✅ |
| 9.0.0 | 8.13.2 | ✅ | ✅ |
| 8.14.3 | 8.13.2 | Not tested | ✅ |
Known pitfalls that are not caused by this plugin:
- AGP and Gradle must be compatible with each other. For example, AGP 8.13 fails inside AGP on Gradle 9.7. See Google's AGP–Gradle compatibility table.
- AGP 9 compiles Kotlin itself. Applying
org.jetbrains.kotlin.androidin an AGP 9 module fails withCannot add extension with name 'kotlin', whether or not the Bugsee plugin is applied.
Plugin behavior can be configured from two sources, with the following precedence (highest to lowest):
bugsee { … }DSL in yourbuild.gradle/build.gradle.kts.<rootProject>/bugsee.propertiesfile —plugin.*keys.- Built-in defaults baked into the plugin.
Any value set in the DSL overrides the same value set in
bugsee.properties, and any value in bugsee.properties overrides
the plugin's built-in default. Internally this is implemented via
Gradle's Property.convention(…) semantics — the properties layer is
applied as a convention before your DSL block runs, and your .set(…)
calls in the DSL supersede it.
A single bugsee.properties file at the root project directory
configures both the app token (used by AppTokenResolver) and the
plugin itself. The two surfaces share the file but live under
distinct namespaces:
| Namespace | Owner | Example |
|---|---|---|
| (unprefixed) | App-token resolution | app_token=YOUR_APP_TOKEN |
plugin.* |
Gradle plugin behavior | plugin.debug=true |
The file is optional. Keys not present in the file fall through to the next source (DSL, then defaults).
The DSL is the right surface when configuration is the same for all
builds of an app. bugsee.properties is the right surface when
configuration varies by CI environment without touching the build
script — e.g. enabling debug logging on a per-CI-runner basis,
flipping size-analysis on for release builds only via an env-templated
file, or sharing config across multiple modules in a multi-module
build.
The plugin reads <rootProject>/bugsee.properties — i.e. the
top-level directory of your Gradle build, NOT each sub-project's
directory. In a multi-module build, configuration lives in one place.
The file is registered as a configuration-cache input via
providers.fileContents(...). Editing bugsee.properties invalidates
the CC entry and triggers a re-load on the next build. No manual
--no-configuration-cache flag needed.
Each plugin.<path> key corresponds to a Property<T> on the
plugin's DSL extension tree. Key paths use the same camelCase /
dotted-path form as the DSL field names.
| Key | Type | Default | DSL equivalent |
|---|---|---|---|
plugin.endpoint |
String | https://api.bugsee.com |
bugsee { endpoint.set(…) } |
plugin.debug |
Boolean | false |
bugsee { debug.set(…) } |
plugin.feedback |
Boolean | false |
bugsee { feedback.set(…) } |
plugin.optimizeExtensionsLoading |
Boolean | true |
bugsee { optimizeExtensionsLoading.set(…) } |
| Key | Type | Default |
|---|---|---|
plugin.ndk.enabled |
Boolean | false |
plugin.ndk.forceDebugSymbolsUpload |
Boolean | false |
plugin.ndk.useMergedNativeLibs |
Boolean | true |
With ndk.enabled, native symbols are uploaded from the unstripped libraries
in build/intermediates/merged_native_libs/<variant> (keyed by GNU build-id,
needs bugsee-cli 0.8.0+), so file:line frames no longer depend on
android.defaultConfig.ndk.debugSymbolLevel and the app's AAB does not grow.
Unchanged prebuilt libraries are deduplicated server-side. Set
useMergedNativeLibs to false to use only AGP's native-debug-symbols.zip.
A library that an earlier release uploaded only as SYMBOL_TABLE (function names)
is upgraded to the unstripped copy automatically (bugsee-cli 0.8.1+); the server
never replaces debug info with a poorer file, so no forceDebugSymbolsUpload is needed.
When enabled, the plugin automatically adds the bugsee-android-leak
module dependency (memory/thread leak detection). If the app already
declares the leak module explicitly, this is a no-op — mirroring the
ndk.enabled behaviour.
| Key | Type | Default |
|---|---|---|
plugin.leak.enabled |
Boolean | false |
| Key | Type | Default |
|---|---|---|
plugin.buildInfo.enabled |
Boolean | true |
plugin.buildInfo.allBuildTypes |
Boolean | false |
| Key | Type | Default |
|---|---|---|
plugin.buildInfo.sizeAnalysis.enabled |
Boolean | false |
plugin.buildInfo.sizeAnalysis.buildConfiguration |
String | unset; falls back to the Gradle variant name |
plugin.buildInfo.sizeAnalysis.chunkedUpload |
Boolean | false |
| Key | Type | Default |
|---|---|---|
plugin.buildInfo.sizeCheck.enabled |
Boolean | unset — gate disabled |
plugin.buildInfo.sizeCheck.warningPercent |
Double | unset — threshold disabled |
plugin.buildInfo.sizeCheck.failPercent |
Double | unset — threshold disabled |
plugin.buildInfo.sizeCheck.warningBytes |
Long (bytes) | unset — threshold disabled |
plugin.buildInfo.sizeCheck.failBytes |
Long (bytes) | unset — threshold disabled |
| Key | Type | Default |
|---|---|---|
plugin.buildInfo.dependencies.enabled |
Boolean | true |
plugin.buildInfo.dependencies.scope |
String | runtime |
plugin.buildInfo.dependencies.includeSelectedReason |
Boolean | false |
plugin.buildInfo.dependencies.maxCount |
Int | 5000 |
| Key | Type | Default |
|---|---|---|
plugin.buildInfo.timings.enabled |
Boolean | true |
| Key | Type | Default | Notes |
|---|---|---|---|
plugin.instrumentation.enabled |
Boolean | true |
Global switch |
plugin.instrumentation.okhttp |
Boolean | true |
|
plugin.instrumentation.httpEngine |
Boolean | true |
Cronet |
plugin.instrumentation.log |
Boolean | true |
android.util.Log redirect |
plugin.instrumentation.thread |
Boolean | true |
|
plugin.instrumentation.mainThreadMisuse |
Boolean | true |
|
plugin.instrumentation.operationDispatch |
Boolean | true |
|
plugin.instrumentation.compose |
Boolean | true |
Compose tag injection |
plugin.instrumentation.composeSecure |
Boolean | true |
Compose secure-field auto-detect |
plugin.instrumentation.composeInput |
Boolean | true |
|
plugin.instrumentation.ktor |
Boolean | true |
|
plugin.instrumentation.cronet |
Boolean | true |
|
plugin.instrumentation.startupTier |
Enum (OFF, MINIMAL, STANDARD, DETAILED, FULL) |
STANDARD¹ |
Case-insensitive |
¹ The defaults in this table — including every boolean instrumentation
flag and startupTier — are supplied at resolution time by
InstrumentationConfigResolver, NOT as Property.convention(…) on
the DSL extension. That is the load-bearing detail that makes the
chain bypass below possible: with no convention on the property,
Property.isPresent is false until something (DSL .set(…) OR the
properties applier OR a future binding) populates it. See the chain
note immediately below.
Instrumentation flags have a deeper resolution chain than other options. Boolean instrumentation flags AND
startupTierresolve in this order at task-configuration time:
- DSL
.set(…)inbugsee { instrumentation { … } }plugin.instrumentation.Xinbugsee.properties- Legacy Gradle property
bugsee.instrumentation.X- Manifest
<meta-data android:name="com.bugsee.android.instrumentation.X" />- Built-in default (
truefor booleans;STANDARDfor startupTier)Setting an instrumentation flag in
bugsee.propertiesmakes the underlying DSLProperty"present" (isPresent == true), andInstrumentationConfigResolvershort-circuits at step 1 — soplugin.*BYPASSES the legacy Gradle-property and manifest-meta-data fallbacks for that key. The user's DSL.set(…)still wins over both sources. The simpler "DSL > properties > default" chain documented at the top of this file applies to every NON-instrumentation option.CI gotcha. If your build matrix uses
-Pbugsee.instrumentation.okhttp=false(the legacy Gradle-property form) to disable instrumentation per-job, that flag is silently ignored onceplugin.instrumentation.okhttpis set inbugsee.properties— the bypass kicks in. To keep CI overrides effective:
- Either remove the conflicting
plugin.instrumentation.Xkey frombugsee.propertiesand rely on the legacy-Pchain, OR- Read the
-Pflag into the DSL explicitly, e.g.so the CLI value flows through the highest-priority DSL slot.bugsee { instrumentation { okhttp.set(findProperty("bugsee.instrumentation.okhttp") as? Boolean ?: true) } }
App token — set via the unprefixed key
app_token=…, notplugin.appToken. The DSL provides additional richer forms (closure, provider, per-variant resolver) that have no properties-file equivalent.
| Property type | Accepted forms |
|---|---|
| Boolean | true / false, yes / no, on / off, 1 / 0 (case-insensitive) |
| Int / Long | Standard integer literal |
| Double | Standard decimal literal |
| String | Trimmed; empty string is rejected (warn — see below) |
| Enum | Case-insensitive match against the enum's constant names |
The plugin logs bugsee.properties issues at the most-appropriate
Gradle log level:
| Event | Log level | Why |
|---|---|---|
| File absent | (silent) | Most consumers don't use the file. |
File present, no plugin.* keys |
(silent) | Coexisting with app_token= is the common shape. |
| File malformed | warn |
User error — surface always. |
| Value malformed | warn |
User error; the key + bad value are named. |
Empty string value (plugin.endpoint=) |
warn |
Likely a half-edited line; default holds. |
Unknown plugin.* key |
info |
Forward-compat — --info to surface typos. |
| Successful apply | warn, only if plugin.debug=true |
Echoes each applied key/value when verbose mode is on. |
# bugsee.properties at the root project
# App token (used by AppTokenResolver — not a plugin.* key)
app_token=YOUR_APP_TOKEN_HERE
# Plugin options
plugin.debug=true
plugin.ndk.enabled=true
plugin.buildInfo.sizeAnalysis.enabled=true
plugin.buildInfo.sizeCheck.warningPercent=10.0
plugin.buildInfo.sizeCheck.failPercent=25.0
plugin.instrumentation.startupTier=DETAILED// build.gradle.kts at app module — DSL overrides for this module
bugsee {
// (1) Overrides plugin.endpoint from bugsee.properties (DSL > properties).
endpoint.set("https://api.bugsee-internal.example.com")
// (2) Sets a key that bugsee.properties did NOT touch — the two
// sources are additive; this becomes the effective value.
feedback.set(true)
// (3) Keys NOT mentioned in either source fall back to plugin
// defaults — `ndk.forceDebugSymbolsUpload`, every other
// instrumentation flag, etc. all remain at their built-in
// defaults documented in the tables above.
}Effective config for the example above:
| Key | Effective value | From |
|---|---|---|
endpoint |
https://api.bugsee-internal.example.com |
DSL (overrides properties) |
feedback |
true |
DSL (additive — no properties value) |
debug |
true |
bugsee.properties |
ndk.enabled |
true |
bugsee.properties |
ndk.forceDebugSymbolsUpload |
false |
built-in default |
buildInfo.sizeAnalysis.enabled |
true |
bugsee.properties |
buildInfo.sizeCheck.warningPercent |
10.0 |
bugsee.properties |
instrumentation.startupTier |
DETAILED |
bugsee.properties |
instrumentation.okhttp (and others) |
true |
downstream resolver default |
For the full set of DSL options, see KDocs on BugseePluginExtension
and the sub-extension classes (BugseeNdkExtension,
BugseeBuildInfoExtension, BugseeInstrumentationExtension, etc.).