Charles is a desktop HTTP and SOCKS proxy that records the traffic of browsers, desktop apps and phones, and decrypts HTTPS for the hosts you choose. To make that traffic leave from a proxy IP instead of your own, open the external proxy settings in Charles's Proxy menu, enter your order's host, port, username and password for HTTP and HTTPS, and save. Charles still records everything; the upstream proxy only changes where it exits.

Charles is a GUI application we could not run on our test machines, so the settings below follow Charles's own documentation; where the docs name no exact label, the step says what the setting does.

Before you start

  1. Open your order in the dashboard at https://app.proxyhive.io and copy HOST, PORT, USERNAME and PASSWORD for the HTTP proxy.
  2. Confirm the proxy works without Charles: curl -x http://USERNAME:PASSWORD@HOST:PORT https://api.ipify.org. If it fails here, Charles will not fix it; the curl guide has the flags.
  3. Decide what you are debugging. On the computer itself, Charles's Proxy menu switches its system and browser proxy configuration on and off. A phone needs its Wi-Fi proxy set to your computer's address and the port shown in Charles's Proxy Settings.

Set the external proxy

Charles's documentation calls this External Proxies. In the Proxy menu, open the external proxy settings, then:

  1. Enable the proxy for HTTP and enter HOST and PORT.
  2. Enable it for HTTPS and enter the same HOST and PORT. Charles keeps separate entries so http:// and https:// requests could go to different proxies; for one provider IP they are the same.
  3. Tick authentication for each and enter USERNAME and PASSWORD. Charles supports Basic and NTLM; a proxy username and password from a dashboard is Basic.
  4. Optionally add hosts to the bypass list: whitespace-separated, each with an optional port, wildcards allowed. Your own API, a local mock server and your company's single sign-on page usually belong here.
  5. Leave SOCKS empty unless you need it. Charles sends all non-HTTP(S) traffic, such as port forwarding, through a SOCKS proxy if one is set.

If you skip the credentials, Charles passes the upstream's authentication challenge back to the client, so a browser will prompt you for them. That is fine for a quick look, but scripted clients and phone apps usually cannot answer, so store the credentials in Charles.

SSL proxying

Without SSL proxying, Charles forwards encrypted traffic to the server without decrypting it, so you learn where an app connects but not what it sends. To read it:

  1. Install and trust the Charles root certificate: Help > SSL Proxying > Install Charles Root Certificate on macOS and Windows, then set it to trusted in Keychain Access on macOS.
  2. Firefox keeps its own store: browse to https://chls.pro/ssl through Charles and tick Trust this CA to identify websites. For Java, save the certificate with Help > SSL Proxying > Save Charles Root Certificate and import it; Java may need it again after each upgrade.
  3. On a phone, browse to https://chls.pro/ssl while it is proxied through Charles. On iOS 10.3 and later, also enable full trust under Settings > General > About > Certificate Trust Settings.
  4. In the SSL Proxying Settings, add only the hosts you are debugging, or * for everything. Browser sessions already open may need a restart to pick up the change.

Keep the host list short. Every decrypted host gets a certificate Charles issued, so anything that checks certificates strictly fails there and nowhere else.

What still breaks

  • Android apps you did not build. Since Android 7, apps trust user-installed certificates only if their network security configuration says so. Charles's docs say plainly that SSL proxying works with apps you control.
  • Pinned apps. An app that pins its server's key rejects the Charles certificate whatever the device trusts. Remove the host from SSL proxying and you still see its tunnel.
  • Bot defences. Decrypted traffic reaches the site over Charles's own TLS connection, so its TLS fingerprint differs from the app's. A response that changes only under SSL proxying is worth comparing with the tunnel left closed.

With ProxyHive

Phone and desktop apps that change by country are the usual reason to chain Charles to a proxy. An ISP proxy gives you a static address on a named consumer carrier in the location you pick at checkout, with username and password authentication, so the app sees one stable, local-looking IP for the whole session. If you want the same workflow scripted and open source, mitmproxy does it from the command line.