Join the Shiny Community every month at Shiny Gatherings

Top 3 Tools to Monitor User Adoption in R Shiny

Can you monitor user adoption for R Shiny apps? What is user adoption anyway? We’ll answer these questions and show you how to do it yourself in this article.

Put simply, user adoption is the process by which new users become familiar with your product and/or service and decide to keep using it. User adoption rate is critical for your R Shiny dashboards because it tells you if your service actually solves a problem. If the adoption rate is high, more users are adopting your dashboard than abandoning it.

But what tools can you use to monitor user adoption in R Shiny? Today we bring you 3 tools to include in your next project.

Not an R Shiny expert? Here are example dashboards you can build with Shiny.

Table of contents:

Shiny.stats – Add Statistics Panel to R Shiny

The shiny.stats package by Appsilon provides an easy way for logging users’ activity and adding a statistics panel to your R Shiny apps. The only requirement is that you have an accessible database, which can be as simple as a local PostgreSQL database or a sqlite file.

Before you can start monitoring user adoption with shiny.stats, you’ll have to install the package. Install it directly from GitHub:


The next step is to initialize the database you want to use with shiny.stats. You should only do this once. The snippet below will connect to a sqlite database named user_stats:


connection <- DBI::dbConnect(RSQLite::SQLite(), dbname = "user_stats.sqlite")

Now comes the potentially tricky part, depending on how your app’s authentication is set up. You’ll need to define a function to extract the username. The below example will extract it from the URL, from a dedicated username parameter.

Once that’s out of the way, plug the logic into the Shiny app. The magic happens in the server function where the database connection is established and user behavior is monitored:


