Charlie and Me - Testing Native Mobile Apps with Charles Proxy

By Scott Gast

“Charles is a tool that you often use when you’re having a bad day…”
–Karl von Randow, Charles author (source)

Sorry, Karl. We love Charles and use it regularly when testing our mobile apps! It is an invaluable tool for our testing and development teams. In this blog post, I’d like to cover a few challenges we face in testing our mobile apps and how Charles helps us:

  1. Simulating poor network conditions
  2. Debugging server vs client issues
  3. Dodging server cache
  4. Modifying data in API responses

1. How does your app perform under poor network conditions?
Mobile app experiences can vary under different network conditions (e.g., WiFi, LTE, 3G, Edge, packet loss). Testing these network conditions can be difficult. For example, how will your app perform when a server response takes a long time to return, times out, or fails completely? We handle these network variables using network throttling and breakpoints within Charles.

Let’s take a look at our Promo Codes feature:

promo code

So what happens when a user tries to redeem or view their promo codes under a slow network connection?

Let’s start first by simulating a poor network connection by using Throttle Settings:

throttle settings

Adjust the network settings to the conditions you’d like to test. Under a slow network condition, our app successfully shows an onscreen loading spinner to the user while waiting for the server response:

promo code waiting on response

Next let’s test a timeout on an API request. Again, while testing a timeout could be accomplished with throttle settings or Rewrite, let’s set a breakpoint on this API request and not let the request execute:

charles app response

How does our app respond?

app request timed out

Our app lets the user know something went wrong with the user’s attempted action, and it navigates the user back to the view where the user began.

Finally, let’s test a complete network failure on an API request, again using a breakpoint but this time aborting the request when it is made:

aborting breakpoint request

Once again our app lets the user know something went wrong and navigates the user successfully to where the user began.

2. Is the issue on the server or the client?
When a tricky bug is observed on the app, one of the first things to identify is whether the issue is caused by the app or by the server response.

For example, one issue we’ve observed is sometimes our server unexpectedly responds with a mix of localized and non-localized copy:

app with localization

We use Charles to dig into the request headers as our server determines whether or not to serve localized content. View the request headers and look at the Accept-Language value the app is sending:

changing localization in headers

We have found some devices are stubborn and continue to set the wrong language-locale request header values even after the device’s language/locale settings have changed.

3. Your app’s requests hit the server cache
Like many mobile apps, we use a client-server architecture. We utilize data caching on API requests to improve response times for the clients. Many times during testing we’ll make some changes on the server wanting to see those changes on our app, but the server returns cached responses.

For example, we cache our API responses for hotel inventory.

cached inventory response edge case

The server will respond with a 304 (Not Modified) if we make the same request within a certain time frame.

304 cached response

Charles has a nice feature to turn off caching for a specific API endpoint by simply right clicking on the endpoint and selecting “No Caching” from the contextual menu:

turning off caching

It’s that easy and that powerful. Voilà: fresh results and no more 304s.

non cached response

4. The API response doesn’t have the data you need to test
At HotelTonight we have multiple test environments as well as the production environment. Sometimes when content is created on a test environment, the test server response will include a URL for the production server in the API response for that content (not ideal, we know…).

We see this with our launch modal images. Check out this test launch modal that is pointing to the production environment to get an image:

test launch modal

And here is the server response:

modal server response

One great thing about Charles is there are various ways to solve this issue:

Use whichever tool makes the most sense for you.

For this example, let’s set a breakpoint on the response and manually edit the image’s location:

setting a response breakpoint

response breakpoint result


successfully changed test launch modal

We like using Charles. A lot. Like almost every time we test our apps. We’ve mentioned multiple challenges when testing mobile apps and how we use Charles to solve these issues. However, using Charles to simply monitor the interaction between the server and the apps (as well as third party API calls) is invaluable to understanding how your app works and its performance. We especially recommend monitoring this interaction during new feature development.

We leave you with a few additional nuggets…

Switching Proxy Settings
Changing the manual proxy settings on each device to enable Charles multiple times on multiple test devices across multiple team members is painful. Likewise, finding out you forgot to disable Charles on some test device by seeing a bunch of requests added to your Charles recording session after someone else starts using that device is also less than ideal.

On Android we recommend using the Proxy Settings app to quickly toggle proxy settings for Charles. On iOS we have yet to find a good solution, although we did have limited success in creating an iOS configuration profile with the manual proxy settings already set and then installing it on the device. Doing so seemed to work for a little while, but it seems to stop working over time. If you have any iOS suggestions, let the authors know! (here)

About Charles and Getting Started
There are many sources online explaining what Charles is and how to configure it for mobile devices. There was a big SSL cert configuration change in Charles version 3.10 and higher, so most of the documentation online (apart from official Charles site) is intended for Charles version 3.9.x and earlier. To use Charles on a mobile device, we essentially follow these instructions, install a cert on the mobile device, and enable SSL proxying for our host names.

Recommended Charles Reading
Beyond DevTools: Debugging by Proxy
Debugging HTTP on an Android phone or tablet with Charles proxy for fun and profit
Tutorial: Using Charles Proxy With Your iOS Development And HTTP Debugging

Written by Scott Gast

Read more posts by Scott, and follow Scott on Twitter.

Interested in building something great?

Join us in building the worlds most loved hotel app.
View our open engineering positions.