Setup shiny.telemetry in a Rhino application

The {shiny.telemetry} package can be used with any Shiny application and in this guide we will show how to add it to a {rhino} application.

{rhino} is a package that provides a framework to build high quality, enterprise-grade Shiny apps at speed. It is designed to help you build Shiny apps that are scalable, maintainable, and robust.

Using {shiny.telemtry} with {rhino} is very simple and it requires only a few lines of code just as any other app.

Useful links:

Creating a new {rhino} application

Starting a new {rhino} application is as simple as running the rhino::init() command. Learn more about “Creating your first Rhino app” in this guide.

The command creates a boilerplate folder structure for a {rhino} application, where app/main.R contains the UI and server logic. The application structure is best explained on this “App structure” documentation.

Before setting up {shiny.telemetry} in the application, let’s add a simple input element to the boilerplate code. Otherwise, the only events that will be tracked are the login, logout and the user’s browser version.

For this we will add a text input to the application and in the sections below observe how it is being tracked by {shiny.telemtry}.

Adding the code below to the app/main.R file will add a text input and a “Hello world” message with the contents of the input.

# app/main.R (replace with the following code)
box::use(
  shiny[
    bootstrapPage, div, moduleServer, NS, renderUI, tags, textInput, uiOutput, 
    verbatimTextOutput,
  ],
)

#' @export
ui <- function(id) {
  ns <- NS(id)
  bootstrapPage(
    textInput(ns("name"), "My name", "world"),
    verbatimTextOutput(ns("text")),
    uiOutput(ns("message"))
  )
}

#' @export
server <- function(id) {
  moduleServer(id, function(input, output, session) {
    output$message <- renderUI({
      div(
        style = "display: flex; justify-content: center; align-items: center; height: 50vh;",
        tags$h1(
          tags$span(sprintf("Hello %s! ", input$name)),
          tags$a("Check out Rhino docs!", href = "https://appsilon.github.io/rhino/")
        )
      )
    })
  })
}

Using an existing {rhino} application

Alternatively, you can add {shiny.telemetry} to an existing {rhino} application by following the steps in the next sections.

Please note, that if there are no input elements in the application, the only events that will be tracked are the login, logout and the user’s browser version.

Setup {shiny.telemetry}

The following 4 steps are needed to start using {shiny.telemetry} for tracking inputs in the application:

  1. Import functions from {shiny.telemetry} using {box};
  2. Add Javascript code to UI definition;
  3. Create a Telemetry object;
  4. Start telemetry session attached to a Shiny session.

The first step is to install {shiny.telemetry} with:

rhino::pkg_install("shiny.telemetry")

Import functions from shiny.telemetry

The {rhino} frameworks promotes the use of {box} to import functions from packages and internal modules. See the {rhino} documentation on how to write R code for more details.

The minimal setup for {shiny.telemetry} needs to import:

Any additional function that is being used, needs to be imported as well. This can be done by adding the following code to the top of app/main.R file on the package imports:

# app/main.R (top of file)
box::use(
  shiny[
    bootstrapPage, div, moduleServer, NS, renderUI, tags, textInput, uiOutput,
    verbatimTextOutput,
  ],
  # other packaage imports ...
  shiny.telemetry[DataStorageLogFile, Telemetry, use_telemetry],
)

Add Javascript code to UI definition

The next step is to call use_telemetry() function in the root UI definition on app/main.R file to load the necessary Javascript code.

Note that the id parameter needs to be passed to the use_telemetry() function to ensure that the browser version is tracked correctly, as well as the mechanism to track anonymous user via client side cookies.

# app/main.R (change n `ui` function)
#' @export
ui <- function(id) {
  ns <- NS(id)
  bootstrapPage(
    use_telemetry(id),
    tags$div(
      style = "display: flex; justify-content: center; align-items: center; margin-top: 2em;",
      textInput(ns("name"), "My name", "world")
    ),
    verbatimTextOutput(ns("text")),
    uiOutput(ns("message"))
  )
}

Create Telemetry object

The next step is to create a Telemetry object that will be used to track events in the app.

We recommend creating an instance of Telemetry on the app/main.R and then start the telemetry session on the root server function definition, just as shown in the code below.

This will create a text file with the events tracked by {shiny.telemetry}. It is the simplest storage backend available and the file contains JSON data that can be easily read and processed.

To learn about other backends see the “Use External Databases with shiny.telemetry” guide.

Please note, that the values themselves are not tracked by default and need to be enabled by setting the track_values parameter to TRUE in the start_session() method. In this example we are enabling them to help demonstrate the capabilities of {shiny.telemetry}.

# app/main.R (create telemetry object and initialize in a session)
telemetry <- Telemetry$new(
  app_name = "rhino_app",
  data_storage = DataStorageLogFile$new("local_file.txt")
)

#' @export
server <- function(id) {
  moduleServer(id, function(input, output, session) {
    telemetry$start_session(track_values = TRUE)
    # Server logic ...
  })
}

The telemetry$start_session() call can be customized to enable/disable different types of events and can be further extended to include/exclude input ids. See the Guide on tracking specific inputs for more details.

The application is now ready to track the input changes, login, logout and browser version. Start the application and test it out yourself.

shiny::runApp() # Start the application and change inputs 
Figure 1: Running Rhino app and changing the input.
Figure 1: Running Rhino app and changing the input.

Access the events

The {shiny.telemetry} package provides a default dashboard to visualize the events tracked by the application. In this example we will use the local_file.txt that has been configured in the application.

To start the dashboard run the code below after installing the suggested packages (renv::install("semantic.dashboard", "shinyjs", "plotly", "timevis", "DT"))

# Required suggested packages:
#  renv::install("semantic.dashboard", "shinyjs", "plotly", "timevis", "DT")
library(shiny.telemetry)

data_storage <- DataStorageLogFile$new("local_file.txt")
analytics_app(data_storage = data_storage)

This will start a dashboard that will show the events tracked by the application. It shows: