How to Make an R Shiny Progressive Web App

Shiny from R-Studio (PWA)

is a programming language that has been around for long time. You can read about it here:

Personally, I discovered it when working at Bell Labs in the mid-80’s. I was exploring the really cool “exp tools” the AT&T guys published for internal use one day. A program named “S” showed up on one day… hmm, what’s this?

I ran it and got a “>” prompt. Very useful, eh? Well, I poked around a bit and discovered it was vector based math program. Then promptly forgot about it for about 20 years. While I was ignoring it, “S” turned into “R” and the “Comprehensive R Archive Network (CRAN)” was created. This open source project is truly amazing.

Long story short, I messed around with R off and on, the syntax just made my brain hurt. For a while I did things the “Python way” using SciPy and plotted some stuff. After getting burned by writing an app using Python 3.4 which didn’t work on Python 2.7, I decided to try R again. Things had changed a lot.

RStudio has been available for a few years, this is a really nice IDE for R. Additionally, RStudio has developed Shiny server. Using Shiny, you can add a modern UI to your R program. The UI runs in a browser and uses Bootstrap and jQuery underneath. The web page is served by the Shiny server and communicates over a web socket with a R executable running on the server.

You can test a Shiny program in the IDE, however the web app must be hosted for others to use it. RStudio provides for you to host your apps. My apps have a small audience, so I’m using the rocker/shiny docker container in a small AWS Lightsail instance. It runs along side the main site using port 8082. The main site is served by Apache. Apache must proxy port 8082 to the Shiny server. I hope to describe how this is done in future post.

Anatomy of a Shiny App

In the end, we want a Progressive Web Shiny App. We’ll start with a regular web app then convert it to a PWA. Many options for creating Shiny apps exist, which can be confusing. I’ll use the simplest method as an example. This method uses only R language files which are converted to HTML automatically by the Shiny server. For more details about how this works, please consult the Shiny docs.

Single File Shiny App

Just create a new Shiny Project, you will get a sample application

This will create app.R, which is a fully functional Shiny app. With app.R selected, run the app:

RStudio will start a local server and open the app in the Viewer. You should be able interact with it. We’ll take a look at it later. Let’s convert it to a PWA.

Requirements for a PWA

A PWA must have a main HTML file (usually index.html) which use the following types of files properly:

  • manifest.json
  • icons
  • Service Worker JavaScript file

Starting with a 512x512 px PNG image, I used Web App Manifest Generator to create the manifest and icon files. I downloaded the .zip and extracted these files to the “www” directory:


This provides everything, except the service worker. Creating a service worker can be confusing, but it is actqully quite simple. Using Google’s example, I was able to create a simple “sw.js” file.

This script provides the code for storing files in the browser’s local storage. It also handles the install event. Chrome uses the files to create the PWA program itself.

These files provide all of the basic needs for a PWA. At this point, the R program must be updated to use them. Finally, we’ll need to serve the app over https, otherwise Chrome will not allow installing it for offline use.

If you are not aware, Chrome is the ONLY browser that supports installing a PWA on a desktop. Safari will install a PWA as a Home Screen Icon on an iOS device however. (Getting the icon to show up properly is tricky). An R Shiny app will install and run in mobile mode on iOS.

R Code for Using the Manifest and Service Worker

Shiny can emit HTML code into the index.html it generates. For a PWA, manifest must be linked in the HEAD and the sw.js script must be included after the BODY is loaded.

Adding the LINK tag is done in the UI section of the Shiny app. For instance, if a fluidPage() is used. You must add a “tags$head” as the first parameter to the function. The script needs to be added to the page as well. This is accomplished by providing a (fairly long) HTML string as the last parameter to the fluidPage() function call. This is the minimal amount of code to create these required HTML:

At this point, it is possible to run the app locally and verify that Chrome recognizes it as a PWA.

What Does this Code Do?

You can look at the code using the Chrome developer’s tool. In short, Shiny converts the R code to HTML. You can actually create your own www/index.html file to do this, but you can’t use the R code to layout the screen using the nice Bootstrap support for widgets, etc.

Here’s a snippet of what the HEAD looks like in HTML

Here’s a snippet of what the BODY looks like in HTML

That’s it!

As a follow up, I hope to write up how to proxy HTTPS into the Shiny server docker container.




Engineer and Philospher

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

// from Twitter

Iteration K3: Translating Checkout


Jest Unit testing — Use of Matchers (Part2)

HTML Best Practices: Classes & IDs

“Popular Interview Question in JavaScript”

Row row your boat …

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Joe Bologna

Joe Bologna

Engineer and Philospher

More from Medium

Maven Unicorn Challenge

Analysing the cost of vehicles in Gran Turismo 6 Using Google Sheets

A picture of Luxury Cars in a street

[PowerBI/Excel] Quanto gastaram os deputados federais brasileiros em 2021?

Tableau multi-language and translation techniques