# How to Share an R Shiny App — shinyapps.io, Shinylive, and Static Reports

Canonical: https://commareports.com/share-shiny-app
Published: 2026-09-04

> Shiny needs a live R process, so shinyapps.io free tier is public with 25 active hours a month. Shinylive compiles to static WebAssembly, and an R Markdown render covers the case where readers only need the findings.

# 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](/alternatives/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.

```r
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](/host-html-file). 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:

```r
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:

```bash
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](/docs/sharing).

## 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.

**[Create your first report →](https://commareports.com/)**

### Related

- [Share an R Markdown report](/share-rmarkdown-report)
- [Share a Quarto report](/share-quarto-report)
- [Share a Streamlit app](/share-streamlit-app)
