How to share an R Shiny app
Shiny's whole design is a live R process that recomputes outputs when inputs change. That is what makes it good, and it is why "just send me the app" has never had a simple answer. There are now three genuinely different routes, and picking the wrong one is the usual source of pain.
Route one: host the running app
shinyapps.io. The path of least resistance — rsconnect::deployApp() and
you have a URL. The free tier is limited in ways that matter for sharing: a
small number of applications, roughly 25 active hours per month, and apps that
are publicly reachable, since authentication is a paid feature. Read the
current plan page rather than trusting a remembered number. What is
structurally true regardless of tier: active-hour metering means a link left
open in someone's tab burns your quota.
Posit Connect / Posit Connect Cloud. The enterprise answer, with real authentication and scheduling. If your organization already runs it, deploy there and stop reading. If it does not, standing it up to share one app is not proportionate. See Posit Connect alternatives for the trade-offs.
Self-hosted Shiny Server. Full control, a server to operate.
Route two: compile it to static with Shinylive
Shinylive compiles the app to WebAssembly so R runs in the reader's
browser. There is no server, and the output is a static folder with an
index.html — which means you can upload it anywhere that serves static files
and the app stays interactive.
shinylive::export("myapp", "site")
This is the best answer when it applies, and it does not always apply. The constraints are real: the data has to travel with the bundle, so a live database query is out; every package you use must be available for WebAssembly; and the bundle is large, because it ships an R runtime. For a teaching app, a self-contained simulator, or a parameter explorer over a modest dataset, it is close to ideal.
A Shinylive export is a folder with relative references, so it needs to be
served over HTTP with the whole tree intact — the same requirement as any
multi-file HTML report. Opening index.html from disk
fails for the usual file:// reasons.
Route three: publish the findings, not the app
This is the case most requests actually are. A colleague, a reviewer, or a client wants to know what the analysis concluded. They are not going to move the slider, and building a deployment path for a reader who will look once is the wrong trade.
R already renders self-contained HTML:
rmarkdown::render("analysis.Rmd",
output_options = list(self_contained = TRUE))
self_contained = TRUE inlines the CSS, JavaScript and images into one file —
htmlwidgets and plots included, so a plotly or leaflet chart stays interactive
with nothing fetched at view time. Quarto does the same with embed-resources: true.
Then publish it, and keep publishing to the same id:
curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
-H "Authorization: Bearer $COMMA_API_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile html analysis.html \
--arg title "Trial analysis — $(date +%F)" '{title: $title, html: $html}')"
What the review layer adds
Statistical review is a conversation about specific figures, and email is a terrible container for it. A published render carries anchored threads: a reviewer highlights the interaction term and pins "this is the unadjusted model, the pre-registered one is in the appendix." That thread stays attached across revisions, so when the analysis is re-run in six weeks the objection is still visible next to the number it was about.
Readers need no R, no shinyapps quota, and no seat — access is a setting on the report: private, team, domain-gated or link.
Choosing
- Reader will genuinely interact and the data can ship with the app → Shinylive, upload the folder.
- Reader will interact and the app needs a live database → host it, properly, with auth.
- Reader wants the findings → render and publish, and stop maintaining a server for an audience of readers.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.