Snap-O

Network Inspector

Capture HTTP and HTTPS requests from an Android app in Snap-O, including response bodies, Server-Sent Events, and WebSocket messages. Works with OkHttp, Ktor's OkHttp engine, and HttpURLConnection.

Add JitPack to Gradle

Snap-O publishes its Android libraries through JitPack. Add the repository to your dependency sources once.

settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
    }
}

Add the Android dependency

Choose the dependency that matches your network client. Use the real interceptor in debug builds and its no-op counterpart in release builds.

OkHttp or Ktor

Use the OkHttp interceptor for OkHttp directly or through Ktor's OkHttp engine.

app/build.gradle.kts
dependencies {
    debugImplementation("com.github.openai.snap-o:network-okhttp3:2.0.1")
    releaseImplementation("com.github.openai.snap-o:network-okhttp3-noop:2.0.1")
}
HttpURLConnection

Use the HttpURLConnection interceptor on Android 7.0 (API 24) or newer.

app/build.gradle.kts
dependencies {
    debugImplementation("com.github.openai.snap-o:network-httpurlconnection:2.0.1")
    releaseImplementation("com.github.openai.snap-o:network-httpurlconnection-noop:2.0.1")
}

Add request interceptors

Add the interceptor once when the client is created. Every request made by that client can then be replayed or streamed to Snap-O.

OkHttp

Kotlin
import com.openai.snapo.network.okhttp3.SnapOOkHttpInterceptor

val client = OkHttpClient.Builder()
    .addInterceptor(SnapOOkHttpInterceptor())
    .build()
Requests are buffered on the device for up to five minutes by default, so Snap-O can open after the app starts and still show recent traffic.
Ktor with the OkHttp engine

Attach the same interceptor through Ktor's OkHttp engine.

Kotlin
import com.openai.snapo.network.okhttp3.SnapOOkHttpInterceptor

val client = HttpClient(OkHttp) {
    engine {
        addInterceptor(SnapOOkHttpInterceptor())
    }
}
HttpURLConnection

Open the connection through the Snap-O interceptor. Response details are captured when your app reads the response code or response stream.

Kotlin
import com.openai.snapo.network.httpurlconnection.SnapOHttpUrlInterceptor

val interceptor = SnapOHttpUrlInterceptor()
val connection = interceptor.open(URL("https://example.com"))

connection.connect()
connection.inputStream.use { body ->
    // Read the response.
}
connection.disconnect()
WebSockets

Create WebSockets through the wrapped factory. Regular HTTP calls can continue using the original client.

Kotlin · OkHttp
import com.openai.snapo.network.okhttp3.withSnapOInterceptor

val webSocketFactory = client.withSnapOInterceptor()
val webSocket = webSocketFactory.newWebSocket(request, listener)

For Ktor, assign okHttpClient.withSnapOInterceptor() to the engine's webSocketFactory and install Ktor's WebSockets plugin.

Verify the connection

  1. Install and launch the debug build on an authorized Android device or emulator.
  2. Open Snap-O on macOS and select the connected device.
  3. Open Tools → Network Inspector, use the toolbar network icon, or press ⌘⌥I.
  4. Select the app process if prompted, then trigger a request in the Android app.
  5. Open the request to inspect headers, bodies, timing, SSE, or WebSocket messages.

If the Android app restarts, Snap-O may offer a newer process in the inspector sidebar. Switch to it to continue with live traffic.

Troubleshooting

  • Confirm the device is online and authorized in adb devices.
  • Confirm the installed variant includes the debug interceptor, not the no-op release artifact.
  • Make sure the request uses the exact OkHttp client, Ktor engine, or HttpURLConnection wrapper you configured.
  • Keep the Android app process running and select the newest process after an app restart.
  • Update the Snap-O desktop app and Android dependency together if a protocol mismatch appears.
  • Large or old bodies may be unavailable after the five-minute, 10,000-event, or 16 MB replay limits are reached.

Advanced setup

Debug builds initialize the on-device server automatically through SnapONetworkInitProvider. Most apps should keep the defaults.

Provider configuration

The provider supports automatic initialization, main-process filtering, a mode label, and replay limits. Manifest overrides must use Android manifest-merger directives because the library already declares these metadata entries.

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application>
        <provider
            android:name="com.openai.snapo.network.SnapONetworkInitProvider"
            android:authorities="${applicationId}.snapo-network-init"
            android:exported="false">
            <meta-data
                android:name="snapo.auto_init"
                android:value="false"
                tools:replace="android:value" />
        </provider>
    </application>
</manifest>
Manual initialization

If automatic initialization is disabled, initialize the inspector from your application process with a custom NetworkInspectorConfig.

Kotlin
import com.openai.snapo.network.NetworkInspector
import com.openai.snapo.network.NetworkInspectorConfig

NetworkInspector.initialize(
    application,
    NetworkInspectorConfig(),
)
Read the protocol and security reference on GitHub