Skip to main content

Android

This guide shows you how to easily integrate the Coralogix RUM SDK into your native Android apps.

Coralogix Android SDK supports Android 7.0+ (API level 24) and above.

Features

In addition to capturing errors, including ANRs, this SDK can intercept network calls, send log messages with customized severity levels, report errors, and track your customers' page transitions.

Installation

Add the Maven Central Repository dependency to your module's build.gradle:

dependencies {
implementation "com.coralogix:android-sdk:2.21.0"
}

The SDK pulls in androidx.work transitively — you do not need to declare it yourself.

Note

If you use on-demand WorkManager initialization and remove the default androidx.startup provider, the automatic flush-on-background backstop job is skipped. The immediate flush still runs on backgrounding and nothing else is affected.

Note

If you encounter a dependency that requires Java 8+ APIs, see Troubleshooting for next steps.

Initialization

Call CoralogixRum.initialize() once in your Application.onCreate() method. Calling it a second time is a no-op.

import com.coralogix.android.sdk.CoralogixRum
import com.coralogix.android.sdk.model.CoralogixDomain
import com.coralogix.android.sdk.model.CoralogixOptions

class MyApp : Application() {
override fun onCreate() {
super.onCreate()

val options = CoralogixOptions(
applicationName = "MyApp",
coralogixDomain = CoralogixDomain.EU2,
publicKey = "<YOUR_PUBLIC_KEY>",
environment = "production",
version = BuildConfig.VERSION_NAME
)

CoralogixRum.initialize(this, options)
}
}

Check whether the SDK initialized successfully:

if (CoralogixRum.isInitialized()) {
Log.d("TAG", "Coralogix SDK is initialized.")
}

Refer to the following fields for CoralogixOptions.

PropertyTypeDescriptionRequiredExample
applicationNameStringName of the applicationYes"MyApp"
coralogixDomainCoralogixDomainThe region associated with your Coralogix domainYesEU1, EU2, US1, US2, US3, AP1, AP2, AP3
publicKeyStringCoralogix token, publicly visible public_key valueYes"my_public_key"
labelsMap<String,String>An optional set of labels that are added to every span for enrichment purposesNolabels = mapOf("payment" to "visa")
environmentStringSpecify the environment, such as development, staging, or productionYes"production"
versionStringVersion of the applicationNo"v.1.0"
userContextUserContextUser context information, such as user ID, name, email, and additional metadataNoUserContext(userId = "123", username = "User", email = "[email protected]", metadata = mapOf("role" to "Admin"))
viewContextViewContextDescription of current activityNo"MyActivityName"
instrumentationsMap<Instrumentation, Boolean>Map to turn on/off specific instrumentation. Defaults to all true.Noinstrumentations = mapOf( Instrumentation.Network to false)
ignoreUrlsList<String>A list of URLs to ignore for logging and monitoring purposes. Supports strings and regular expressions for matching.NoignoreUrls = listOf("https://jsonplaceholder\\.typicode\\.com/.*", ".*\\.svg", ".*\\.ico")
ignoreErrorsList<String>List of error patterns to be ignored for logging and monitoring. Supports strings and regular expressions for matching.NoignoreErrors = listOf("^IllegalArgumentException$", "IOException", "ANR")
collectIPDataBooleanAllow the option to send IP address to identify session country. Defaults to true.Notrue
sessionSampleRateNumberPercentage of overall sessions being tracked. Defaults to 100%.No100%
traceParentInHeaderTraceParentInHeaderConfigControls W3C traceparent header injection in network requests across service boundaries.NoTraceParentInHeaderConfig()
fpsSamplingSecondsNumberInterval (in seconds) for collecting and logging frame rate data for performance tracking. Defaults to 300 sec.No10
beforeSend(EditableCxRum) -> EditableCxRum?Intercepts and modifies each event before sending. Return null to discard the event.NobeforeSend = { event -> if (event.userContext?.email?.endsWith("@example.com", ignoreCase = true) == true) { event.copy(userContext = event.userContext?.copy(email = "redacted")) } else { event } }
beforeSendCallback(List<Map<String, Any?>>) -> UnitCallback for hybrid frameworks (React Native, Flutter). No-op on native Android.NobeforeSendCallback = { events -> /* forward to host */ }
tracesExporter(CoralogixTraceExporterData) -> UnitOptional callback that receives the raw OTLP span payload alongside the standard RUM export, enabling distributed-tracing integration. See Trace Exporter.NotracesExporter = { data -> /* forward OTLP payload */ }
excludeFromSamplingList<ExcludableInstrumentation>Instrumentation categories always exported at 100% regardless of sessionSampleRate. See Decoupling session sampling.NolistOf(ExcludableInstrumentation.Errors)
userInteractionOptionsUserInteractionOptionsConfiguration for user-interaction instrumentation.NoUserInteractionOptions()
debugBooleanEnables verbose SDK logging. Defaults to false.Notrue
proxyUrlString?Optional proxy endpoint for data routing. The ingestion URL is appended as a cxforward query parameter.No"https://your.proxy.com/"

