R Shiny Google Analytics: How to Add GA to Shiny Apps

Estimated time:

User adoption is an important metric for any application's success. But <strong>measuring adoption</strong> hasn't always been a priority for Shiny developers. We think it's time to change this. So today we'll show you how to add Google Analytics to R Shiny apps. In this article, we'll cover how to combine R Shiny and Google Analytics by adding a <strong>Google Analytics tracker</strong> to your Shiny application. We'll also present a <strong>real Google Analytics example</strong> in Shiny from our recent, <a href="https://demo.prod.appsilon.ai/forest-ranges/" target="_blank" rel="noopener"><em>Forest Ranges</em> application</a>. <blockquote>Is your Shiny app succesful? Explore these <a href="https://appsilon.com/monitoring-r-shiny-user-adoption/" target="_blank" rel="noopener">top 3 tools for monitoring user adoption in Shiny</a>.</blockquote> Note: Before setting up Google Analytics, you should consider the legal implications of improper configuration, data protection, and GDPR compliance. There is a complicated and evolving situation with <a href="https://noyb.eu/en/101-complaints-eu-us-transfers-filed" target="_blank" rel="noopener">legal action</a> being taken on EU and US companies failing to adhere to GDPR (also known as DSGVO or RGPD). <h2>Finding Google Analytics Tracking Code</h2> First, you’ll need to register a Google Analytics account and log in. Once inside, find the `Admin` button and click to enter the administration panel. <img class="alignnone size-full wp-image-13607" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01deaaebaad0dba42415f_ga-admin-button.webp" alt="Google Analytics Admin button" width="2332" height="1806" /> From there you need to create a new property. Think of a property as an individual website (an application in our case) that you want to track. It's convenient to name the property after the app, hence the name "Forest App" below. But the naming convention can follow whatever you’re comfortable with. <img class="alignnone size-full wp-image-13609" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01debaebaad0dba42419f_ga-new-property.webp" alt="Google Analytics new property view for Shiny app" width="2332" height="1806" /> Follow the instructions and you will be rewarded with a small chunk of HTML code that should look something like this: <pre>&lt;!-- Global site tag (gtag.js) - Google Analytics --&gt; &lt;script async src="https://www.googletagmanager.com/gtag/js?id=G-ThisIsNotReal"&gt; &lt;script&gt;  window.dataLayer = window.dataLayer || [];  function gtag(){dataLayer.push(arguments);}  gtag('js', new Date());  gtag('config', 'G-ThisIsNotReal'); &lt;/script&gt; </pre> <h2>Adding Google Analytics Tracking Code to Shiny App</h2> There are many ways to include arbitrary HTML code into a Shiny app. But before we do that, notice that the suggested HTML code contains two <code>script</code> tags. Instead of adding this HTML as-is, you might find it beneficial to add two separate JS scripts. <blockquote>Need a quick dashboard? <a href="https://templates.appsilon.com/" target="_blank" rel="noopener">Download a free Shiny dashboard template from Appsilon</a>.</blockquote> For the first one, we'll add a URL, but for the second one, we'll create a local JS script. If we decide to extend its functionality, this method will pay off for us in the end. In this example, I created a <code>gtag.js</code> script in <code>static/js</code> folder: <pre>$(() =&gt; {  /* Default installation */  window.dataLayer = window.dataLayer || [];  function gtag() {    dataLayer.push(arguments);  };  gtag('js', new Date());  gtag('config', 'G-XC5N93969C'); }); </pre> <p dir="auto">Notice that everything we'll write in the <code>gtag.js</code> script will be wrapped in <code>$( () =&gt; {} );</code>. This is the JQuery way of making sure that this code runs after the page has been loaded.</p> <p dir="auto">Now, this is how I add the scripts to the Shiny App:</p> <pre># somewhere inside the UI shiny::tags$head(  shiny::tags$script(    src = "https://www.googletagmanager.com/gtag/js?id=G-ThisIsNotReal",    async = ""  ),  shiny::tags$script(    src = "static/js/gtag.js"  ) ) </pre> <p dir="auto">At this point, you should run the app and go to the Google Analytics page. Here, you’ll want to check if the events are being recorded in real-time (the lag here should not exceed 1-2 minutes).</p> <h2 dir="auto">Extend Google Analytics Tracker with Custom Events</h2> That was fairly straightforward; nothing too complex going on. But there would be no reason to write this article if it was only about adding a GA tracker to the app. The interesting and most important part is being able to track certain events that we’re interested in. For instance, in our Forest Ranges app, users can select a tree species to check its future conditions. What we would like to know, is what species draw the most attention.  <blockquote>New to Shiny? See what’s possible with <a href="https://demo.appsilon.com/" target="_blank" rel="noopener">Appsilon’s Shiny demos</a>. </blockquote> To do that, we obviously need to know which specimen was selected. After this point, things may differ from app to app, because everything depends on what you choose to track and how you choose to do it.  Following our example, we have a dropdown input with tree species options: <pre>shiny.semantic::dropdown_input(  input_id = ns("tree_specie"),  choices = trees_human,  choices_value = trees_abr,  default_text = "Tree species",  value = trees_abr[1] ) </pre> Here, 'trees_human is a character vector of "human-readable" tree names (e.g. "European silver fir"), and 'trees_abr' is a character vector of corresponding scientific abbreviations (e.g. "abal" form "Abies Alba") In order for the GA tracker to know which species the user selected, we need to do three things: <ul><li>Find the required element in the HTML structure of the app</li><li>Add a proper event listener to this element</li><li>Send the event's data to GA with a function provided by Google</li></ul> Let's jump into it! <h3>Finding the element</h3> To "find" the element in the HTML structure of the app, recall that <code>shiny.semantic::dropdown_input</code> generates a dropdown menu where each element has a class <code>item</code>. Because this is the only dropdown menu in our app, we can refer to these elements with a simple css selector <code>.item</code>. Finding this element jQuery style looks like this: <pre>$('.item') </pre> <p dir="auto">This selector will find <em><strong>every</strong></em> element of class <code>item</code> on the page. It's pretty useful because we won't need to iterate over an array of elements to add event listeners. However, because our selector finds all elements, we'll need to use the <code>.currentTarget</code> property of the event inside a callback function to make sure we refer only to the element that emitted an event.</p> <p dir="auto">Speaking of the event, let's add an event listener now.</p> <h3 dir="auto">Adding an event listener</h3> We want something to happen when a user <strong>clicks</strong> on the item of interest: <pre>$('.item').on('click', (event) =&gt; {  const selectedSpecie = $(event.currentTarget).data().value;  console.log(selectedSpecie); }); </pre> <p dir="auto">This obscure jQuery code finds an element stored in the <code>currentTarget</code> property of the <code>event</code> object (the event is passed as an argument to a callback function), executes <code>data()</code> method on it, and extracts the <code>value</code> property. This value should contain an actual tree abbreviation.</p> To check that everything is done correctly, run the app and open it in the browser. Then, open developer tools and navigate to the console. You should now see species abbreviations in the console every time we select a tree. This is neat, but we want to send this data to Google Analytics, not to the console. So let’s learn how, next. <h3>Sending data to Google Analytics</h3> To send this data to GA, we will use the <code>gtag</code> function that Google has already provided. According to the <a href="https://developers.google.com/tag-platform/gtagjs/reference#event" target="_blank" rel="nofollow noopener">official documentation</a>, we can specify an event name and pass some data to it. We can now replace <code>console.log</code> with <code>gtag</code>: <pre>$('.item').on('click', (event) =&gt; {  const selectedSpecie = $(event.currentTarget).data().value;  gtag('event', 'specie_selected', {    selected_specie: selectedSpecie  }); }); </pre> <h2>Check out custom events in Google Analytics for Shiny</h2> <p dir="auto">Now we’re finally able to take a look at the results of our efforts! Go to the Google Analytics page, navigate to the Reports section, and select Realtime. Scroll down until you find a panel with <code>Event count by Event name</code>. This is the place where we will track our event.</p> <p dir="auto"><img class="alignnone size-full wp-image-13611" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01dec2a228de4b21de518_ga-realtime-report.webp" alt="Google Analytics realtime report for Shiny app" width="2274" height="1686" /></p> <p dir="auto">If you were able to follow all the steps in this blog post, you will ultimately see something like this. Congratulations!</p> If you were able to follow all the steps in this blog post, you will ultimately see something like this. <img class="alignnone size-full wp-image-13613" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01dee72a288e80b4cbb00_ga-realtime-summary.webp" alt="Google Analytics realtime summary of Shiny app in use" width="1764" height="495" /> Congratulations! You've now successfully implemented Google Analytics in a Shiny app. <h2>Why use Google Analytics in a Shiny App?</h2> <h3>Shiny user metrics with Google Analytics</h3> I know it seems out of place to ask this after we've gone through the trouble. But it's important to emphasize the 'why' of <strong>monitoring user metrics</strong> in Shiny. First, you've worked hard on your application and it's out there. Sitting on the world wide web or helping your colleagues <strong>solve problems</strong> in their team. But is it really solving 'all' of their needs? Google Analytics makes monitoring user adoption of your application easy and straightforward. It helps answer questions like: <ul><li>How many users are there? </li><li>How often are they using it? </li><li>And how long are they using it for? </li></ul> These are all important pieces of the informational pie that construct your overall user adoption. <blockquote>Is your UX holding you back? Follow these <a href="https://appsilon.com/ux-design-of-shiny-apps-7-steps-to-design-dashboards-people-love/" target="_blank" rel="noopener">7 steps to design dashboards that people will love</a>.</blockquote> <h3>Shiny project benefits</h3> Adding custom events, allows you to not only monitor session counts but also gain additional insights from your users' behavior and interests. What if you spent a lot of time and effort on developing a certain feature (say this dropdown menu with tree species), but it turns out that the users don't even need it? By discovering what users do and do not use, you can now adjust the development process and de-prioritize features. Saving your team time and resources.  <h2>Concluding Google Analytics in R Shiny apps</h2> Of course, this was a simple example, but the real applications of this approach go far beyond what we showed. You can track any number of different events, and send different data parameters to Google Analytics to achieve your goals. Let us know how you use GA in your Shiny app in the comments section below.  Want to learn more about how to use tools like Hotjar, shiny.stats, and shinylogs? Explore the <a href="https://appsilon.com/blog/">Appsilon blog</a> and consider subscribing to the Shiny Weekly newsletter - where we collect the latest Shiny news from the R community.  And of course, if you need help with getting your enterprise Shiny app from PoC to production-ready, reach out to <a href="https://appsilon.com/">Appsilon</a>. We'll help you scale, design, and succeed with Shiny.

Contact us!
Damian's Avatar
Damian Rodziewicz
Head of Sales
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Have questions or insights?
Engage with experts, share ideas and take your data journey to the next level!
Join Slack
Explore Possibilities

Take Your Business Further with Custom Data Solutions

Unlock the full potential of your enterprise with our data services, tailored to the unique needs of Fortune 500 companies. Elevate your strategy—connect with us today!

Talk to our Experts
user metrics