by Barrett Lyon @ doxx.net
Stream console logs from iOS/Android devices over WebSocket.
Created to enable Cursor AI assistance with mobile apps during development. Console messages from TestFlight builds are impossible to extract in real-time, making debugging a guessing game. This streams logs directly to your dev environment so you can see what's happening on device while working in Cursor.
NOT for production use. This is a dev/beta debugging tool only. The purpose is to speed up development and reduce guesswork during mobile app debugging.
MIT License
# Build
make build
# Run (HTTP, IPv4 only)
./bin/DebugSocket_darwin_arm64 --secret=your-secret --bind-v4=0.0.0.0:8765
# Run (HTTPS, dual-stack)
./bin/DebugSocket_linux_amd64 \
--secret=your-secret \
--bind-v4=0.0.0.0:443 \
--bind-v6=[::]:443 \
--tls \
--cert=/path/to/your.crt \
--key=/path/to/your.key| Flag | Default | Description |
|---|---|---|
--secret |
(required) | Shared secret for auth |
--bind-v4 |
IPv4 bind address, e.g. 0.0.0.0:8765 |
|
--bind-v6 |
IPv6 bind address, e.g. [::]:8765 |
|
--tls |
false | Enable TLS |
--cert |
TLS certificate path | |
--key |
TLS private key path |
At least one of --bind-v4 or --bind-v6 is required.
- Copy
swift/DebugSocket.swiftinto your project - Update
serverURLandsharedSecretin the file - Initialize on app launch:
// App.swift or AppDelegate
@main
struct MyApp: App {
init() {
// Auto-connect for TestFlight/Debug builds only
DebugSocket.shared.connectIfTestFlight()
// OR: Connect only if user enabled toggle in settings
// DebugSocket.shared.initializeIfEnabled()
}
}- Stream your logs:
// In your logging function
func log(_ message: String) {
print(message)
DebugSocket.shared.log(message)
}- (Optional) Add a settings page for user control. See
swift/DebugSocketSettingsView.swiftfor a complete SwiftUI detail view with toggle, device name input, status indicator, and documentation.
- Copy
android/DebugSocket.ktinto your project - Add to
build.gradle:implementation 'com.squareup.okhttp3:okhttp:4.12.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
- Update
SERVER_URLandSHARED_SECRET - Call
DebugSocket.connectIfDebug(this)in Application.onCreate() - Log with
DebugSocket.log(msg)
Generate a self-signed cert to embed in the client:
make gencert
# or: go run gencert.go debug.doxx.netOutputs:
debugsocket.crt- PEM cert for serverdebugsocket.key- PEM key for server- Base64 to paste into client
In DebugSocket.swift:
private let pinnedCertificateBase64: String? = """
MIIB4zCCAYigAwIBAgIRAPAiLKkxJU39GLFOMYWqQNMwCgYIKoZIzj0EAwIwODEd
... (paste generated base64) ...
"""Start server with the cert:
./bin/DebugSocket_darwin_arm64 \
--secret=your-secret \
--bind-v4=0.0.0.0:8765 \
--tls \
--cert=debugsocket.crt \
--key=debugsocket.keycurl "https://debug.doxx.net/devices?secret=your-secret"[
{
"device": "abc123def456...",
"name": "Ben's iPhone 16",
"ipv4": "10.99.1.5",
"ipv6": "fd00::5",
"connected": "2026-01-26T15:00:00Z",
"log_count": 347
}
]# JSON
curl "https://debug.doxx.net/logs/abc123...?secret=your-secret"
# Text
curl "https://debug.doxx.net/logs/abc123...?secret=your-secret&format=text"# Last 5 minutes
curl "https://debug.doxx.net/logs/abc123...?secret=your-secret&since=5m"
# Regex
curl "https://debug.doxx.net/logs/abc123...?secret=your-secret®ex=Error"
# Combined
curl "https://debug.doxx.net/logs/abc123...?secret=your-secret&since=30m®ex=\[API\]"websocat "wss://debug.doxx.net/tail/abc123...?secret=your-secret"
wscat -c "wss://debug.doxx.net/tail/abc123...?secret=your-secret"| Endpoint | Method | Auth | Description |
|---|---|---|---|
/stream |
WebSocket | ?secret=X |
Phone connects, streams logs |
/tail/{device} |
WebSocket | ?secret=X |
Dev connects, receives logs |
/devices |
GET | ?secret=X |
List connected devices |
/logs/{device} |
GET | ?secret=X |
Get session logs |
/health |
GET | None | Health check |
| Param | Example | Description |
|---|---|---|
since |
5m, 1h, 30s |
Time filter |
regex |
Error|Warning |
Regex filter |
format |
json, text |
Output format |
- New connection clears previous logs
- Logs exist only while device connected
- Reconnect = fresh session
make build # linux/amd64 + darwin/arm64
make run # local dev, HTTP
make run-tls # local dev, TLS
make gencert # generate self-signed cert
make clean # remove binariesOutput: ./bin/DebugSocket_linux_amd64, ./bin/DebugSocket_darwin_arm64
See CURSOR_DEBUGGING.md for usage examples.
# Dev
./bin/DebugSocket_darwin_arm64 --secret=dev123 --bind-v4=127.0.0.1:8765
# Prod dual-stack
./bin/DebugSocket_linux_amd64 \
--secret=prod-secret \
--bind-v4=0.0.0.0:443 \
--bind-v6=[::]:443 \
--tls \
--cert=/path/to/your.crt \
--key=/path/to/your.key
# IPv6 only
./bin/DebugSocket_linux_amd64 --secret=your-secret --bind-v6=[::]:8765