livelink v0.1.0 Released - Shareable Links That Run R and Shiny in the Browser

livelink turns R code into a URL that runs in the browser, with no server and nothing to upload. It covers webR for a full R REPL and Shinylive for R and Python Shiny apps, packs the code into the link itself, and reads any link back into files.
software-releases
r-package
Author

James Balamuta

Published

July 15, 2026

livelink hex logo: a stack of code lines receding into the distance with an outbound arrow

livelink hex logo: a stack of code lines receding into the distance with an outbound arrow

The livelink package (GitHub, documentation) turns a piece of R code into a URL that runs it in the browser. There is no server, no account, and nothing to upload. You hand someone a link, they click it, and they are looking at a live R session with your code already in the editor. Two destinations are supported: webR, a full R REPL compiled to WebAssembly, and Shinylive, which runs R and Python Shiny applications entirely client-side.

Sharing R usually starts with a tax. First install R, then an IDE, then the one package that will not compile on somebody’s laptop. That tax is why a reproducible example turns into a support thread, why a workshop loses its first twenty minutes to setup, and why a “just try this” is rarely just anything. livelink removes the install step from the sharing part. The link is the runnable code.

The trick is that there is no trick. Everything after the # in a URL is a fragment, and browsers never send a fragment to any server. livelink compresses your code, base64-encodes it, and writes it into that fragment. The link is the whole payload. There is nothing on the other end to spin up, pay for, or take down when you forget it exists.

Three steps. You write R inside webr_repl_link with no quotes and no escaping. You get a URL whose fragment carries the code itself. The recipient opens it and lands in a live webR session with the code in the editor and the plot already drawn.

Three steps. You write R inside webr_repl_link with no quotes and no escaping. You get a URL whose fragment carries the code itself. The recipient opens it and lands in a live webR session with the code in the editor and the plot already drawn.

Regular readers may recognize the idea from the other direction. My peeky package makes the point that a Shinylive app keeps no secrets: to run in the browser, the app hands its entire source to the visitor, because the app is the bundle. livelink is that same property turned into a feature on purpose. Instead of pulling code out of someone else’s link, you deliberately pack your own code into one and pass it along.

A Shiny app, in R or Python

shinylive_r_link() and shinylive_py_link() do the same for a Shiny application, in either language:

app <- "
library(shiny)
ui <- fluidPage(sliderInput('n', 'Bins', 1, 50, 30), plotOutput('hist'))
server <- function(input, output) {
  output$hist <- renderPlot(hist(faithful$waiting, breaks = input$n))
}
shinyApp(ui, server)
"

shinylive_r_link(app, mode = "app")

mode = "app" sends the reader straight to the running application; mode = "editor" puts the code beside it, which is what you want when the point is to teach. The engine is written into the URL itself, shinylive.io/r/ versus shinylive.io/py/, so a link carries its own language with it.

More than one file, and whole directories

Real work is rarely a single script. webr_repl_project() packs several files into one link, and each file can be written as R in braces rather than as a string full of escaped newlines:

webr_repl_project(list(
  "main.R"    = { source("utils.R"); summarise(mtcars) },
  "utils.R"   = { summarise <- function(d) summary(d) },
  "README.md" = "# Analysis"
))

The braced blocks are captured, never run, so an assignment inside one leaves nothing behind in your session. For teaching, webr_repl_exercise() returns a paired scaffold and worked solution, and webr_repl_directory() turns a folder of scripts into one link per file, or into a single bundled link with single_link = TRUE.

Installation

livelink is on GitHub now, with a CRAN submission in review. Install the current version with pak:

# install.packages("pak")
pak::pak("coatless-rpkg/livelink")

Once it clears CRAN, install.packages("livelink") will work as well.

For a guided tour, the package ships vignettes on getting started, multi-file projects and Shiny apps, decoding and previewing links, links inside documents, and teaching with livelink.

Acknowledgements

Thanks to George Stagg for webR and its browser REPL, and to Winston Chang for the Shinylive share-URL feature. livelink writes to the share formats they built and opens in the runtimes they maintain, so it is mostly a friendly wrapper around a good idea they had. Pyodide is its own remarkable project, and it is what runs the Python side of Shinylive. Thanks, too, to peeky for stating the other half of this idea plainly enough that the feature became obvious. And for turning a braced R expression into clean, verbatim source, livelink borrows reprex’s stringify_expression(), which is MIT licensed. livelink is one step, and webrarian is the next, already taking shape.

For details, see the livelink news file entry below:

livelink news file entry for version 0.1.0

Features

  • Added webr_repl_link(), webr_repl_project(), webr_repl_exercise(), and webr_repl_directory() to create shareable webR REPL links for single scripts, multi-file projects, exercise and solution pairs, and whole directories.
  • Added shinylive_r_link(), shinylive_py_link(), shinylive_project(), and shinylive_directory() for R and Python Shiny apps on Shinylive.
  • Added decode_*() and preview_*() functions to extract the embedded files from any link or inspect them in memory, the exact inverse of link creation.
  • Code can be given as an R expression, a string, a file path, a named list of files, or clipboard content. Multi-file projects can be written as braced R rather than as escaped strings.
  • Added a livelink chunk engine and a chunk hook for knitr and Quarto, so a code chunk in a document can carry its own runnable link, with comments intact.
  • Returned objects work with repl_urls(), as.character(), format(), knit_print() (a clickable link in a rendered document), and as.data.frame().

GitHub Repository

References

Every external link used above, gathered in one place: