Cache-On-Delivery: How We Made The Hybrid App Experience Seamless.

At Swiggy, we are obsessed with delivering things faster — be it food, new features or even an user’s app experience. And of course, when it comes to the best user experience, nothing beats the feel of the native app.

Having said that, a hybrid app is the need of the hour because of its smaller app size, OTA (over the air) updates and cross-platform usage, among many other benefits.

To a user, a hybrid app shouldn’t look or behave any differently than its native app equivalent, because they simply want a service that works consistently, anytime, anywhere!

In order to provide a wholesome UX while maintaining speed to market across multiple platforms, we use web pages only in low-interaction pages like FAQ, T&Cs and experimental pages. And to display these pages, we use WebView & WkWebView in Android & iOS respectively.

Are you thinking, WebViews? No..! right now?

Let’s face it, we all have a love-hate relationship with WebViews. Yes, WebViews are frustrating to deal with when it comes to its reliability across multiple devices. BUT (and yes, there’s a but), WebViews are powerful because they offer high flexibility, independent deployment cycle & scale.


Most of our web pages are optimized by server-side rendering, code splitting, image and font optimizations etc. On the app, optimization is possible by using hardware acceleration & enabling default WebViews caching.

But, are all of these optimizations good enough to provide the best user experience? Well, let’s find out by taking a look at the performance of our Help & Support web page.

no cache

In this sample, it took around 13 seconds on a good 3G connection.

~13 seconds load time

Performance issues

On closer inspection, we were able to visualize the major performance bottlenecks — downloading of JS files along with font & image assets.

Obvious solution: caching, which, well, we do! But web page caching has its own limitations, primarily the fact that cache control headers are not respected across multiple app launches & cause inconsistencies across different devices. Also, WebViews caching does not help in downloading JS and other assets during first-time page load.

Because default WebViews caching isn’t reliable across multiple app launches, we thought to ourselves, why don’t we implement our own caching mechanism?

And yes, we did!


Dreaming up the in-house caching system

To make this in-house caching system a reality, we needed to:

  1. Ensure fetching of all resources like JS, images & fonts upfront during app startup
  2. Trigger asynchronous, on-demand download of those assets
  3. Save the downloaded file locally for later use
  4. Intercept and inject the cached files into the WebView
Caching techniques at Swiggy

After dreaming of this caching system and a little white-boarding, this approach seemed absolutely clear. Now was the time for action.


Implementing the caching system

Implementation came with its own set of questions, but we were able to boil it down to the big 3.
1. How to intercept requests & serve the locally downloaded content? 
2. How to deal with dynamic JavaScript files, fonts and image assets?
3. How to purge the cache?

The ‘Eureka!’ Moment

While digging for solutions, we stumbled upon Android’s documentation about WebViewClient which talks about shouldInterceptRequest() API.

This API lets us intercept URL requests, overriding this method notifies us whenever there is a JavaScript, image or font asset download request. Sweet!

Armed with the knowledge on how to intercept the requests and serve cached files locally, we focused on defining a clear contract between portal & app team on how & when to download and purge the assets.

The Implementation

Build process of the web app makes use of WebPack, a JavaScript bundler. To reduce the initial boot time, heavy chunks of JavaScript that aren’t critical are loaded dynamically using code-splitting. Once WebPack builds all these files, we generate a manifest containing source mapping of all the assets handled by it (JavaScript, CSS, Fonts, Images file etc).

Finally, we served this information using a simple REST resources API.

Resource Config Manager: syncs the latest resource from Swiggy servers and makes a copy locally in the device.

Typical response from our resource API

We maintain resource config version numbers and feature-wise version numbers so that whenever there is a version mismatch, we flush the old assets & download the new ones. We also check for the hash-code for each asset so that we download only the new resource which got added into the list.

The Interceptor: module intercepts the web page requests and serves the local cache version if available.
Download Manager: helps download all qualified images, fonts, JavaScript assets etc and saves them locally in a temp folder for later access. 
Cache Manager: maintains the cache and its expiry as per the configuration.

It’s time for results!

These simple optimization techniques gave us a stunning ~96% performance boost for Help and Support page. Wow!

with manual caching
Help and Support | Before vs After
Help & Support | Performance comparison on different networks

Naturally, with such positive results, we felt confident enough to extend these solutions to other areas of the app.

In fact, we made use of these techniques on the on-boarding pages of the recently launched Swiggy SUPER and we were (not) surprised that it worked just as beautifully!

Swiggy Super | Before vs After

With Swiggy SUPER, we saw a 79% performance boost on a good 3G connection.

Swiggy Super | Performance comparison on different network

This kind of manual caching technique works really well as long as we download the assets files upfront.

Manual caching still comes with few caveats, such as strict API contract between portal and apps team, invalidating the stale cache, accounting for the API failures, bundle download failures, corruption of bundle etc.

However, from our own experience, we’re sure that it’s worth the effort to write and maintain manual caching to gain the larger performance benefits and for having a seamless experience on hybrid apps.

As you read this, we continue our experiments with the WKWebView for similar performance gains in iOS and it turns out it’s not very straightforward.

Well, that’s for another story! In the meanwhile, watch out Swiggy Bytes blog for more stories on all the scoop on product & engineering at Swiggy. (And tell us which ones you like!)


Better performance for the win!

Improving the performance of the Help & Support, among other sections, via caching made way for such a smooth experience that it became the talk of the Twitter town!


Behind the optimization techniques were the ideas, hard work, and collaboration among this quartet, Anand Kumar Kurapati, Kumar Reddy, Abey Alex, and Aayush Agrawal. Kudos!

If you’re interested in working on challenges like this one, join our team. We are hiring! I’m on Twitter, whenever you’d like to talk about food, tech or both.