porthole capturing on URLSession · snaplen ∞ · in-process

porthole

0000  70 6f 72 74 68 6f 6c 65                          |porthole|

An in-app network inspector for iOS & macOS. no proxy · no certificates · no desktop app · just a SwiftUI viewer compiled into your build.

[ install » ] [ read the source ]
0000  6e 6f 20 70 72 6f 78 79  2e 20 6e 6f 20 63 65 72 |no proxy. no cer|
0010  74 2e                                            |t.|
0x0040 CAPTURE

Porthole records your app’s URLSession requests, responses, and WebSocket frames in-process and shows them in a SwiftUI viewer.

A fork of Proxyman / Atlantis, with an on-device viewer instead of a desktop app.

live capture · 0 captured
Live demo. Pause or clear capture.
0x0080 THE PACKET
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
SRC bytes 0–1
HTTP · HTTPS
Every URLSession request & response.
DST bytes 2–3
WebSocket
Frames sent ↑ and received ↓.
PAYLOAD bytes 4–7
SwiftUI Viewer
Headers, bodies, timing, status.
EXPORT bytes 8–11
cURL · HAR
Replay any entry elsewhere.
FLAGS bytes 12–13
pause / resume / clear
Control capture at runtime.
WINDOW byte 14
ring buffer
Fixed capacity; oldest evicted.
OPT byte 15
memory-only
Never touches disk.
0000  73 77 69 66 74 20 70 61  63 6b 61 67 65 20 61 64 |swift package ad|
0010  64                                               |d|
0x0100 INSTALL

Add via Swift Package Manager:

// Package.swift
dependencies: [
    .package(
        url: "https://github.com/sohandotgit/Porthole.git",
        from: "3.3.0"
    )
]
0x0140 START

Start capture once at launch, in debug builds.

import SwiftUI
#if DEBUG
import Atlantis
#endif

@main
struct MyApp: App {
    init() {
        #if DEBUG
        Atlantis.start()
        #endif
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}
0x0180 INSPECT

Present the viewer anywhere.

import Atlantis

struct DebugMenu: View {
    @State private var showTraffic = false

    var body: some View {
        Button("Network Log") { showTraffic = true }
            .sheet(isPresented: $showTraffic) {
                NavigationStack {
                    AtlantisTrafficListView()
                }
            }
    }
}
0x01c0 CONTROLS
MEMBER TYPE DESCRIPTION
clear() func Remove all recorded traffic.
isPaused Bool Ignore new requests while true.
capacity Int Max entries kept. Default 500.
0x0200 EXPORT
  • »cURL: copy a request as a curl command.
  • »HAR: export the session for Proxyman, Charles, or DevTools.
0x0240 USED BY
redBus
0x0280 REQUIRES

iOS 16+ · macOS 11+ · Mac Catalyst 13+ · tvOS 13+ · watchOS 10+ · Xcode 14+. No dependencies.

0x02c0 NOTES

Traffic stays in memory, never on disk or off-device. No Map Local, Breakpoint, or Scripting. Keep Atlantis.start() behind #if DEBUG.

0000  6d 65 6d 6f 72 79 20 6f  6e 6c 79                |memory only|