get_user <- function(session) {

ui <- fluidPage(
  titlePanel("Old Faithful Geyser Data"),
        "Number of bins:",
        min = 1,
        max = 50,
        value = 30
      actionButton("apply_slider", "Apply")

server <- function(input, output, session) {
  connection <- odbc::dbConnect(RSQLite::SQLite(), dbname = "user_stats.sqlite")

  # creating user connection list and making sure required tables exist in DB
  user_connection <- initialize_connection(connection, username = get_user(session))

  # registering login

  # selecting registered actions to watch
  log_click(user_connection, id = "apply_slider")
  log_input(user_connection, input, input_id = "bins")

  # server code
  output$distPlot <- renderPlot({
    x <- faithful[, 2]
    bins <- seq(min(x), max(x), length.out = isolate(input$bins) + 1)
    hist(x, breaks = bins, col = "darkgray", border = "white")

  # registering logout (this also disconnects connection object, if not used take care of it on your own)

shinyApp(ui = ui, server = server, options = list(port = 8888, launch.browser = FALSE))

Here’s what the Shiny app looks like:

Image 1 – R Shiny app that monitors user adoption data

You simply can’t tell that user behavior is monitored from the app itself. Luckily, we can check the database. Open the sqlite file in your favorite database management tool – we’re using TablePlus:

Image 2 – User behavior data saved in the database

Do you know what’s really handy about shiny.stats? You can easily display users’ stats in an R Shiny dashboard. The following code snippet creates a dashboard that allows you to monitor user adoption in R Shiny:


# prepare credentials list to access logs:
db_credentials <- list(
  DB_NAME = "user_stats.sqlite",
  DB_DRIVER = "SQLite"

# define function hot to get username
get_user <- function(session) {
  username <- isolate(parseQueryString(session$clientData$url_search)$username)

# define ui and server
ui <- shiny_stats_ui()
server <- shiny_stats_server(get_user, db_credentials = db_credentials)

shinyApp(ui = ui, server = server, options = list(port = 8887, launch.browser = FALSE))

Image 3 – Displaying users’ data in an R Shiny dashboard

Easy, right? Let’s see what else is available in R Shiny.

Shinylogs – Track Inputs, Outputs, Errors, and Session Info

The shinylogs is another package that allows you to monitor user adoption in R Shiny. It records inputs or output changes, and info about the user’s session. All recordings are done client-side, so you can rest assured it won’t slow down the application and occupy the server.

As with shiny.stats, the first step here is to install the package. It’s available on CRAN which makes things super simple:


The way shinylogs handles storing user monitoring data by combining two functions. The first one – track_usage() captures all inputs, errors, outputs, and session info, and it also accepts the second function as a parameter. The name of that function varies. For example, you can use store_json(path = "") to save logs in JSON format. Other formats are also available, such as RDS, Google Drive, SQLite, and others. Read their function reference for more details.

We’ll keep things simple and store logs in JSON format in the logs/ directory. The R Shiny app below applies a clustering algorithm to the Iris dataset and lets you change the columns you want to see on a scatter plot:


ui <- fluidPage(
  headerPanel("Iris k-means clustering"),
        inputId = "xcol",
        label = "X Variable",
        choices = names(iris)
        inputId = "ycol",
        label = "Y Variable",
        choices = names(iris),
        selected = names(iris)[[2]]
        inputId = "clusters",
        label = "Cluster count",
        value = 3,
        min = 1,
        max = 9

server <- function(input, output, session) {
  # Store JSON with logs in the temp dir
    storage_mode = store_json(path = "logs/")

  # classic server logic
  selectedData <- reactive({
    iris[, c(input$xcol, input$ycol)]
  clusters <- reactive({
    kmeans(selectedData(), input$clusters)
  output$plot1 <- renderPlot({
      "#E41A1C", "#377EB8", "#4DAF4A", "#984EA3",
      "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999"

    par(mar = c(5.1, 4.1, 0, 1))
      col = clusters()$cluster,
      pch = 20, cex = 3
    points(clusters()$centers, pch = 4, cex = 4, lwd = 4)

shinyApp(ui = ui, server = server)

Here’s what the Shiny app looks like:

Image 4 – R Shiny application that uses shinylogs in the background

Just make a couple of adjustments here and there in the dashboard – change the columns, cluster numbers, go crazy! The logs will automatically get saved to the logs/ directory, as you can see from the image below:

Image 5 – Contents of the logs/ directory

The logs are saved in JSON format, which means you can grab the contents and open any JSON formatter available online. Doing so will pretty-print the JSON, meaning it will be easier to read:

Image 6 – Contents of the log file, pretty printed

Did you see how easy that was? You didn’t have to configure anything, besides the storage file format option and the path. Up next, we’ll explore one massively popular option to monitor user adoption in R Shiny.

Google Analytics – It Works with R Shiny Too

Setting up Google Analytics to work with R Shiny is much more challenging than the previous two options. You’ll first need to create a Google Analytics account if you don’t already have it and then create a new property. The linked article provides a step-by-step guide, so we’ll only focus on the good parts.

Assuming you have an Analytics account registered and property created, download these four files from GitHub:

Image 7 – GitHub contents of the R Shiny app

These four files are everything we need to link an R Shiny application to Google Analytics, and therefore, monitor user adoption. Now head back to Google Analytics and copy the Global Site Tag (gtag.js) script. It should look like this:

Image 8 – Global Site Tag script

You’ll need to partially replace the contents of google-analytics.html with your global site tag info. Here’s what ours looks like after the modification:

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="">
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', '');

  $(document).on('change', 'select', function(e) {
    ga('send', 'event', 'widget', 'select data', $(e.currentTarget).val());

  $(document).on('click', 'button', function() {
    ga('send', 'event', 'button', 'plot data');

You can use ours, of course, just remember to change the global site tag ID.

Once that’s out of the way, run app.R to verify Shiny app loads without any issues:

Image 9 – Sunlight in the US R Shiny app

Neat. Everything works as advertised, and the R Shiny app is now automatically logging everything you do into Google Analytics. Keep in mind: Changes won’t be reflected immediately in Google Analytics – please allow a couple of minutes for usage data to become visible.

Here’s what it looks like on our end. The first image shows real-time info:

Image 10 – Google Analytics real-time overview

And the following one shows an overview of the engagement:

Image 11 – Google Analytics engagement overview

That’s it! R Shiny is now connected to Google Analytics.

Monitor User Adoption in R Shiny – Summary

In short, yes you can monitor user adoption in R Shiny apps. And there are multiple ways to do so. In this article, we covered 3 quick ways to monitor user adoption in R Shiny. The first two solutions are a no-brainer for small apps and teams, especially if you don’t have to monitor everything. The Google Analytics solution is a clear winner and an industry standard if your app has many users and you really want to make deep dives into user behavior. It’s a bit more challenging to set up, but nothing you can’t manage in a coffee break.

Which tool do you use to monitor user adoption in R Shiny apps? Please let us know in the comment section below. Also, don’t hesitate to hit us on Twitter – @appsilon. We’d love to hear your input.

Want to share your R Shiny apps with the world? Here are 3 ways to Share R Shiny apps, entirely free.