Charles Proxy Tutorial for iOS

Learn how to use Charles for iOS and macOS to inspect encrypted and unencrypted network traffic for both your own apps and third-party apps. By Irina Galata.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Snooping on Someone Else’s App

If you’re like most developers, you’re curious how things work. Charles enables this curiosity by giving you tools to inspect any app’s communication.

Go to the App Store on your device and find and download Weather Underground. This free app is available in most countries. If it’s not available, or you want to try something else, feel free to use a different app.

You’ll notice a flurry of activity in Charles while you’re downloading Weather Underground. The App Store is pretty chatty!

Once the app is installed, launch the app and click the broom icon in Charles to clear recent activity.

Tap Search, enter the zip code 90210 and select Beverly Hills as your location. Then, tap View. If you were to use your current location, the URL that the app fetches could change if your location changes, which might make some later steps in this Charles Proxy tutorial harder to follow.

There are tons of sites listed in the Structure tab! This is a list of all activities from your iOS device.

Activities structured in Charles Proxy

Switch to the Sequence tab and enter weather in the filter box to show only weather traffic.

You’ll now see a few requests to api.weather.com. Click one.

The Overview section shows some request details, but not much, as you haven’t enabled SSL proxying for api.weather.com.

Click Proxy ▸ SSL Proxying Settings and Add. Enter api.weather.com for the Host, leave Port empty and click OK to dismiss the window.

SSL Proxying Settings

Back in the Weather Underground app, pull down to refresh and re-fetch data. If the app doesn’t refresh, you might need to kill it from the multitasking view and try again.

Huzzah! Charles shows unencrypted requests!

Charles unencrypted requests

Look for a request with a URL containing /v3/wx/observations/current. This contains the payload used to populate the weather screen.

Modifying the Response

Time to have some fun and change the data before the app gets it. Can you get the app to break or act funny?

In Charles, right-click the request within the Sequence list, and click Breakpoints in the pop-up list. Then, click Proxy ▸ Breakpoint Settings, double-click the breakpoint you added and make sure to empty Query:

Charles breakpoints

This ensures you intercept any request containing this path, regardless of the query parameters, and Charles will pause and let you edit both the request and response.

Again on your device, pull down to refresh the app.

A new tab titled Breakpoints should pop up with the outgoing request. Click Execute without modifying anything. A moment later, the Breakpoints tab should again reappear with the response.

Click the Edit Response tab near the top. At the bottom, select JSON text. Scroll down and find temperature and change its value to something unrealistic like 98000. Click Execute.

Note: If you take too long editing the request or response, the app may silently time out and never display anything. If the edited temperature doesn’t appear, try again a little more quickly.

Modified Temperature

98000°F is incredibly hot! It seems like the app doesn’t adjust the font size for temperatures with more than five digits. That’s a definite one-star rating. ;]

Back in Charles, delete the breakpoint you set by going to Proxy ▸ Breakpoint Settings.

Uncheck the entry for api.weather.com to temporarily disable it, or highlight the row and click Remove to delete it. Pull down to refresh, and the temperature should return to normal.

Simulating Slow Networking

Now, you’ll simulate slow networking. Click the Tortoise icon to start throttling. Next, click Proxy ▸ Throttle Settings to see available options. The default is 56 kbps, which is pretty darn slow. You can also tweak settings here to simulate data loss, reliability issues and high latency.

Try refreshing the app, zooming the map and/or searching for another location. Painfully slow, right?

It’s a good idea to test your own app under poor network conditions. Imagine your users on a subway or entering an elevator. You don’t want your app to lose data, or worse, crash in these circumstances.

Apple’s Network Link Conditioner provides similar throttling capabilities, yet Charles allows for much finer control over network settings. For example, you can apply throttling to only specific URLs to simulate just your servers responding slowly instead of the entire connection.

Remember to turn off throttling when you’re done with it. There’s nothing worse than spending an hour debugging only to discover you never turned off throttling!

Troubleshooting Your Own Apps

Charles Proxy is especially great for debugging and testing your own apps. For example, you can check server responses to ensure you have JSON keys defined correctly and expected data types are returned for all fields. You can even use throttling to simulate poor networks and verify your app’s timeout and error-handling logic.

Before you build and run, add the following two hosts to Charles’ SSL Proxying Settings as you learned to do above:

  • www.countryflags.io
  • restcountries.eu

Then, build and run the sample app on your device or simulator.

Starter project app

This app shows a list of all the countries with some short info on each of them. But what happened to the icons? It looks like there was an error decoding the data from the service. You’ll see if Charles can help you get to the bottom of the problem.

Switch to Charles Proxy (on your Mac) and in the Sequence tab, change the filter to countryflags.io. You’ll see that all the requests failed with a 404 error, as no image was found for any country:

Charles Proxy 404 Response

As you can see in Charles, you use a three-letter code to fetch an image of a country flag. But according to countryflags.io, you need to use a two-letter country code to get it working!

Now, change the filter in the Sequence tab to restcountries.eu to monitor what data you receive from this service to see whether you can get the code:

[{
    "name": "Afghanistan",
    "topLevelDomain": [".af"],
    "alpha2Code": "AF",
    "alpha3Code": "AFG",
    "callingCodes": ["93"],
    "capital": "Kabul",
    "altSpellings": ["AF", "Afġānistān"],
    "region": "Asia",
    "subregion": "Southern Asia",
    "population": 27657145,
    "latlng": [33.0, 65.0],
    "demonym": "Afghan",
    "area": 652230.0,
    "gini": 27.8,
    "timezones": ["UTC+04:30"],
    "borders": ["IRN", "PAK", "TKM", "UZB", "TJK", "CHN"],
    "nativeName": "افغانستان",
    "numericCode": "004",
    "currencies": [{
        "code": "AFN",
        "name": "Afghan afghani",
        "symbol": "؋"
    }],
...

The response contains two country codes called alpha2Code and alpha3Code. In Xcode, open Country.swift and take a closer look at CodingKeys. Indeed, the code was wrong!

Replace the following:

case code = "alpha3Code"

With:

case code = "alpha2Code"

Build and run the app again.

Fixed CountryFlags App

Success! This is a trivial but good demonstration of how viewing networking traffic in Charles Proxy can help you uncover bugs in your networking code.