Mobile session replay
Updated Oct 21, 2026 · today
The Epok replay libraries record your Android and iOS screens as masked wireframes and send them only to Epok. You watch them in the same replay player as browser sessions. Capture uses PostHog's open-source mobile recorder (MIT), pinned to one tested version and configured so that nothing reaches PostHog.
What is recorded
- Wireframes of your views: layout, text, and touches. No screenshots and no video.
- Text inputs and images are always masked. A typed value is stored only as asterisks.
- Logs, network bodies, and analytics events are not captured.
- Nothing is created, recorded, queued, or sent until your app grants consent. Withdrawal stops capture and erases anything still queued on the device.
Android
Android 8.0 (API 26) or later. The library pins posthog-android 3.72.3; if your app already uses a different PostHog version, Gradle reports the conflict at build time.
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven("https://jitpack.io")
}
}
// app/build.gradle.kts
dependencies {
implementation("com.github.jayswamidass:epok-android:0.1.0")
}import dev.epok.replay.EpokReplay
import dev.epok.replay.EpokReplayConfig
class App : Application() {
lateinit var replay: EpokReplay
override fun onCreate() {
super.onCreate()
// Constructs nothing yet: no capture, no queue, no network.
replay = EpokReplay(this, EpokReplayConfig(
ingestKey = "epk_…", // restricted ingest-only key
endpoint = "https://ingest.getepok.dev",
))
}
}
// From your consent UI, on a background thread (setup does disk I/O):
app.replay.grant() // start masked wireframe capture
app.replay.withdraw() // stop capture and erase anything still queuediOS
iOS 15 or later, Swift Package Manager. The package pins posthog-ios 3.92.0. Use your Epok tenant ID as accountId; the server identifies your tenant from the key.
// Xcode: File → Add Package Dependencies…, or in Package.swift:
.package(url: "https://github.com/jayswamidass/epok-ios.git", exact: "0.1.0"),
// target dependencies:
.product(name: "EpokRum", package: "epok-ios"),
.product(name: "EpokReplay", package: "epok-ios"),import EpokRum
import EpokReplay
// On launch — creates no PostHog SDK, no files, and sends nothing yet:
let rum = try Rum(config: RumConfig(
endpoint: "https://ingest.getepok.dev",
publicIngestKey: "epk_…", // restricted ingest-only key
accountId: "YOUR_TENANT_ID", projectId: "0",
serviceName: "my-ios-app"))
let replay = try EpokReplay(rum: rum,
host: URL(string: "https://ingest.getepok.dev/v1/rum/mobile/ios")!,
publicIngestKey: "epk_…")
// From your consent UI (on the main actor):
await replay.grantConsent() // grants RUM consent too, then starts capture
await replay.withdrawConsent() // stop capture and erase anything still queuedSource and licence
Both libraries are open source under Apache-2.0: epok-android (built by JitPack from the tagged source) and epok-ios (Swift Package Manager). Mobile replay is in early access: tell us when you install it, so that we can help you check the first sessions.
Check the integration
- Use a restricted ingest-only key. The key ships inside your app, so treat it as public.
- Before consent, confirm the app makes no request to ingest.getepok.dev.
- Grant consent, use the app for a minute, then open Replay in Epok and filter by Android or iOS. A new session appears within a few minutes.
- Type into a text field and check that the replay shows only asterisks.
- Withdraw consent and confirm that no further uploads occur.
For mobile traces, errors, and metrics, see mobile OpenTelemetry. For browsers, see browser RUM & replay.