This repository contains helper scripts and a mitmproxy addon to easily intercept HTTP(S) traffic from Android emulators and iOS simulators using mitmproxy. It also provides control endpoints to start/stop recording and dynamically map local responses to specific request URLs.
mitmproxy(v9+ recommended)- Android Emulator with root access
- iOS Simulator (via Xcode)
- macOS or Linux
brew install mitmproxysudo apt update
sudo apt install mitmproxyVerify installation:
mitmdump --version- Emulator must be rooted (use x86 or ARM images that support root).
- Emulator must be started using
-writable-systemflag to be able to perform anadb remount - Android SDK + ADB installed and configured in your
$PATH.
- Launch emulator with writable system
You should find an emulator that can be rooted using adb root. In most cases these are the emulators WITHOUT Google Play Services.
Launch the emulator with a writable-system partition
# Find name of AVD
emulator -list-avds
emulator -avd <name of avd> -writable-system- Run the script:
chmod +x android-certificate-install.sh
./android-certificate-install.shThis script will:
- Ensure the mitmproxy CA certificate exists as
~/.mitmproxy/mitmproxy-ca-cert.cer - Push the certificate to the emulatorβs system certificate store (using the correct method for Android version)
- Configure proxy settings to forward traffic to mitmproxy on host (
10.0.2.2:8080) - Reboot the emulator to apply changes
xcode-selectmust point to an installed Xcode- You may need to manually trust the certificate in:
Settings > General > About > Certificate Trust Settings
If simctl fails:
sudo xcode-select -s /Applications/Xcode.appchmod +x ios-certificate-install.sh
./ios-certificate-install.shThis will:
- Boot or select a running iOS simulator
- Install mitmproxy CA certificate (
mitmproxy-ca-cert.pemcopied asmitmproxy-ca-cert.crt) into the simulator keychain - Set system proxy on the
Ethernetinterface (used by the simulator) - Exit with an error if automatic install fails (no manual fallback)
If you want your entire macOS system to trust mitmproxy (for capturing CLI tools or other apps):
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain mitmproxy-ca-cert.crtThe file proxy-session-controller.py is a mitmproxy addon that:
- Records flows while a session is active
- Allows you to start/stop recording via HTTP API
- Lets you map specific URLs to local mock response files
Start mitmproxy with the addon:
mitmdump -p 8080 -s proxy-session-controller.pyThis starts mitmproxy with:
- Listening port:
8080 - Control API:
http://localhost:9999
Running mitmproxy in background with the addon:
screen -dm mitmdump -p 8080 -s proxy-session-controller.pyAbout screen:
The screen command is a terminal multiplexer that lets you run multiple sessions within a single terminal window. By starting mitmdump in a detached screen session, you can keep it running in the background while continuing to use your terminal for other tasks.
This approach is especially useful in CI/CD environments, where you don't want a pipeline step to hang because mitmdump is occupying the terminal interactively.
You can re-attach to the running session at any time using:
screen -rThis allows you to check logs or interact with the process as needed. To verify if mitmdump is running, you can use:
pgrep mitmdumpThis will return the process ID if it is running.
When using mitmproxy with emulators and simulators, a lot of background network traffic is generated by the operating system and system apps (such as Google or Apple services). Most of this traffic is not relevant for app testing or debugging and can clutter your logs.
The IGNORED_ENDPOINTS list in proxy-session-controller.py contains hostnames for common Android and iOS system services that are automatically filtered out. Requests to these endpoints are not recorded or included in your output files.
Examples of ignored endpoints:
- Android:
gstatic.com,googleapis.com,clients4.google.com,play.googleapis.com, etc. - iOS:
apple.com,icloud.com,itunes.apple.com,push.apple.com, etc.
Why is this useful?
- Reduces noise in your captured network logs.
- Makes it easier to focus on your appβs actual API calls.
- Prevents large, irrelevant log files from being generated.
If you want to capture all traffic, you can remove or modify the IGNORED_ENDPOINTS list in the script.
These endpoints allow dynamic control of recording and local response mapping.
# Default recording, outputs to flows.json
curl -X POST http://localhost:9999/start_recording
# Optional name for recording, outputs to "name".json
curl -X POST http://localhost:9999/start_recording \
-H "Content-Type: application/json" \
-d '{"name": "output_file_name"}'curl -X POST http://localhost:9999/stop_recordingThis saves all recorded flows to the file specified when starting the recording (e.g., output_file_name.json), or to flows.json if no name was provided.
curl -X POST http://localhost:9999/map_local/enable \
-H "Content-Type: application/json" \
-d '{"url": "https://api.example.com/data", "file_path": "/absolute/path/to/response.json"}'Any requests matching the URL will return the contents of response.json.
curl -X POST http://localhost:9999/map_local/disable \
-H "Content-Type: application/json" \
-d '{"url": "https://api.example.com/data"}'curl -X POST http://localhost:9999/map_local/disable- For Android: Emulator must be rooted to modify
/system/etc/security/cacerts - For iOS:
simctl keychainmay not work on all Xcode versions. If it fails, the certificate will be opened manually for trust.- You may need to manually trust the cert in the iOS Simulator settings
- For macOS:
- You can manually install the CA cert into the system keychain to capture macOS traffic too
- The local mapping only works if the URL matches exactly, including protocol and query params.
Each captured flow includes the method, URL, headers, and parsed JSON request/response body if possible.
[
{
"request": {
"method": "GET",
"url": "https://api.example.com/data",
"headers": { ... },
"body": {}
},
"response": {
"status_code": 200,
"headers": { ... },
"body": { "result": "ok" }
}
}
]You can integrate mitmproxy recording into your mobile test lifecycle to verify network behavior during test execution.
- Start mitmproxy with the addon (before your test suite):
mitmdump -p 8080 -s proxy-session-controller.py- Start recording flows (before your test begins):
curl http://localhost:9999/start_recording-
Run your UI/E2E test that performs network requests from the Android emulator or iOS simulator.
-
Stop recording after the test is finished:
curl http://localhost:9999/stop_recording- Validate the output in
flows.jsonusing a custom validation script.
import json
with open("flows.json") as f:
flows = json.load(f)
expected_url = "https://api.example.com/data"
matched = any(flow["request"]["url"] == expected_url for flow in flows)
assert matched, f"Expected request to {expected_url} not found!"
print("[β] Network request verified.")In your test framework (e.g., XCTest for iOS, Espresso or UIAutomator for Android), you can:
- Trigger
/start_recordingin the test setup phase - Run the UI interaction
- Trigger
/stop_recordingin the test teardown - Run a validation script after the test completes
This allows you to assert that expected network calls were made, validate request payloads, and check response data without needing to modify your app code.
To reset Android emulator proxy:
adb shell settings put global http_proxy :0To reset macOS proxy:
networksetup -listallnetworkservices | tail +2 | while read -r interface; do
networksetup -setwebproxystate "$interface" off
networksetup -setsecurewebproxystate "$interface" off
doneFeel free to extend this tool with more proxy automation, better cert handling, or a simple UI for the control endpoints.