Everything Alohomora captures and how to use it. Each feature works on both the in-app console and the desktop companion.
All outbound network activity is captured as structured, queryable data. Every entry carries:
The detail view has three tabs: Overview (method, status, timing), Request (headers + body), and Response (headers + body). Search across all entries, clear the list, share to Slack as formatted text or cURL, or replay the request.
Capture is automatic for OkHttp and Ktor. On iOS, you need to use the provided session configuration. For anything else, record manually.
val client = OkHttpClient.Builder() .addInterceptor(TrafficInterceptor()) .build()
val client = HttpClient { install(AlohomoraInspector) }
let config = Alohomora.shared.alohomoraURLSessionConfiguration() let session = URLSession(configuration: config)
Alohomora.recordTraffic( method = "GET", url = "https://api.example.com/users", statusCode = 200, requestHeaders = headers, responseBody = body )
Open any captured request, edit the method, URL, headers, or body, then re-send it. The request goes through your HTTP client, so signatures are regenerated, bearer tokens are refreshed, and cert pinning works.
Register a handler once at startup:
// OkHttp (including Retrofit) Alohomora.registerReplayHandler(okHttpReplayHandler(client)) // Ktor (Android + iOS) Alohomora.registerReplayHandler(ktorReplayHandler(client)) // Custom lambda Alohomora.registerReplayHandler { request -> // sign, send, return response }
If your app signs requests, tell replay which headers to strip so your interceptors regenerate them:
ReplayHeaders.additionalStripList = setOf("X-Signature", "X-Timestamp")
Retrofit has no interceptors of its own — it delegates to the OkHttpClient passed to Retrofit.Builder().client(...). Register the replay handler on that same client.
val okHttpClient = OkHttpClient.Builder() .addInterceptor(SigningInterceptor()) .addInterceptor(TrafficInterceptor()) .build() val retrofit = Retrofit.Builder() .baseUrl("https://api.example.com/") .client(okHttpClient) .build() Alohomora.registerReplayHandler(okHttpReplayHandler(okHttpClient))
The desktop app can intercept matching requests on the device and return canned responses before they hit the network. Each rule carries:
Use {{placeholder}} syntax in mock response bodies. Each placeholder resolves to a fresh value per request. Unknown placeholders pass through as-is.
| Syntax | Example output |
|---|---|
{{uuid}} | 550e8400-e29b-41d4-a716-446655440000 |
{{name}} | Jane Smith |
{{firstName}} / {{lastName}} | Jane / Smith |
{{email}} | jane.smith@example.com |
{{int(1,100)}} | 42 |
{{float(0,1)}} | 0.7342 |
{{amount(10,500)}} | 247.83 |
{{date(past,30)}} | 2026-07-15 |
{{date(future,365)}} | 2027-05-20 |
{{timestamp}} | 1723456789000 |
{{bool}} | true or false |
{{oneOf(active,inactive,pending)}} | inactive |
Rules are grouped into named sessions, saved to ~/.alohomora/mock-sessions/ as JSON. Auto-save triggers after 500 ms of inactivity. The last active session is restored on launch.
.alohomora-mocks.json and share with your team.alohomora-mocks.json or HAR 1.2 files (only 2xx responses with a body are kept)Simulate slow networks with five presets:
| Preset | Latency | Throughput |
|---|---|---|
| Edge | 500 ms | 50 KB/s |
| Slow 3G | 200 ms | 100 KB/s |
| Fast 3G | 100 ms | 300 KB/s |
| Slow Wi-Fi | 50 ms | 1 MB/s |
| None | 0 | Unlimited |
Latency is applied before the response. Throughput is capped on the body.
On Android, device-wide throttling is available via a local VPN service. This covers all device traffic including WebViews, not just your HTTP client.
Browse Alohomora's internal capture database and any app databases you register. Pick a database, then a table, and page through rows.
// Register a database for inspection Alohomora.registerAppDatabase(name = "app.db") // Exclude a database you don't want visible Alohomora.excludeAppDatabase(name = "cache.db")
Record named events with a timestamp and optional string properties. The Events panel lists entries newest-first, with search by name, expand to view properties, and clear.
Alohomora.recordEvent( name = "checkout_started", properties = mapOf("cart_size" to "3") )
Read live key-value state from the device:
Keys load lazily. Click a key to fetch its current value. Read-only.
Uncaught exceptions are captured automatically. The crash handler is installed at init and chains to whatever handler was there before, so your Crashlytics/Sentry stays intact.
Alohomora.recordError(throwable, place = "SyncWorker")
Swift Error is not a KotlinThrowable, so use the dedicated overload:
Alohomora.shared.recordError( reason: "DecodingError: keyNotFound", stackTrace: Thread.callStackSymbols.joined(separator: "\n"), place: "ProfileLoader" )
Features: search, full stack-trace detail view, copy to clipboard, clear.
Errors also appear in the Events timeline as App.Exception entries, rendered with an error accent bar.
Config shows build metadata: project name, variant, version name/code, branch, commit SHA, dirty flag, and build timestamp.
Git History shows the last N commits (configurable, default 50): SHA, author, subject, and timestamp.
Both are injected at build time by the Gradle plugin (Android) or an Xcode run-script phase (iOS). No runtime cost.
alohomora { enabledVariants = setOf("debug") maxCommits = 50 slackWebhookUrl = "https://hooks.slack.com/services/..." versionName = project.version.toString() versionCode = 1 }
Desktop-only. Accessible from the Dashboard toolbar or the command palette.
Compose a URL from individual parts: scheme dropdown (https, http, deeplink, content, custom), host, port, path, query parameters (add/remove rows), and fragment. A live URL preview updates as you type. Click "Open on device" to fire via adb shell am start.
Every URL you fire is persisted to ~/.alohomora/deeplink-history.json (up to 50 entries, deduplicated). Click to populate the builder, play to fire directly, trash to remove individual entries, or "Clear all" at the top.
Cmd/Ctrl+K opens a searchable command palette on the desktop app. Actions are grouped into four categories:
Cmd+1..9 shortcutsArrow keys to navigate, Enter to select. Each action shows its keyboard shortcut as a chip.
These panels are gated on device capability and hidden when connected to an iOS device.
| Shortcut | Action |
|---|---|
Cmd/Ctrl+K | Open command palette |
Cmd/Ctrl+1..9 | Switch to Nth sidebar section |
Cmd/Ctrl+T | Toggle dark/light theme |
Cmd/Ctrl+/ | Open keyboard shortcuts help |
Cmd/Ctrl+N | New window |
Cmd/Ctrl+W | Close window |
Cmd/Ctrl+= | Zoom in |
Cmd/Ctrl+- | Zoom out |
Cmd/Ctrl+0 | Reset zoom |
Cmd/Ctrl+Shift+S | Take device screenshot |
Cmd/Ctrl+Shift+Backspace | Clear active panel data |
Escape | Close side sheet / dismiss dialog |