Configuration

Instrumentation

Enable or disable instrumentation modules using the instrumentations map. All modules are enabled by default.

instrumentations = mapOf(
Instrumentation.Network to false // disables network instrumentation
)
ModuleConstantDescription
ErrorInstrumentation.ErrorCaptures handled and unhandled exceptions.
NetworkInstrumentation.NetworkReports network requests and responses.
CustomInstrumentation.CustomAllows sending custom logs and events.
MobileVitalsInstrumentation.MobileVitalsTracks CPU, memory, FPS, cold start, and warm start.
AnrInstrumentation.AnrDetects Application Not Responding (ANR) events.
UserInteractionInstrumentation.UserInteractionAutomatically tracks taps, scrolls, and swipes.
LifecycleInstrumentation.LifecycleCaptures app and fragment lifecycle events.
NavigationInstrumentation.NavigationReports navigation events between screens.

Mobile Vitals

Set which Mobile Vitals detectors to run. All detectors are enabled by default.

val config = CoralogixOptions(
// ...
mobileVitalsOptions = mapOf(
MobileVitalType.CpuUsage to true,
MobileVitalType.MemoryUsage to false // disables memory detector
)
)
DetectorDescription
MobileVitalType.CpuUsageCPU utilization and main-thread time.
MobileVitalType.MemoryUsageMemory footprint and utilization.
MobileVitalType.FpsFrame rate (FPS).
MobileVitalType.ColdStartTimeApp cold start duration.
MobileVitalType.WarmStartTimeApp warm start duration.
MobileVitalType.SlowFrozenFramesSlow and frozen frame counts.

Learn more in Mobile Vitals.

Decoupling session sampling

By default, sessionSampleRate is an all-or-nothing gate: when a session is sampled out, the entire SDK shuts down and nothing is sent. Use excludeFromSampling to keep specific instrumentation categories flowing even when a session is sampled out.

This is useful when you want a low sample rate to reduce data volume but still need every error or custom log to reach Coralogix.

val options = CoralogixOptions(
// ...
sessionSampleRate = 10,
excludeFromSampling = listOf(
ExcludableInstrumentation.Logs,
ExcludableInstrumentation.Errors
)
)
ValueExported event type
Errorserror
Logslog
Networknetwork-request
UserInteractionsuser-interaction
MobileVitalsmobile-vitals
CustomSpancustom-span
CustomMeasurementcustom-measurement
Navigationnavigation
Lifecyclelife-cycle

Inside a beforeSend hook, EditableCxRum.isSessionSampledIn tells you whether the event came from a sampled-in session or was sent only because its category appears in excludeFromSampling. Use this to filter excluded categories further — for example, keep only ANR errors from sampled-out sessions:

beforeSend = { event ->
val isError = event.errorContext != null
when {
!isError -> event
event.isSessionSampledIn == true -> event
event.errorContext?.type == "ANR" -> event
else -> null
}
}

Ignoring errors and URLs

  • Ignore errors: Use ignoreErrors to exclude errors matching specific patterns. Supports strings and regular expressions.
