14 Interactive Reporting
Acknowledgements
Most of what we’ll discuss today can be found at quarto.org, the Quarto-Live documentation or shinylive.io. Gemini Code Assist was also active during the development of these materials, and some text was generated with its assistance.
Introduction & The Need for Interactivity
Static vs. Interactive:
Quarto is excellent for static reports (HTML, PDF, Word)
Static documents only show pre-computed results
Compute engine can be attached to the document to enable interactivity
Enter Shiny:
Traditionally, Shiny (in R or Python) creates interactive web apps
Quarto natively supports embedding Shiny elements directly into Markdown documents
Instead of writing a full standalone app UI, you can write a narrative document and embed interactive widgets (sliders, plots) throughout
Server-Backed Shiny in Quarto
When a user interacts with a slider, the browser sends a request to a backend server (running R or Python)
The server recalculates the output (e.g. a plot) and sends the image/data back to the browser
Implementation in Quarto
- To enable this, add
server: shinyto the YAML header
Example yaml header
---
title: "My Interactive Report"
format: html
server: shiny
--- Example R code chunk
#| panel: sidebar
sliderInput("bins", "Number of bins:", min = 1, max = 50, value = 30)
#| panel:
fill plotOutput("distPlot") #| context: server
output$distPlot <- renderPlot({
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
hist(x, breaks = bins, col = 'darkgray', border = 'white')
}) The Deployment Bottleneck
Because it requires a backend to compute, you cannot host this on simple static hosting (like GitHub Pages, Netlify, or standard web servers)
You must deploy to a specialized server (e.g. shinyapps.io, Posit Connect, or your own Shiny Server)
Cons: Can be expensive, hard to scale if thousands of users visit at once, and requires server maintenance
WebAssembly (Wasm) & Shinylive
WebAssembly (Wasm)
A binary instruction format that allows code written in languages like C, C++, Rust—and now R and Python—to run natively inside the web browser at near-native speeds
Magic: The browser becomes the server!
WebR and Pyodide
WebR: A version of the R interpreter compiled to Wasm.
Pyodide: A version of the Python interpreter compiled to Wasm.
Shinylive
Shinylive bundles your Shiny application, the WebR/Pyodide engine, and the necessary packages into a static bundle
When the user opens the webpage, the entire R/Python engine downloads into their browser cache and runs locally on their machine
If you Google this, you will often see tutorials using filters: [shinylive]. That belongs to the older quarto-ext/shinylive extension which only embeds Shiny apps.
Today, we are using the newer, broader r-wasm/quarto-live extension. It allows us to embed Shinylive apps and execute live code cells. Because it injects WebAssembly engines into the document, it requires the special format: live-html in the YAML header.
Serverless Interactivity with quarto-live
The easiest way to use Shinylive in Quarto is via the
quarto-liveextensionIt allows execution of R and Python code blocks right in the browser
# install quarto-live with
quarto add r-wasm/quarto-liveYAML Example
---
title: "Serverless Report"
format: live-html
engine: knitr # or jupyter for Python
--- Using Live Code Blocks
- Instead of
{r}, use{webr}(for R) or{pyodide}(for Python) to create interactive code editors where users can run and modify code on the fly!
Embedding Full Shinylive Apps
You can use the {shinylive-r} or {shinylive-python} code blocks to embed complete, serverless Shiny applications directly in the document.
Deployment
Standard Shiny deployment requires a server (cloud service or expensive private servers)
Shinylive / Quarto-live Deployment:
The output is 100% static HTML, CSS, JavaScript, and Wasm files.
Where can you host it? Anywhere.
GitHub Pages, Netlify, Amazon, …
Trade-offs
Initial Load Time: The first time a user visits, they have to download the Wasm engine - the more complicated the greater the download/load time (anywhere from a few seconds to hanging forever).
Data Privacy: Since the compute happens in the user’s browser, you cannot hide your proprietary code or secure database credentials in the Shinylive app. All data sent to the app is pushed to the client.
Compute Limits: It relies on the user’s RAM and CPU. Not suitable for massive big-data machine learning jobs.
Summary
Use Server-backed Shiny for heavy compute, large datasets, or when code/data must remain private.
Use Shinylive/Quarto-live for educational tools, public dashboards, low-cost hosting, and infinite scalability.
Resources
Quarto Interactive Documents (Official Docs):
Use for: Understanding the basics of embedding standard Shiny, Observable JS, and Jupyter widgets into Quarto.
Quarto-Live Documentation:
Use for: The official guide on setting up the
quarto-liveextension, using{webr}chunks, and embedding{shinylive}apps.
Shinylive (R) Official Site:
Link: https://shinylive.io/r/
Use for: An online playground to test and build serverless R Shiny apps right in your browser.
Shinylive (Python) Official Site:
Link: https://shinylive.io/py/
Use for: An online playground for Python Shiny applications.
Review Questions
- What is the primary limitation of standard, static Quarto documents when it comes to data exploration?
- In a traditional server-backed Shiny application embedded in Quarto, where does the code computation actually happen?
- What is WebAssembly (Wasm), and why is it described as turning the user’s browser into the server?
- Describe the “Initial Load Time” trade-off associated with Shinylive. Why does the first visit take longer than subsequent visits?
- Why is Shinylive/Quarto-live not recommended for applications that require highly sensitive database credentials or massive machine-learning computations?