Network Telemetry & Monitoring in KMP
Appxiom captures HTTP/HTTPS network telemetry across Android and iOS in Kotlin Multiplatform applications. It tracks request/response durations, status codes, payload sizes, sensitive header masking, dynamic endpoint grouping, and network failures (timeouts, DNS failures, connection drops).
Engine Handling
Kotlin Multiplatform network monitoring operates seamlessly depending on your target platform and Ktor client engine, including OkHttp in Android, Darwin and CIO in iOS.
Dependency Setup
In your shared module's build.gradle.kts (e.g. composeApp/build.gradle.kts):
val appxiomVersion = "2.1.0"
kotlin {
sourceSets {
commonMain.dependencies {
api("tech.appxiom:appxiom-kmp-core:$appxiomVersion")
// Ktor telemetry plugin (always implementation, NEVER export to iOS framework)
implementation("tech.appxiom:appxiom-kmp-ktor:$appxiomVersion")
// Ktor Client core & serialization
implementation("io.ktor:ktor-client-core:2.3.12")
implementation("io.ktor:ktor-client-content-negotiation:2.3.12")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")
}
}
}
1. Ktor Client Telemetry Setup
Install AppxiomKtorPlugin directly into your shared HttpClient instance:
package com.example.app.network
import io.ktor.client.HttpClient
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.serialization.kotlinx.json.json
import kotlinx.serialization.json.Json
import tech.appxiom.kmp.ktor.AppxiomKtorPlugin
val apiClient = HttpClient {
// Install Appxiom telemetry plugin
install(AppxiomKtorPlugin)
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
isLenient = true
})
}
}
2. Dynamic URL Grouping (Observe.setUrlPatterns)
Dynamic RESTful paths (e.g. /users/123 and /users/456) should be grouped into a single aggregated endpoint in the dashboard (/users/{id}):
import tech.appxiom.kmp.ktor.Observe
Observe.setUrlPatterns(
listOf(
"/api/v1/users/{id}",
"/api/v1/orders/{orderId}/items/{itemId}",
"/api/v1/products/{slug}"
)
)
3. Sensitive Header Masking (Observe.setMaskedHeaders)
Prevent confidential auth tokens, passwords, or session cookies from appearing in the dashboard:
import tech.appxiom.kmp.ktor.Observe
Observe.setMaskedHeaders(
listOf(
"Authorization",
"Proxy-Authorization",
"Cookie",
"Set-Cookie",
"X-Api-Key",
"X-Auth-Token"
)
)
Masked headers will appear as * in the Appxiom dashboard.
4. Domain Whitelisting & Timeout Rules
import tech.appxiom.kmp.ktor.Observe
// Only capture telemetry for specified API domains:
Observe.setWhiteListedDomains(
listOf("api.example.com", "auth.example.com")
)
// Set custom timeout thresholds in milliseconds (minimum 1000ms):
Observe.setBaseUrlTimeouts(
mapOf(
"https://api.example.com/checkout" to 5000L,
"https://api.example.com/upload" to 30000L
)
)
// Configure body capture (enabled by default, max 64 KB):
Observe.setCaptureBody(true)
Observe.setMaxBodySizeBytes(64 * 1024L)
5. iOS Native Info.plist Configuration (Darwin Engine)
When targeting iOS with the Darwin engine (ktor-client-darwin) or native URLSession, network calls are intercepted natively by the Appxiom iOS framework. Configure host whitelisting, dynamic URL path grouping, sensitive header masking, and timeout thresholds in your iOS target's Info.plist (typically iosApp/iosApp/Info.plist) as well under the AX dictionary.
Configuration Overview
- Whitelisting Hosts: Define allowed domains directly under
HTTPMonitoring. Only HTTP(S) calls to these hosts will be tracked. To monitor all hosts, use*(or omit the whitelist). - Grouping Dynamic Path Components (
PathPatterns): Nest dynamic path patterns under a host key (or*). Dynamic path segments are enclosed in{}(e.g./users/{userId},/orders/{orderId}) to aggregate dynamic calls into a single issue. - Privacy & Masking Headers (
MaskedHeaders): Mask sensitive headers (such asAuthorization,Cookie, or custom keys) before telemetry is reported. Define headers globally under<key>*</key>or scope them to specific endpoints (e.g.,/users). - Network Timeouts (
NetworkTimeout): Define maximum request thresholds in milliseconds. If an API call exceeds this duration, Appxiom flags an issue report.
Info.plist Example
<key>AX</key>
<dict>
<key>AppKey</key>
<string>YOUR_IOS_APP_KEY</string>
<key>PlatformKey</key>
<string>YOUR_IOS_PLATFORM_KEY</string>
<!-- Network Monitoring Configuration -->
<key>HTTPMonitoring</key>
<dict>
<!-- Whitelist specific host or use "*" to monitor all hosts -->
<key>api.example.com</key>
<dict>
<key>PathPatterns</key>
<dict>
<!-- Global rules for all endpoints under this host -->
<key>*</key>
<dict>
<key>MaskedHeaders</key>
<array>
<string>Authorization</string>
<string>Cookie</string>
<string>X-Api-Key</string>
</array>
<key>NetworkTimeout</key>
<integer>4000</integer>
</dict>
<!-- Group dynamic endpoints with parameters wrapped in {} -->
<key>/users/{userId}</key>
<dict/>
<key>/orders/{orderId}/items/{itemId}</key>
<dict/>
<!-- Endpoint-specific masking and custom timeout -->
<key>/fileUpload</key>
<dict>
<key>MaskedHeaders</key>
<array>
<string>X-Upload-Token</string>
</array>
<key>NetworkTimeout</key>
<integer>50000</integer>
</dict>
</dict>
</dict>
</dict>
</dict>
Please make sure that only one AX key exists in your Info.plist file. All Appxiom configurations (AppKey, PlatformKey, and HTTPMonitoring) must be grouped inside this single dictionary.
Next Steps
Learn how to trap and report crashes in Crash & Error Reporting.