
Network inspector for Ktor Client capturing requests, responses, failures, timings, headers, body previews, WebSocket frames, GraphQL metadata, cURL commands, exportable logs, plus in-memory store and optional Compose UI.
KtorScope is a Kotlin Multiplatform network inspector for Ktor Client. It captures requests, responses, failures, timings, headers, body previews, WebSocket frames, GraphQL metadata, cURL commands, and exportable logs, then exposes everything through a shared in-memory store and an optional Compose Multiplatform UI.
The project currently targets Android and iOS.
Current version: 1.2.0
| Module | Purpose |
|---|---|
ktorscope-core |
Shared models, store, redaction, body previews, cURL generation, GraphQL parsing, pretty printing, and log export helpers. |
ktorscope-ktor |
Ktor Client plugin that records HTTP transactions and WebSocket frames into KtorScopeStore. |
ktorscope-compose |
Compose Multiplatform inspector UI, clipboard/share hooks, and transaction details screens. |
ktorscope-persistence |
Optional Room KMP history persistence plus platform file storage for large bodies and persisted WebSocket frame history. |
For a published Maven setup, use the same module split:
commonMain.dependencies {
implementation("io.github.mahmoud947:ktorscope-core:1.2.0")
implementation("io.github.mahmoud947:ktorscope-ktor:1.2.0")
implementation("io.github.mahmoud947:ktorscope-compose:1.2.0")
implementation("io.github.mahmoud947:ktorscope-persistence:1.2.0") // optional Room history
}If you use a Gradle version catalog, add the modules to gradle/libs.versions.toml:
[versions]
ktorscope = "1.2.0"
[libraries]
ktorscope-core = { module = "io.github.mahmoud947:ktorscope-core", version.ref = "ktorscope" }
ktorscope-ktor = { module = "io.github.mahmoud947:ktorscope-ktor", version.ref = "ktorscope" }
ktorscope-compose = { module = "io.github.mahmoud947:ktorscope-compose", version.ref = "ktorscope" }
ktorscope-persistence = { module = "io.github.mahmoud947:ktorscope-persistence", version.ref = "ktorscope" }Then use the aliases in your dependencies:
commonMain.dependencies {
implementation(libs.ktorscope.core)
implementation(libs.ktorscope.ktor)
implementation(libs.ktorscope.compose)
implementation(libs.ktorscope.persistence) // optional Room history
}Inside this repository, use project dependencies:
commonMain.dependencies {
implementation(projects.ktorscopeCore)
implementation(projects.ktorscopeKtor)
implementation(projects.ktorscopeCompose)
implementation(projects.ktorscopePersistence) // optional Room history
}Install the plugin in your Ktor client:
import io.github.mahmoud.ktorscope.ktor.KtorScope
import io.ktor.client.HttpClient
val client = HttpClient {
install(WebSockets) // optional, required only when your client uses Ktor WebSockets
install(KtorScope) {
enabled = true
captureBodies = true
captureWebSocketFrames = true
maxBodySize = 250_000
redactHeaders = setOf("Authorization", "Cookie", "Set-Cookie", "X-Api-Key")
prettyPrint = true
prettyPrintConfig {
includeCurl = true
}
logger = { message -> println(message) }
}
}Show the inspector UI from Compose:
import androidx.compose.runtime.Composable
import io.github.mahmoud.ktorscope.compose.KtorScopeScreen
@Composable
fun NetworkInspectorRoute(onClose: () -> Unit) {
KtorScopeScreen(onBackClicked = onClose)
}To keep historical sessions across launches, add ktorscope-persistence, create a KtorScopePersistence on each platform with ScopPersistenceFactory, and pass its historyPersistence into the Ktor plugin:
install(KtorScope) {
historyPersistence {
enabled = true
maxRecords = 500
this.persistence = ktorScopePersistence.historyPersistence
}
}Then pass persistHistory = true and onLoadFullBody = ktorScopePersistence.bodyFileStore::readBody to KtorScopeScreen.
WebSockets plugin is installed.maxBodySize.maxWebSocketFramePreviewSize.Build all library modules:
./gradlew :ktorscope-core:build :ktorscope-ktor:build :ktorscope-compose:build :ktorscope-persistence:buildhttps://github.com/user-attachments/assets/1426b17f-b1d2-42b0-8dc8-f9f7ed3a97e9
KtorScope is released under the Apache License 2.0.
KtorScope is a Kotlin Multiplatform network inspector for Ktor Client. It captures requests, responses, failures, timings, headers, body previews, WebSocket frames, GraphQL metadata, cURL commands, and exportable logs, then exposes everything through a shared in-memory store and an optional Compose Multiplatform UI.
The project currently targets Android and iOS.
Current version: 1.2.0
| Module | Purpose |
|---|---|
ktorscope-core |
Shared models, store, redaction, body previews, cURL generation, GraphQL parsing, pretty printing, and log export helpers. |
ktorscope-ktor |
Ktor Client plugin that records HTTP transactions and WebSocket frames into KtorScopeStore. |
ktorscope-compose |
Compose Multiplatform inspector UI, clipboard/share hooks, and transaction details screens. |
ktorscope-persistence |
Optional Room KMP history persistence plus platform file storage for large bodies and persisted WebSocket frame history. |
For a published Maven setup, use the same module split:
commonMain.dependencies {
implementation("io.github.mahmoud947:ktorscope-core:1.2.0")
implementation("io.github.mahmoud947:ktorscope-ktor:1.2.0")
implementation("io.github.mahmoud947:ktorscope-compose:1.2.0")
implementation("io.github.mahmoud947:ktorscope-persistence:1.2.0") // optional Room history
}If you use a Gradle version catalog, add the modules to gradle/libs.versions.toml:
[versions]
ktorscope = "1.2.0"
[libraries]
ktorscope-core = { module = "io.github.mahmoud947:ktorscope-core", version.ref = "ktorscope" }
ktorscope-ktor = { module = "io.github.mahmoud947:ktorscope-ktor", version.ref = "ktorscope" }
ktorscope-compose = { module = "io.github.mahmoud947:ktorscope-compose", version.ref = "ktorscope" }
ktorscope-persistence = { module = "io.github.mahmoud947:ktorscope-persistence", version.ref = "ktorscope" }Then use the aliases in your dependencies:
commonMain.dependencies {
implementation(libs.ktorscope.core)
implementation(libs.ktorscope.ktor)
implementation(libs.ktorscope.compose)
implementation(libs.ktorscope.persistence) // optional Room history
}Inside this repository, use project dependencies:
commonMain.dependencies {
implementation(projects.ktorscopeCore)
implementation(projects.ktorscopeKtor)
implementation(projects.ktorscopeCompose)
implementation(projects.ktorscopePersistence) // optional Room history
}Install the plugin in your Ktor client:
import io.github.mahmoud.ktorscope.ktor.KtorScope
import io.ktor.client.HttpClient
val client = HttpClient {
install(WebSockets) // optional, required only when your client uses Ktor WebSockets
install(KtorScope) {
enabled = true
captureBodies = true
captureWebSocketFrames = true
maxBodySize = 250_000
redactHeaders = setOf("Authorization", "Cookie", "Set-Cookie", "X-Api-Key")
prettyPrint = true
prettyPrintConfig {
includeCurl = true
}
logger = { message -> println(message) }
}
}Show the inspector UI from Compose:
import androidx.compose.runtime.Composable
import io.github.mahmoud.ktorscope.compose.KtorScopeScreen
@Composable
fun NetworkInspectorRoute(onClose: () -> Unit) {
KtorScopeScreen(onBackClicked = onClose)
}To keep historical sessions across launches, add ktorscope-persistence, create a KtorScopePersistence on each platform with ScopPersistenceFactory, and pass its historyPersistence into the Ktor plugin:
install(KtorScope) {
historyPersistence {
enabled = true
maxRecords = 500
this.persistence = ktorScopePersistence.historyPersistence
}
}Then pass persistHistory = true and onLoadFullBody = ktorScopePersistence.bodyFileStore::readBody to KtorScopeScreen.
WebSockets plugin is installed.maxBodySize.maxWebSocketFramePreviewSize.Build all library modules:
./gradlew :ktorscope-core:build :ktorscope-ktor:build :ktorscope-compose:build :ktorscope-persistence:buildhttps://github.com/user-attachments/assets/1426b17f-b1d2-42b0-8dc8-f9f7ed3a97e9
KtorScope is released under the Apache License 2.0.