R Shiny browser() - Introduction to Debugging in R Shiny

Reading time:
time
min
By:
Dario Radečić
January 1, 1970

Debugging R Shiny applications is neither fun nor an easy task. Shiny's reactivity means that the code execution isn't linear and that the code overall is harder to access because it runs behind a web server. So, what can you do? One possibility is to use the R Shiny browser function, which allows you to pause the execution of your Shiny app end and enter a debug mode. Essentially, this enables you to examine the current state of your app and run the code line by line. Today you'll see 5 practical and hands-on examples of using the R Shiny browser function. We'll start with the most basic example you can think of, and end up with debugging your own Shiny module. Let's dig in! <blockquote>How do you handle empty state in R Shiny? <a href="https://appsilon.com/shiny-emptystate-tutorial/" target="_blank" rel="noopener">Read our in-depth guide to shiny.emptystate package</a>.</blockquote> Table of contents: <ul><li><a href="#basic">Basic Debugging with R Shiny browser()</a></li><li><a href="#observe">Debugging when an Event Happens with observeEvent</a></li><li><a href="#conditional">R Shiny browser() with Conditional Statements</a></li><li><a href="#custom-functions">Debugging with R Shiny browser() in Custom Functions</a></li><li><a href="#custom-modules">Debugging with R Shiny browser() in Custom Shiny Modules</a></li><li><a href="#summary">Summing up R Shiny browser()</a></li></ul> <hr /> <h2 id="basic">Basic Debugging with R Shiny browser()</h2> In essence, all you need to start using the R Shiny browser function is to add <code>browser()</code> wherever you want to start debugging your Shiny app. Simple as that! For this first example, we'll make the most basic app that allows the user to enter a number, then multiply the number by 2 and display it back via <code>verbatimTextOutput</code>. We'll put the <code>browser()</code> function right before the calculation, as shown below: <pre><code class="language-r">library(shiny) <br>ui &lt;- fluidPage(  numericInput(inputId = "num", label = "Enter a number:", value = 5),  verbatimTextOutput(outputId = "output") ) <br>server &lt;- function(input, output) {  result &lt;- reactive({    # Pause for debugging    browser()    input$num * 2  }) <br>  output$output &lt;- renderPrint({    result()  }) } <br>shinyApp(ui = ui, server = server)</code></pre> Since there's a default value for the input, you'll immediately see the following when you launch the app: <img class="size-full wp-image-20239" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d793c5eef432cde41744_c9a3a249_1.webp" alt="Image 1 - Basic debugging (1)" width="1512" height="1300" /> Image 1 - Basic debugging (1) This means the Shiny app has hit the browser breakpoint, and you can continue executing the code by hitting Enter in the R console: <img class="size-full wp-image-20241" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d794c774367445233628_a90c905d_2.webp" alt="Image 2 - Basic debugging (2)" width="1512" height="1300" /> Image 2 - Basic debugging (2) It has now executed the computation code and is ready to display the results (hit Enter one more time): <img class="size-full wp-image-20243" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d7955d38d30fab0fbef8_9aeb518b_3.webp" alt="Image 3 - Basic debugging (3)" width="1512" height="1086" /> Image 3 - Basic debugging (3) The results are correct, and the output also shows you which line of the code was responsible for delivering the results. Pretty basic, sure, but now you know how the <code>browser()</code> function works. Let's cover another example next. <h2 id="observe">Debugging when an Event Happens with observeEvent</h2> You can also use the R Shiny browser function when a certain event happens, such as a button click. In Shiny, this is typically done by adding the <code>observeEvent()</code> function to the piece of UI for which you want, well, observe events. The following Shiny app has one button, and when clicked, the app enters a debug mode: <pre><code class="language-r">library(shiny) <br>ui &lt;- fluidPage(  actionButton(inputId = "btn", label = "Click Me"),  verbatimTextOutput(outputId = "output") ) <br>server &lt;- function(input, output) {  observeEvent(input$btn, {    # Pause for debugging    browser()    output$output &lt;- renderPrint({      "Button Clicked!"    })  }) } <br>shinyApp(ui = ui, server = server)</code></pre> This is what the app will look like when you first launch it: <img class="size-full wp-image-20245" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d7961c638d294134059e_f066bcd7_4.webp" alt="Image 4 - observeEvent debugging (1)" width="1404" height="854" /> Image 4 - observeEvent debugging (1) You'll see the following output in the R console when you click on the button: <img class="size-full wp-image-20247" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d797d7575130662e8f61_8c3e40ce_5.webp" alt="Image 5 - observeEvent debugging (2)" width="1404" height="1338" /> Image 5 - observeEvent debugging (2) As before, hit Enter on your keyboard or click on Continue to go through the code: <img class="size-full wp-image-20249" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79849b91708eb343566_3d75d4d2_6.webp" alt="Image 6 - observeEvent debugging (3)" width="1404" height="1444" /> Image 6 - observeEvent debugging (3) And at the end, you'll see the output in the application below the button: <img class="size-full wp-image-20251" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79836826c908436328c_6c0710bd_7.webp" alt="Image 7 - observeEvent debugging (4)" width="918" height="402" /> Image 7 - observeEvent debugging (4) A big pro of the <code>browser()</code> function is its usage with conditional statements, so let's cover that next. <h2 id="conditional">R Shiny browser() with Conditional Statements</h2> You can also create conditional breakpoints in R Shiny with the <code>browser()</code> function by adding it to the body of a conditional statement. Sounds simple, so let's take a look at the implementation. The following Shiny app has a slider control that allows the user to select a number between 1 and 10 (set to 5 by default). The textual output below the slider will print "Greater than 5" or "Less than or equal to 5", depending on the current slider value. But here's the catch - only the condition where the value is greater than 5 will implement the <code>browswer()</code> function. Let's take a look: <pre><code class="language-r">library(shiny) <br>ui &lt;- fluidPage(  sliderInput(inputId = "num", label = "Select a number:", min = 1, max = 10, value = 5),  verbatimTextOutput(outputId = "output") ) <br>server &lt;- function(input, output) {  output$output &lt;- renderPrint({    if (input$num &gt; 5) {      # Pause for debugging      browser()      "Greater than 5"    } else {      "Less than or equal to 5"    }  }) } <br>shinyApp(ui = ui, server = server)</code></pre> Since the slider value of 5 falls into the <code>else</code> code block, the app doesn't enter into the debug mode: <img class="size-full wp-image-20253" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79978149a2ea79ee280_feb8404a_8.webp" alt="Image 8 - Conditional statement debugging (1)" width="938" height="530" /> Image 8 - Conditional statement debugging (1) But as soon as you increase the value, the output gets grayed out: <img class="size-full wp-image-20255" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79a84d9192ab6b2280f_09e245bd_9.webp" alt="Image 9 - Conditional statement debugging (2)" width="938" height="530" /> Image 9 - Conditional statement debugging (2) And you can also see the breakpoint in the R console: <img class="size-full wp-image-20257" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79ad7575130662e9145_a6a31ada_10.webp" alt="Image 10 - Conditional statement debugging (3)" width="1058" height="1210" /> Image 10 - Conditional statement debugging (3) As before, hit Enter to reach the end of the code block: <img class="size-full wp-image-20259" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79b5d38d30fab0fc519_580cf42b_11.webp" alt="Image 11 - Conditional statement debugging (4)" width="1058" height="1210" /> Image 11 - Conditional statement debugging (4) And you'll see the output and the debug message in the R Shiny app: <img class="size-full wp-image-20261" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79b85b6bd7053b909b0_66aa6044_12.webp" alt="Image 12 - Conditional statement debugging (5)" width="1566" height="712" /> Image 12 - Conditional statement debugging (5) Long story short - conditional statements allow you to enter a debug mode only if certain criteria is met. This comes in handy when implementing complex programming logic that depends on user input. <h2 id="custom-functions">Debugging with R Shiny browser() in Custom Functions</h2> The cool thing about Shiny <code>browser()</code> when compared to regular breakpoints is that the thing still works outside the server function. We'll demonstrate this by implementing <code>browser()</code> in a custom calculation function. The Shiny app below has a single numeric input which gets multiplied by 10 and incremented by 5 - a logic implemented in a custom function. The output is stored in a reactive value and is displayed immediately. No need to click on any buttons. Here's the code: <pre><code class="language-r">library(shiny) <br>custom_calculation &lt;- function(x) {  y &lt;- x * 10  # Pause for debugging  browser()  z &lt;- y + 5  return(z) } <br>ui &lt;- fluidPage(  numericInput(inputId = "num", label = "Enter a number:", value = 25),  verbatimTextOutput(outputId = "output") ) <br>server &lt;- function(input, output) {  result &lt;- reactive({    custom_calculation(input$num)  }) <br>  output$output &lt;- renderPrint({    result()  }) } <br>shinyApp(ui = ui, server = server)</code></pre> This is what you'll see when you first launch the app: <img class="size-full wp-image-20263" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79c6b3c80c04fb89c12_b11dd9ee_13.webp" alt="Image 13 - Custom function debugging (1)" width="1022" height="400" /> Image 13 - Custom function debugging (1) You'll immediately get redirected to RStudio and will be able to continue executing the code from the console: <img class="size-full wp-image-20265" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79d5951232f1a806ebd_d095e192_14.webp" alt="Image 14 - Custom function debugging (2)" width="1452" height="1626" /> Image 14 - Custom function debugging (2) The input value has now been multiplied by 10, and is currently asking you to increment it by 5: <img class="size-full wp-image-20267" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79d16b3ff510e39c8f7_a935ac12_15.webp" alt="Image 15 - Custom function debugging (3)" width="1452" height="1660" /> Image 15 - Custom function debugging (3) And finally, press Enter one more time to return the value: <img class="size-full wp-image-20269" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79e338f8c4c1b23d2db_a40ef787_16.webp" alt="Image 16 - Custom function debugging (4)" width="1452" height="1700" /> Image 16 - Custom function debugging (4) This is what you'll see in your app: <img class="size-full wp-image-20271" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79f71479ae64929c585_120bf6eb_17.webp" alt="Image 17 - Custom function debugging (5)" width="1548" height="588" /> Image 17 - Custom function debugging (5) Overall, the R Shiny <code>browser()</code> function works anywhere, which is its main selling point. For our final example, let's see how well it works inside a custom Shiny module. <h2 id="custom-modules">Debugging with R Shiny browser() in Custom Shiny Modules</h2> Shiny modules deserve an article on their own, so we'll keep the theory light here. Think of them as repeated structures, allowing you to write the code once and reuse it in multiple places. Our simple module will allow the user to enter a text string, and will have a default value of "abc". The server function of this module will implement the <code>browser()</code> function, and will return the input string from the user combined with arrows on both sides. See it for yourself: <pre><code class="language-r">library(shiny) <br>myModuleUI &lt;- function(id) {  ns &lt;- NS(id)  textInput(inputId = ns("text"), label = "Enter a string:", value = "abc") } <br>myModule &lt;- function(input, output, session) {  result &lt;- reactive({    # Pause for debugging    browser()    paste("---&gt;", input$text, "&lt;---")  }) <br>  return(result) } <br>ui &lt;- fluidPage(  myModuleUI("module1"),  verbatimTextOutput("output") ) <br>server &lt;- function(input, output) {  result &lt;- callModule(myModule, "module1") <br>  output$output &lt;- renderPrint({    result()  }) } <br>shinyApp(ui = ui, server = server)</code></pre> You can now launch the app - here's what you'll see: <img class="size-full wp-image-20273" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d79f9006b587a562ef3e_754e2681_18.webp" alt="Image 18 - Custom module debugging (1)" width="1228" height="576" /> Image 18 - Custom module debugging (1) Overall, our module was used to make this UI element, which also triggers a call to the <code>browser()</code> function: <img class="size-full wp-image-20275" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d7a05d38d30fab0fc8ca_9d381b05_19.webp" alt="Image 19 - Custom module debugging (2)" width="1262" height="1238" /> Image 19 - Custom module debugging (2) As before, click on Continue to keep running the code line by line: <img class="size-full wp-image-20277" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d7a1b89c0bb01398e9c7_ccd8956b_20.webp" alt="Image 20 - Custom module debugging (3)" width="1262" height="1238" /> Image 20 - Custom module debugging (3) And this is the output you'll see in the end: <img class="size-full wp-image-20279" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d7a16b3c80c04fb89f5b_d7000a02_21.webp" alt="Image 21 - Custom module debugging (4)" width="1804" height="534" /> Image 21 - Custom module debugging (4) We're sure that debugging a custom Shiny module was easier than you thought. Let's make a brief recap next. <hr /> <h2 id="summary">Summing up R Shiny browser()</h2> And there you have it - 5 ways to use the R Shiny browser function in your app. You now know how to pause the execution and run the subsequent code line by line. This will ensure you don't get any unexpected bugs and will make the ones you currently have easier to fix. If you're wondering about <b>R Shiny browser alternatives</b>, you might stumble upon regular breakpoints. These sometimes work, but can only be used inside the <code>shinyServer</code> function. You might also want to consider a Shiny reactive log, but that's a more advanced concept better suited for some other time. <i>What's your go-to way of debugging R Shiny applications? Are you using the browser() function regularly, or do you prefer something else?</i> Let us know in the comment section below. <blockquote>Great R Shiny apps are tough to build, and your company might be the bottleneck. <a href="https://appsilon.com/performant-r-shiny-apps-with-database-indexing-normalization/" target="_blank" rel="noopener">Make sure they're giving you all you need to build great Shiny apps.</a></blockquote>

Have questions or insights?

Engage with experts, share ideas and take your data journey to the next level!

Is Your Software GxP Compliant?

Download a checklist designed for clinical managers in data departments to make sure that software meets requirements for FDA and EMA submissions.
Explore Possibilities

Share Your Data Goals with Us

From advanced analytics to platform development and pharma consulting, we craft solutions tailored to your needs.

Talk to our Experts
shiny
tutorials