From f59e3e0dd5d90191491c57acad0f427add554433 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 9 Sep 2026 15:27:54 +0200 Subject: [PATCH 1/6] docs(android): add Compose effect guidance Add Compose-specific guidance about emitting custom telemetry from Effect APIs and other post-composition callbacks instead of from composable bodies. Cross-link the Android custom instrumentation page back to the Compose page so manual instrumentation guidance points readers to this recomposition caveat. --- .../integrations/jetpack-compose/index.mdx | 36 +++++++++++++++++++ .../custom-instrumentation.mdx | 8 +++++ 2 files changed, 44 insertions(+) diff --git a/docs/platforms/android/integrations/jetpack-compose/index.mdx b/docs/platforms/android/integrations/jetpack-compose/index.mdx index 1c1111f5ceb131..ecad7963bbf0ea 100644 --- a/docs/platforms/android/integrations/jetpack-compose/index.mdx +++ b/docs/platforms/android/integrations/jetpack-compose/index.mdx @@ -356,3 +356,39 @@ SentryAndroid.init(this) { options -> }) } ``` + +## Custom Telemetry in Compose + +Composable functions can run many times during recomposition. Don't emit custom Sentry spans, messages, +breadcrumbs, or other telemetry directly from a composable body, as it can duplicate telemetry or attach it +to the wrong UI lifecycle moment. + +Prefer emitting telemetry from: + +- `LaunchedEffect`, `DisposableEffect`, or `SideEffect` (more info in [Google's developer docs](https://developer.android.com/develop/ui/compose/side-effects)) +- Event callbacks such as `onClick` when the telemetry corresponds to a user action +- APIs that run after composition, such as draw-time or layout-time lambdas, when that timing is what you want to measure + +For example, avoid capturing a message directly from the body: + +```kotlin +@Composable +fun LoginScreen() { + Sentry.captureMessage("Login screen shown") + // ... +} +``` + +Instead, capture state in the body as needed but emit it from an Effect API: + +```kotlin +@Composable +fun LoginScreen() { + val firstComposedAt = remember { Instant.now() } + + LaunchedEffect(Unit) { + Sentry.captureMessage("Login screen shown: $firstComposedAt") + } + // ... +} +``` diff --git a/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx b/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx index 012ea3c96b054e..af7b45d7de53d6 100644 --- a/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx +++ b/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx @@ -14,6 +14,14 @@ To capture transactions and spans customized to your organization's needs, you m + + +If you emit custom Sentry spans or other telemetry from Jetpack Compose code, use Compose Effect APIs such as +`LaunchedEffect`, `DisposableEffect`, or `SideEffect` instead of emitting from a composable body. Composable bodies +can run repeatedly during recomposition. See Jetpack Compose. + + + From 563d61b6291483b289cea46b67e0230ae07bd64a Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Sat, 12 Sep 2026 07:02:06 +0200 Subject: [PATCH 2/6] Update docs/platforms/android/integrations/jetpack-compose/index.mdx Co-authored-by: Alex Krawiec --- docs/platforms/android/integrations/jetpack-compose/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/integrations/jetpack-compose/index.mdx b/docs/platforms/android/integrations/jetpack-compose/index.mdx index ecad7963bbf0ea..f5d1816b788d40 100644 --- a/docs/platforms/android/integrations/jetpack-compose/index.mdx +++ b/docs/platforms/android/integrations/jetpack-compose/index.mdx @@ -359,7 +359,7 @@ SentryAndroid.init(this) { options -> ## Custom Telemetry in Compose -Composable functions can run many times during recomposition. Don't emit custom Sentry spans, messages, +Composable functions can run many times during recomposition. Don't send custom Sentry spans, messages, breadcrumbs, or other telemetry directly from a composable body, as it can duplicate telemetry or attach it to the wrong UI lifecycle moment. From 2260ad82b41844d9c83eb1e290cad7de7e8e36df Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Sat, 12 Sep 2026 07:02:14 +0200 Subject: [PATCH 3/6] Update docs/platforms/android/integrations/jetpack-compose/index.mdx Co-authored-by: Alex Krawiec --- docs/platforms/android/integrations/jetpack-compose/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/integrations/jetpack-compose/index.mdx b/docs/platforms/android/integrations/jetpack-compose/index.mdx index f5d1816b788d40..3081d10d5d3ee5 100644 --- a/docs/platforms/android/integrations/jetpack-compose/index.mdx +++ b/docs/platforms/android/integrations/jetpack-compose/index.mdx @@ -363,7 +363,7 @@ Composable functions can run many times during recomposition. Don't send custom breadcrumbs, or other telemetry directly from a composable body, as it can duplicate telemetry or attach it to the wrong UI lifecycle moment. -Prefer emitting telemetry from: +Instead, send telemetry from: - `LaunchedEffect`, `DisposableEffect`, or `SideEffect` (more info in [Google's developer docs](https://developer.android.com/develop/ui/compose/side-effects)) - Event callbacks such as `onClick` when the telemetry corresponds to a user action From a04a69ea11dde26cc6f6d821a988cb4d22cb6c9c Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Sat, 12 Sep 2026 07:02:27 +0200 Subject: [PATCH 4/6] Update docs/platforms/android/integrations/jetpack-compose/index.mdx Co-authored-by: Alex Krawiec --- docs/platforms/android/integrations/jetpack-compose/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/integrations/jetpack-compose/index.mdx b/docs/platforms/android/integrations/jetpack-compose/index.mdx index 3081d10d5d3ee5..2aa348b379e881 100644 --- a/docs/platforms/android/integrations/jetpack-compose/index.mdx +++ b/docs/platforms/android/integrations/jetpack-compose/index.mdx @@ -379,7 +379,7 @@ fun LoginScreen() { } ``` -Instead, capture state in the body as needed but emit it from an Effect API: +Instead, capture state in the body as needed but send it from an Effect API: ```kotlin @Composable From 53138b42cc1a1ad1f36117137ec92fad72651486 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Sat, 12 Sep 2026 07:02:35 +0200 Subject: [PATCH 5/6] Update docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx Co-authored-by: Alex Krawiec --- .../android/tracing/instrumentation/custom-instrumentation.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx b/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx index af7b45d7de53d6..d04cb216acd7bc 100644 --- a/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx +++ b/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx @@ -16,7 +16,7 @@ To capture transactions and spans customized to your organization's needs, you m -If you emit custom Sentry spans or other telemetry from Jetpack Compose code, use Compose Effect APIs such as +If you send custom Sentry spans or other telemetry from Jetpack Compose code, use Compose Effect APIs such as `LaunchedEffect`, `DisposableEffect`, or `SideEffect` instead of emitting from a composable body. Composable bodies can run repeatedly during recomposition. See Jetpack Compose. From fc54b0252ed908c669b1de8a9ac93a45047f1689 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Sat, 12 Sep 2026 07:02:43 +0200 Subject: [PATCH 6/6] Update docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx Co-authored-by: Alex Krawiec --- .../android/tracing/instrumentation/custom-instrumentation.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx b/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx index d04cb216acd7bc..57bc14ec9bfdc8 100644 --- a/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx +++ b/docs/platforms/android/tracing/instrumentation/custom-instrumentation.mdx @@ -17,7 +17,7 @@ To capture transactions and spans customized to your organization's needs, you m If you send custom Sentry spans or other telemetry from Jetpack Compose code, use Compose Effect APIs such as -`LaunchedEffect`, `DisposableEffect`, or `SideEffect` instead of emitting from a composable body. Composable bodies +`LaunchedEffect`, `DisposableEffect`, or `SideEffect` instead of sending from a composable body. Composable bodies can run repeatedly during recomposition. See Jetpack Compose.