The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

shinysnap saves and restores the state of a running Shiny app. It
takes a snapshot (the input values plus any server-side values
you register), writes it to a plain JSON file that users can keep,
share, and diff, and restores it later into a different session, without
a page reload and without enableBookmarking(). Inputs
inside renderUI() that appear during the restore receive
their values as soon as they exist, so no timing code is needed, and a
report says what was applied, what never appeared, and what failed.
The word “snapshot” is used in the sense of a virtual machine or file
system snapshot: a saved state you can write to a file and restore
later. It has nothing to do with snapshot testing
(expect_snapshot in testthat and shinytest2) or with
screenshots.
You can install the development version of shinysnap from GitHub with:
# install.packages("pak")
pak::pak("nanxstats/shinysnap")A complete app with a save button and a restore upload:
library(shiny)
library(shinysnap)
ui <- fluidPage(
sliderInput("n", "Sample size", 10, 500, 100),
selectInput("model", "Model", c("simple", "complex")),
uiOutput("model_inputs"),
snap_download_button("save"),
snap_file_input("restore")
)
server <- function(input, output, session) {
snap_enable(app = "demo", version = "1.0.0")
output$model_inputs <- renderUI({
if (input$model == "simple") {
numericInput("rate", "Rate", 0.05)
} else {
sliderInput("k", "k", 1, 10, 3)
}
})
snap_download_handler("save")
snap_file_restore("restore")
}
shinyApp(ui, server)The saved file is readable:
{
"format": 1,
"app": {"name": "demo", "version": "1.0.0"},
"created": "2026-09-16T18:22:03Z",
"producer": {"shinysnap": "0.1.0", "shiny": "1.14.0", "r": "4.6.1"},
"inputs": {
"k": 3,
"model": "complex",
"n": 100
},
"values": {},
"bindings": {
"k": "shiny.sliderInput",
"model": "shiny.selectInput",
"n": "shiny.sliderInput"
},
"meta": {}
}Uploading it puts the app back into that state: the select is applied, the dynamic UI it controls re-renders, and the slider inside it gets its value the moment it exists.
Apps that do this by hand collect
reactiveValuesToList(input) into an .rds file
and, on upload, loop over session$sendInputMessage(), add a
special case for matrix inputs, guard every server-side value with
is.null() for files saved by older versions, and send the
values of dynamic inputs in waves of shinyjs::delay(),
because messages for inputs that are not on the page yet are dropped
silently. With shinysnap, the server side of such an app becomes:
snap_enable(app = "myapp", version = "2.4.0", exclude = c("^btn_", "^nav$"))
snap_track(prefs)
snap_track(main_options)
snap_download_handler(c("btn_save_main", "btn_save_details"))
snap_file_restore(
c("btn_restore_main", "btn_restore_details"),
validate = function(snap) {
if (is.null(snap$inputs$model)) stop("This file was not saved by this app.")
},
migrate = function(snap, from) {
if (is.null(snap$values$prefs$scientific)) snap$values$prefs$scientific <- FALSE
snap
}
)See vignette("shinysnap") for the full comparison and
vignette("dynamic-ui") for how the restore works.
snap_take(), snap_restore(): the snapshot
and the restore transaction, with a report.snap_write(), snap_read(): JSON files, zip
bundles that keep uploaded files, and (behind trust = TRUE)
.rds.snap_track(), snap_on_save(),
snap_on_restore(), snap_on_restored():
server-side values and hooks shaped like shiny’s bookmarking hooks.snap_restorer(): how an input’s value becomes the
message its binding understands; built-ins for shiny, bslib, and
shinyMatrix inputs.snap_download_button(),
snap_download_handler(), snap_file_input(),
snap_file_restore(): the UI boilerplate.snap_as_bookmark_url(),
snap_as_test_inputs(), snap_diff():
interoperate with bookmarking, testServer(), and version
control.MIT
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.