ignoreErrors = listOf(
"^IllegalArgumentException$",
"IOException",
"ANR"
)
  • Ignore URLs: Use ignoreUrls to exclude URLs matching specific patterns from network tracing.
ignoreUrls = listOf(
"https://jsonplaceholder\\.typicode\\.com/.*",
".*\\.svg",
".*\\.ico"
)

Network interception

To enable RUM to intercept network events, add CoralogixOkHttpInterceptor to your network client.

OkHttp

val okHttpClient = OkHttpClient.Builder()
.addInterceptor(CoralogixOkHttpInterceptor())
.build()

val request = Request.Builder()
.url("https://api.example.com/data")
.build()

val response = okHttpClient.newCall(request).execute()
println(response.body?.string())

Retrofit

val okHttpClient = OkHttpClient.Builder()
.addInterceptor(CoralogixOkHttpInterceptor())
.build()

val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()

interface ApiService {
@GET("data")
suspend fun getData(): Response<DataModel>
}

val apiService = retrofit.create(ApiService::class.java)
val response = apiService.getData()
println(response.body())

Ktor

Note

Only the OkHttp engine is supported.

val httpClient = HttpClient(OkHttp) {
engine {
preconfigured = OkHttpClient.Builder()
.addInterceptor(CoralogixOkHttpInterceptor())
.build()
}
}

val response = httpClient.get("https://api.example.com/data")
println(response.bodyAsText())

Network capture rules

By default, the SDK captures request URLs, status codes, and timings. Use networkCaptureConfig to also capture specific request and response headers or payloads on a per-URL basis. Rules are evaluated in order — the first match wins.

val config = CoralogixOptions(
// ...
networkCaptureConfig = listOf(
NetworkCaptureRule(
urlPattern = Regex(".*api\\.example\\.com.*"),
reqHeaders = listOf("Accept", "Content-Type"),
resHeaders = listOf("Content-Type", "X-Request-Id"),
collectReqPayload = true,
collectResPayload = false
)
)
)
NetworkCaptureRule fieldTypeDescription
urlString?Exact URL string to match.
urlPatternRegex?Regex pattern matched against the full request URL. Provide url or urlPattern, not both.
reqHeadersList<String>?Request header names to capture (case-insensitive match, captured using your casing).
resHeadersList<String>?Response header names to capture (case-insensitive match, captured using your casing).
collectReqPayloadBooleanCapture the request body. Only text-based payloads ≤ 1024 characters are captured.
collectResPayloadBooleanCapture the response body. Only text-based payloads ≤ 1024 characters are captured.
Note

