how to set up Charles Proxy with a cloud phone
how to set up Charles Proxy with a cloud phone
if you want to inspect HTTPS traffic from a cloud Android phone in 2026, Charles Proxy remains one of the easiest tools to set up. it sits between the cloud phone and the internet, captures every HTTP and HTTPS request, lets you inspect headers and bodies, and supports SSL decryption when the phone trusts the Charles root certificate. the cloud-phone twist is the network path: the phone runs in Singapore, your laptop runs wherever you are, and Charles needs to be reachable from the phone over the network.
this guide covers the full setup: install Charles, configure it for remote-device proxying, install the Charles root CA on the cloud phone, set the phone’s WiFi proxy, decrypt HTTPS, and tear down cleanly when done.
why HTTPS inspection on a cloud phone
three categories of work need real HTTPS inspection on real Android. mobile API debugging (your backend is misbehaving and you want to see the exact request your app sent). third-party SDK auditing (verify what an analytics SDK is sending and where). security testing (catch credential leaks, weak TLS, or tokens that should be hashed but aren’t).
Charles makes all three trivial once you have the right network path between your laptop and the cloud phone.
for context on cloud phone basics, see cloud phone vs physical Android device and how to set up ADB on cloudf.one.
prerequisites
on your laptop: Charles Proxy 4.6 or newer (free trial; paid licenses are inexpensive). on the cloud phone: Android 7.0 or newer with developer options enabled.
# install Charles on macOS
brew install --cask charles
# on Linux
sudo apt install charles-proxy
step 1: configure Charles to listen on a routable port
by default Charles listens on 127.0.0.1:8888. for cloud phones, the phone needs to reach Charles, so listen on 0.0.0.0:8888 instead.
in Charles, go to Proxy menu, then Proxy Settings, then Proxies tab. set HTTP Proxy port to 8888 and uncheck “only allow connections from localhost.” apply and restart Charles.
find your laptop’s IP. on a typical home network this is something like 192.168.1.42 or 10.0.0.5. note this IP; the cloud phone will point at it.
step 2: expose your laptop to the cloud phone
cloud phones run in Singapore. your laptop is somewhere else. there are three ways to bridge this network gap.
option A: ngrok TCP tunnel. simplest for one-off debugging.
ngrok tcp 8888
ngrok prints a public hostname like tcp://2.tcp.ngrok.io:14837. that becomes the proxy host:port you’ll set on the cloud phone.
option B: cloudf.one reverse-tunnel. cloudf.one supports reverse tunnels from your laptop into the cloud phone session for exactly this case. consult your dashboard’s tunnel docs for the exact CLI command; the pattern is cloudfone tunnel reverse --local 8888 --device $DEVICE_ID.
option C: VPN to your home or office network where the cloud phone can reach Charles directly. only works if your home network is publicly addressable, which most are not.
for the rest of this guide, assume you used option A or B and your proxy endpoint is tcp://proxy.host.example:8888.
step 3: configure the cloud phone’s WiFi proxy
on the cloud phone via cloudf.one screen control:
- open Settings, then Network and internet, then Internet.
- long-press the active WiFi network (the cloud phone’s virtual WiFi).
- tap Modify, then Advanced options.
- set Proxy to Manual. enter the proxy hostname (e.g.
2.tcp.ngrok.io) and port (e.g.14837). - save.
alternatively, set the proxy via ADB:
adb -s adb-sg.cloudf.one:5555 shell settings put global http_proxy proxy.host.example:8888
reboot the WiFi for the setting to take effect:
adb -s adb-sg.cloudf.one:5555 shell svc wifi disable
adb -s adb-sg.cloudf.one:5555 shell svc wifi enable
step 4: install the Charles root CA on the cloud phone
HTTPS decryption requires the cloud phone to trust the Charles root CA. without this, all HTTPS traffic shows up encrypted in Charles.
in Charles, go to Help menu, then SSL Proxying, then Save Charles Root Certificate. save the .pem file.
push it to the cloud phone:
adb -s adb-sg.cloudf.one:5555 push charles-ssl-proxying-certificate.pem /sdcard/Download/
on Android 14+, install via Settings, Security and privacy, More security and privacy, Encryption and credentials, Install a certificate, CA certificate. browse to /sdcard/Download/ and select the cert. you’ll see a warning that user-added CAs only work for apps that opt in to user-installed CAs (per Network Security Config).
step 5: decrypt HTTPS for specific hosts
in Charles, go to Proxy menu, then SSL Proxying Settings, and add the hosts you want to decrypt. use wildcards: *.cloudf.one decrypts everything on the cloudf.one domain.
Charles defaults to NOT decrypting any host. you must explicitly opt in per host. this is intentional: random decryption breaks pinned apps and bloats Charles’ session view.
step 6: handle apps that pin certificates
some apps (banking, fintech, security-critical) implement certificate pinning. they validate the server certificate against a pinned hash, ignoring the system trust store. these apps will refuse to talk to the proxy.
three workarounds in order of increasing intrusiveness.
first, opt-in via Network Security Config. if you control the app, add a debug Network Security Config that trusts user CAs. the Android docs cover the syntax.
second, use Frida to patch the pinning check at runtime. our Frida hooking post covers the technique. this is for security research only.
third, use a debug build of the app where pinning is disabled.
apps you do not control and that pin certificates simply cannot be inspected.
step 7: verify the setup
on the cloud phone, open Chrome and visit https://api.example.com. Charles should show a row for the request. if SSL Proxying is configured for that host, you’ll see decrypted JSON in the contents pane.
if you see “SSLHandshake: Received fatal alert: certificate_unknown,” the cert is not trusted. re-check step 4.
if you see “Connect failed: Connection timed out,” the cloud phone cannot reach Charles. re-check step 2 (the network path).
tear down
when done, remove the proxy from the cloud phone:
adb -s adb-sg.cloudf.one:5555 shell settings put global http_proxy :0
adb -s adb-sg.cloudf.one:5555 shell svc wifi disable
adb -s adb-sg.cloudf.one:5555 shell svc wifi enable
remove the Charles root CA via Settings, Security, Encryption and credentials, User credentials.
stop ngrok or the cloudf.one reverse tunnel.
Charles vs mitmproxy: when to use each
Charles has a polished UI, an easy-to-learn interface, and great session manipulation features. mitmproxy is open source, scriptable in Python, and runs headless. for interactive debugging, Charles is faster. for automated traffic rewriting in CI or scripted tests, mitmproxy is better. our mitmproxy guide covers the alternative.
try Charles on a real Singapore cloud phone
register for a free trial for a one-hour cloud phone token. set up Charles + ngrok, install the cert, watch HTTPS traffic from a real Singapore Android device. once confirmed, scale to a paid plan for ongoing API debugging work.
frequently asked questions
does Charles work with Android 14 user CAs?
yes, with the caveat that apps must opt in to user CAs via Network Security Config to trust them. system-trusted CAs work without opt-in. for app testing, modify the debug Network Security Config; for production traffic, use a system-trusted CA via root (which cloud phones do not provide by default).
can Charles intercept WebSocket traffic?
yes. WebSocket frames appear in the Charles session view. SSL Proxying applies to wss:// the same way it does to https://.
what about apps using certificate pinning?
cert-pinned apps refuse the Charles cert. workarounds include Network Security Config opt-in, Frida runtime patching, or a debug build with pinning disabled.
is Charles legal to use on cloud phones?
inspecting traffic from devices and apps you own or control is legal. inspecting traffic from third-party services without permission may violate terms. Charles itself is a legitimate developer tool used industry-wide for QA and debugging.
how do I script Charles for CI?
Charles is GUI-first. for CI, mitmproxy is the better choice because it runs headless and scripts in Python. see our mitmproxy guide.