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 mitmproxy
sudo apt update
sudo apt install mitmproxy
Verify installation:
mitmdump --version
- Emulator must be rooted (use x86 or ARM images that support root).
- Emulator must be started using
-writable-system
flag 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.sh
This 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-select
must 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.app
chmod +x ios-certificate-install.sh
./ios-certificate-install.sh
This will:
- Boot or select a running iOS simulator
- Install mitmproxy CA certificate (
mitmproxy-ca-cert.pem
copied asmitmproxy-ca-cert.crt
) into the simulator keychain - Set system proxy on the
Ethernet
interface (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.crt
The 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.py
This 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.py
About 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 -r
This allows you to check logs or interact with the process as needed. To verify if mitmdump
is running, you can use:
pgrep mitmdump
This 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_recording
This 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 keychain
may 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.json
using 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_recording
in the test setup phase - Run the UI interaction
- Trigger
/stop_recording
in 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 :0
To reset macOS proxy:
networksetup -listallnetworkservices | tail +2 | while read -r interface; do
networksetup -setwebproxystate "$interface" off
networksetup -setsecurewebproxystate "$interface" off
done
Feel free to extend this tool with more proxy automation, better cert handling, or a simple UI for the control endpoints.