Payloads exceeding 1024 characters are dropped entirely, not truncated. Only Content-Type values of application/json, text/*, application/javascript, and application/xml are captured.

Warning

Only headers explicitly listed in reqHeaders or resHeaders are captured. Avoid adding security-sensitive headers such as Authorization or Cookie to your capture rules in production.

Trace exporter

Forward span data to your own collector or backend by setting a tracesExporter callback in CoralogixOptions. The callback receives each batch of spans the SDK produces. Spans continue to flow to Coralogix when this callback is set.

val config = CoralogixOptions(
// ...
tracesExporter = { data ->
val json = data.toJson() // full OTLP JSON string
val spans = data.resourceSpans // structured List<OtlpResourceSpans>
forwardToCustomCollector(json)
}
)

CoralogixTraceExporterData fields:

FieldTypeDescription
resourceSpansList<OtlpResourceSpans>Structured OTLP resource-spans tree.
spanCountIntTotal number of spans in this batch.

Call toJson() to get the full OTLP JSON encoding ready to POST.

For payload format and forwarding considerations, see Trace exporter.

Modify events with beforeSend

Use beforeSend to inspect, transform, or discard events before they reach Coralogix. Return the modified event to send it, or return null to discard it.

val config = CoralogixOptions(
// ...
beforeSend = { event ->
if (event.userContext?.email?.endsWith("@coralogix.com", ignoreCase = true) == true) {
event.copy(userContext = event.userContext?.copy(email = "redacted"))
} else {
event
}
}
)

The event parameter is an EditableCxRum object that exposes all event fields you can read or copy-and-modify:

data class EditableCxRum(
val eventContext: EventContext?,
val labels: Map<String, Any?>?,
val spanId: String?,
val traceId: String?,
val environment: String?,
val viewContext: ViewContext?,
val errorContext: EditableErrorContext?,
val logContext: LogContext?,
val networkRequestContext: NetworkRequestContext?,
val userContext: UserContext?,
val lifecycleContext: LifecycleContext?,
val customMeasurementContext: CustomMeasurementContext?,
val interactionContext: InteractionContext?,
val isSessionSampledIn: Boolean?
)

interactionContext.isMaskedElement is true when the interaction targeted masked content — use it in beforeSend to drop or redact masked interactions. See Privacy and masking for recipes.

isSessionSampledIn is read-only. It is false when the event reached beforeSend only because its category appears in excludeFromSampling.

Proxy URL

Route data through a proxy endpoint by setting proxyUrl in CoralogixOptions. The SDK appends the Coralogix ingestion URL as a cxforward query parameter:

https://your.proxy.com/?cxforward=ingestion.url.com

Your proxy is responsible for forwarding the data to the Coralogix ingestion endpoint.

Custom spans

Use custom spans to instrument business-critical operations. Spans appear in Coralogix as standalone records or grouped under a parent global span.

What you need

W3C traceparent header injection must be enabled:

val options = CoralogixOptions(
// ...
traceParentInHeader = TraceParentInHeaderConfig(enabled = true)
)

getCustomTracer() returns null and logs a warning if this is not set.

Get the tracer

Acquire a tracer from CoralogixRum. Only one tracer instance is issued per SDK lifecycle — store and reuse the returned instance.

val tracer = CoralogixRum.getCustomTracer() ?: return

Start a global span

A global span is the root of a custom trace. Only one global span can be active at a time.

val globalSpan = tracer.startGlobalSpan(
name = "checkout-flow",
labels = mapOf("cart.item_count" to 3)
) ?: return

startGlobalSpan returns null if a global span is already active. The global span exposes traceId and spanId (W3C hex strings) so you can correlate spans with your own backend.

Always call endSpan() when the operation is complete:

globalSpan.endSpan()

Add child spans

Within a global span's context, create child spans for sub-operations:

val childSpan = globalSpan.startCustomSpan(
name = "payment-step",
labels = mapOf("payment.method" to "credit_card")
)
// ... do work ...
childSpan.endSpan()

Child spans inherit the global span's traceId and set the global span as their parentSpanId.

Set attributes

CoralogixCustomSpan supports four attribute types:

childSpan.setAttribute("http.method", "GET") // String
childSpan.setAttribute("http.status", 200) // Int
childSpan.setAttribute("duration.ms", 3.14) // Double
childSpan.setAttribute("from.cache", true) // Boolean

Add events

Add timestamped events to a span to record notable moments:

childSpan.addEvent("retry-attempted")

childSpan.addEvent(
name = "cache-miss",
attributes = mapOf("key" to "user-profile", "size_bytes" to 1024)
)

childSpan.addEvent(
name = "request-sent",
timestamp = System.currentTimeMillis() - 500,
unit = TimeUnit.MILLISECONDS
)

Supported attribute value types: String, Int, Long, Double, Float, Boolean.

Set span status

childSpan.setStatus(StatusCode.OK)
childSpan.setStatus(StatusCode.ERROR)

Cross-thread context propagation

If you start a child span from a different thread than the global span, use withContext to make the global span the active OTel context on that thread:

globalSpan.withContext {
val childSpan = globalSpan.startCustomSpan("background-task")
// ... do work ...
childSpan.endSpan()
}

Ignored instruments

Pass ignoredInstruments to getCustomTracer() to suppress specific automatic instrumentation while a global span is active:

val tracer = CoralogixRum.getCustomTracer(
ignoredInstruments = setOf(
CoralogixIgnoredInstrument.NETWORK_REQUESTS,
CoralogixIgnoredInstrument.USER_INTERACTIONS,
CoralogixIgnoredInstrument.ERRORS
)
) ?: return
ValueDescription
NETWORK_REQUESTSSuppresses automatic network event reporting.
USER_INTERACTIONSSuppresses automatic user-interaction event reporting.
ERRORSSuppresses automatic error/crash event reporting.

Complete example

val tracer = CoralogixRum.getCustomTracer() ?: return

val globalSpan = tracer.startGlobalSpan(
name = "checkout-flow",
labels = mapOf("cart.item_count" to 3)
) ?: return

val paymentSpan = globalSpan.startCustomSpan(
name = "payment-step",
labels = mapOf("payment.method" to "credit_card")
)

paymentSpan.addEvent("payment-initiated")

try {
processPayment()
paymentSpan.setAttribute("payment.success", true)
paymentSpan.setStatus(StatusCode.OK)
paymentSpan.addEvent("payment-complete")
} catch (e: Exception) {
paymentSpan.setAttribute("error.message", e.message ?: "unknown")
paymentSpan.setStatus(StatusCode.ERROR)
} finally {
paymentSpan.endSpan()
globalSpan.endSpan()
}

For details about prerequisites, use cases, and limitations, see Custom spans.

Integration functions

Set user context

Provide user context dynamically as user metadata becomes available.

CoralogixRum.setUserContext(
UserContext(
userId = "123",
username = "User User",
email = "[email protected]",
metadata = mapOf("role" to "Admin")
)
)

val context: UserContext = CoralogixRum.getUserContext()

getUserContext() returns a UserContext with empty values if the SDK is not initialized.

Set labels

Update global labels during runtime.

CoralogixRum.setLabels(
mapOf(
"environment" to "production",
"version" to "1.0.2"
)
)

val labels: Map<String, Any?> = CoralogixRum.getLabels()

getLabels() returns an empty map if the SDK is not initialized.

Set application context

Update the application name and version dynamically.

CoralogixRum.setApplicationContext(
appName = "MyApp",
appVersion = "1.0.0"
)

Custom measurements

Send a numeric key-value measurement to Coralogix.

CoralogixRum.sendCustomMeasurement("image_upload_time_ms", 1480L)

Custom time measurement

Measure the duration of any operation by wrapping it with startTimeMeasure and endTimeMeasure. The SDK records the elapsed time and emits a measurement event with the duration in milliseconds.

CoralogixRum.startTimeMeasure("checkout-flow", mapOf("cart.items" to 3))

// ... perform the operation ...

CoralogixRum.endTimeMeasure("checkout-flow")
  • If startTimeMeasure is called a second time with the same name before endTimeMeasure, the second call is a no-op.
  • If the session goes idle between start and end, the measurement is silently dropped.
  • Calling endTimeMeasure without a prior startTimeMeasure is a no-op.

Set view context

When using the SDK, ViewContext is set to the activity or fragment name by default. Update it manually when needed.

CoralogixRum.setViewContext(
viewName = "CustomViewName"
)

Log messages

Send log messages with customized severity levels. data and labels are optional and apply only to this event.

CoralogixRum.log(
severity = CoralogixLogSeverity.Error,
message = "Custom log message error",
data = mapOf("userId" to "12345"), // optional
labels = mapOf("environment" to "staging") // optional
)

CoralogixLogSeverity defines severity levels:

CaseSeverity level
DebugDebug
VerboseVerbose
InfoInformational
WarnWarning
ErrorError
CriticalCritical

Report errors

Report a handled error to Coralogix. Reported errors appear with level 5 (error) severity.

// Basic — report the exception.
try {
riskyOperation()
} catch (t: Throwable) {
CoralogixRum.reportError(
throwable = t,
data = mapOf("cart_size" to 3, "reason" to "timeout"),
labels = mapOf("team" to "payments")
)
}

The data and labels parameters are optional. data attaches arbitrary key-value pairs to the error event; labels adds searchable metadata.

Custom spans

try {
riskyOperation()
} catch (t: Throwable) {
CoralogixRum.reportError(
throwable = t,
data = mapOf("orderId" to "ORD-123", "amount" to 99.99),
labels = mapOf("team" to "payments")
)
}

data is emitted under error_context.error_custom_data. labels are merged into the event's labels. Provide JSON-serializable values; values that cannot be serialized may be dropped.

For richer error reporting, pass a CoralogixErrorDecorator with customAttributes:

val decorator = CoralogixErrorDecorator(
throwable = t,
isCrash = false
).copy(
customAttributes = mapOf(
"userId" to "12345",
"screen" to "checkout"
)
)
CoralogixRum.reportError(decorator)

To filter or redact error data before it leaves the device, edit the event in the beforeSend callback.

Create new session

Force-start a fresh RUM session on demand — for example, on user logout — without re-initializing the SDK. A new session ID is issued and all per-session state resets.

CoralogixRum.createNewSession()

Pair this with setUserContext when logging in a new user.

Get session ID

Retrieve the current session ID.

val sessionId: String = CoralogixRum.getSessionId()

Returns an empty string if the SDK is not initialized.

Flush events

Flush any events still held in the SDK's batch buffer. The SDK automatically flushes when the app backgrounds; use this to flush on demand.

CoralogixRum.flush()

// React once the export completes:
CoralogixRum.flush {
Log.d("MyApp", "buffered events exported")
}

Shut down

Gracefully shut down the SDK.

CoralogixRum.shutdown()

Check initialization state

Before calling SDK methods, verify the SDK is initialized.

Example

if (CoralogixRum.isInitialized()) {
CoralogixRum.log(CoralogixLogSeverity.Info, "SDK is ready")
}

Get session ID

Retrieve the current session ID. Returns an empty string if the SDK is not initialized.

Example

val sessionId = CoralogixRum.getSessionId()

Get user context

Read back the user context that was set with setUserContext.

Example

val userContext = CoralogixRum.getUserContext()

Get labels

Read back the labels currently attached to events. Returns an empty map if the SDK is not initialized.

Example

val labels = CoralogixRum.getLabels()

Set application context

Attach or update the application name and version at runtime.

Example

CoralogixRum.setApplicationContext(
applicationName = "MyApp",
applicationVersion = "2.1.0"
)

Create new session

Force a fresh session, for example on user logout. Resets the session ID and all session state.

Example

CoralogixRum.createNewSession()

Measure operation duration

Bracket an operation with startTimeMeasure / endTimeMeasure to track how long it takes. Elapsed time appears as a custom measurement in Coralogix.

Example

CoralogixRum.startTimeMeasure("checkout", mapOf("step" to "payment"))
// ... perform checkout ...
CoralogixRum.endTimeMeasure("checkout")

Shut down the SDK

Flush pending data and release resources. Call this when you no longer need the SDK, for example during graceful app termination.

Example

CoralogixRum.shutdown()

Decoupling session sampling

By default, the sessionSampleRate controls which instrumentation categories are exported. Use excludeFromSampling to always export specific categories at 100%, regardless of the sample rate — for example, to ensure errors are never dropped even on low-traffic samples.

Example

val config = CoralogixOptions(
// ...
sessionSampleRate = 20,
excludeFromSampling = listOf(
ExcludableInstrumentation.Errors
)
)

ExcludableInstrumentation values:

ValueDescription
ErrorsError events
LogsLog messages
NetworkNetwork requests
UserInteractionsClick and long-click events
MobileVitalsCPU, memory, FPS, and startup metrics
CustomSpanCustom OpenTelemetry spans
CustomMeasurementCustom numeric measurements
NavigationNavigation events
LifecycleActivity and fragment lifecycle events

Troubleshooting

If you encounter a dependency that requires Java 8+ APIs, such as enabling core library desugaring to ensure compatibility across Android versions, do the following:

1.

Update compileOptions by adding the following to your build.gradle file.

android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
2.

Add the desugaring dependency.

dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
}

This enables modern Java features on older Android versions.

Last updated on