Engaging — Feel like a natural app on the device, with an immersive user experience.

We at PregBuddy, built our mobile website (https://app.pregbuddy.com) as a Progressive Web App (PWA). Using just 300 KB of data to install, the PWA is at least 25x smaller than downloading the Android app. Repeat visits use as little as 10 KB. This low data consumption translates into a 3–4 seconds first visit and less than a second for repeat visits on 2G and 3G networks — an ideal solution for millions of users.

We chose ReactJs as the framework, which is emerging as a great solution for building performant interfaces for the web and other platforms. We have also used Webpack which bundles our client-side code (JavaScript, CSS, etc) into a single JavaScript file (bundle.js). For the UI, we have used the Material UIlibrary for React, which gives an immersive and native-app like feel for the web.

How we optimized Client Side Caching ?

Service Worker

In order to make our website progressive, integrating a service worker is a necessary task. A service worker is a worker thread run by the browser in the background, separate from the web page. It opens the door to features that don’t need a web page or user interaction like push notifications, background sync, network control, etc. With Service Workers, we can intercept/hi-jack every network request and serve a response from cache even when the user is offline.

Caching strategies

All resources cannot be served with the same caching strategy. For example, our HTML pages change frequently and hence, the cache entries become stale. We need to update this content frequently. On the other hand, images can be served from the cache without needing to update for a long time. We have maintained two caches, one mainly for the HTML and bundled JS and other for static content like images.

How is the PWA helpful ?

Offline support

Since the JS and CSS files are already cached, it helps us to serve our pages even when the client network is down. Users can now browse our site in offline mode, which makes the experience much better. Although, the users cannot make any new API calls like profile updation or fetching new articles, but they can view the already cached content.

Saves network bandwidth

Serving majority of redundant files through service workers also helps loading our site faster for subsequent calls. Since, we are not making the call again and again, it frees up a lot of network bandwidth for other critical calls that can be served instantly.

Making the loading of images faster and smoother

We have compressed the images for lower bandwidth usage and used Amazon CloudFront service for static assets delivery like images. This along with Lazy Loading of images gives a much smoother experience.

How did we manage to maintain the feel of a Native App ?

Material Design

Using the Material-UI library for building the front-end for the app helped us to replicate the UI of our android app, which has been designed according to the Google Guidelines. It helped us deliver a similar experience in terms of UI and UX to our users.

Native apps use splash screen to hide the slow loading of home screen. Web never had this luxury and there was a blank page staring at the user before home screen could load up. Now the latest version of Chrome supports generation of a splash screen that radically improves the launch experience and perceived performance of the web app.

Add to Home Screen feature

One more cornerstone of a truly immersive experience is a full screen, standalone experience launched right from the home screen. This is what the Add to Home Screen (ATHS) prompt allows us to do. When the user chooses to add to home screen, the browser creates a high-quality icon on the home screen based on the metadata in the Web Manifest. The ATHS prompt is shown automatically to the user based on a heuristic that is specific to each browser.

User Engagement using Push Notifications

For increasing user engagement, we have implemented notifications using the FCM(Firebase Cloud Messaging). We seek user’s permission before sending out any push notification for better UX.

A small trick to get the first load faster — We have preloaded some of our static resources like images for faster first paint time. Here is the link to an awesome blog, which talks in depth about prefetching and preloading. It can be done as follows:

Serving our pages

We have used a static hosting along with a hack to serve the pages for the PWA, without the content being server rendered. We have used a free static hosting platform to serve the files for our app. Once the bundled js, index.html and required assets are served to the client, all the other pages can be shown via client side routing using the React Router. When a user hits a link of the app directly, we redirect the user to the index page and rest of client side routing is taken care of, by the React Router. The rules for redirects are written on a redirects file, which is mentioned later in the blog. This approach helped us to save the cost of a server, which is important for an early stage startup like us.

Indexing our articles

For indexing the articles, we have created a separate html file, which is served to the user on directly hitting the article links and the content is fetched through plain JS. The reason of using this workaround is that, GoogleBot is unable to crawl through complex JS and renders a blank page at the WebMasters. We found out that the React Router confuses the google bot and therefore doesn’t allow us to index the pages. So, by adding the redirects for articles, we were able to index the articles, which is the MVP feature of our app.

This is how the redirects file looks like:

These were some insights from our PWA and how we had gone about building it. Please feel free to comment if you have newer techniques, as well as ask questions. And, yeah! If this post helps you please do recommend and spread the word!