Charles Proxy / Proxyman Integration for Mobile App Network Request Debugging
Without a proxy tool, debugging the network layer is reduced to print(response) in code and hoping to see something. Charles Proxy and Proxyman intercept all device traffic: you see real headers, request and response bodies, timing, redirects, and websockets. This is the standard tool for debugging and testing API integrations.
Charles Proxy Setup
Installing root certificate on iOS:
- Charles: Help → SSL Proxying → Install Charles Root Certificate on iOS Simulator / Mobile Device
- On device — Settings → General → VPN & Device Management → install the profile
- Settings → General → About → Certificate Trust Settings → enable trust for Charles Proxy CA
After this, Charles can see HTTPS traffic. Without certificate trust, only metadata is visible, the body remains encrypted.
Setting up Wi-Fi proxy on device: the same Wi-Fi as on Mac → Manual proxy → Mac IP address, port 8888 (Charles default).
SSL Proxying List in Charles: by default, not all domains are decrypted — you need to add * or specific hosts through Proxy → SSL Proxying Settings → Include.
Proxyman as an Alternative
Proxyman is a more modern macOS tool with a native SwiftUI interface. It sets up faster, has a cleaner UI, and works better with WebSocket and HTTP/2. It supports automatic certificate installation through Proxyman Certificate Assistant — just a few clicks instead of manual profile setup.
Key Proxyman features:
- Script editor: intercept request/response and modify via JavaScript (simulate backend responses without server changes)
- Breakpoints: pause request before sending, edit, continue
- Map Local / Map Remote: redirect requests to another URL or to a local file (mocking)
Working with Certificate Pinning
If the app uses certificate pinning, Charles/Proxyman won't see traffic — NSURLErrorDomain -1200 or SSLPeerUnverifiedException. Solution for dev/QA builds:
iOS: conditionally disable pinning via #if DEBUG:
#if DEBUG
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
#else
// production pinning logic
#endif
Android: network_security_config.xml with a separate debug config:
<!-- res/xml/network_security_config.xml (debug) -->
<network-security-config>
<debug-overrides>
<trust-anchors>
<certificates src="user"/>
</trust-anchors>
</debug-overrides>
</network-security-config>
With this config in debug builds, the system trusts user CAs (where Charles/Proxyman certificate is added), while in release it doesn't.
Typical Use Cases
- Verifying correct authorization headers (Bearer token, API key)
- Debugging multipart/form-data file uploads
- Testing behavior with slow connections (throttling in Charles: Proxy → Throttle Settings)
- Checking error HTTP response handling (Map Local → substitute 500 response)
- Debugging GraphQL requests and WebSocket frames
Timeline
Setting up Charles or Proxyman for a specific project, including SSL certificates, debug network security config, and team documentation — 4 hours to 1 day.







