How to Share a Quarto or R Markdown Report Behind Company Auth

Render the report to a single self-contained HTML file, then publish that file behind your company login. The analysts keep writing in Quarto or R Markdown. The stakeholders just open a link.

TL;DR
A Quarto or R Markdown report renders to one self-contained HTML file when you embed its resources. Then `dsp publish report.html` returns a permanent URL that only people with your company email can open. No RPubs, no public Quarto Pub link, no Posit Connect server to license and run.

Render the report to a single self-contained HTML file, then publish that file behind your company login. The analysts keep writing in Quarto or R Markdown. The stakeholders just open a link.


Why this is harder than it should be

Quarto and R Markdown produce excellent HTML reports: cross-referenced figures, tabsets, interactive htmlwidgets, a floating table of contents. The format is right. The distribution is the problem.

A report with revenue projections, churn analysis, or an unreleased experiment readout cannot go on a public URL. That rules out the two easiest paths:

  • RPubs publishes R Markdown to a public page. Anyone with the link reads it.
  • Quarto Pub does the same for Quarto. Public by default.

The private paths cost more than the report is worth:

  • Posit Connect (formerly RStudio Connect) handles auth and scheduling well, but it's a licensed server your team has to buy, deploy, and administer. Heavy infrastructure for "let six people read this quarter's analysis."
  • GitHub Pages needs a repo, and a private one needs every viewer to have a GitHub account with access.
  • Email the HTML file works until the report references a _files folder, at which point the charts break the moment the file moves.

So a polished report ends up as a screenshot in a thread, and the cross-references, the interactive widgets, and the table of contents all get lost.


Step 1: Render to one self-contained file

The key is embedding every dependency (CSS, JavaScript, fonts, images) into a single HTML file so it survives being moved or uploaded.

Quarto. Set embed-resources in the document header, then render:

---
title: "Q2 Retention Analysis"
format:
  html:
    embed-resources: true
    toc: true
---
quarto render retention.qmd

R Markdown. The html_document format already defaults to self-contained output, so a plain render gives you one file:

rmarkdown::render("retention.Rmd")

If you've overridden the default, confirm self_contained: true is set under html_document in the YAML header.

The check is the same either way: move the .html to another folder, open it, and make sure every figure, table, and widget still renders. One file, no sidecar folder.


Step 2: Publish it behind company auth

display.dev publishes a single HTML file to a permanent URL and gates it with your identity provider. Viewers authenticate with the Google Workspace or Microsoft 365 account they already use.

npm install -g @displaydev/cli
 
dsp login
 
dsp publish ./retention.html

Drop that URL into Slack, the board doc, or an email. Anyone with a company email opens it and reads the full report with its table of contents, tabsets, and interactive widgets intact. People outside your domain get a login wall.

That's gated publishing: publish in one action, gate by company identity, keep a stable link. Readers don't get charged per seat, so circulating the report widely costs nothing extra, unlike the per-seat model that quietly punishes broad sharing.


How the options compare

MethodPrivate to your companyViewer needs an accountServer to runInteractive widgets survive
RPubsNo (public)NoNoYes
Quarto PubNo (public)NoNoYes
Posit ConnectYesYesYes (licensed)Yes
GitHub Pages (private)YesYes (GitHub)NoYes
Email the HTMLYesNoNoOnly if self-contained
Quarto/RMarkdown + display.devYes (SSO)Company email onlyNoYes

Refreshing a scheduled report

Most Quarto and R Markdown reports run on a cadence: weekly retention, monthly board numbers. Re-render and re-publish to the same URL so every saved link updates together:

quarto render retention.qmd
dsp publish ./retention.html --id <shortId> --base-version <currentVersion>

The --id keeps the URL stable; dsp get <shortId> shows the current version to pass as the baseline. Wire the same two commands into the job that already runs the render, and the published report stays current without anyone re-sending a link. The GitHub Actions guide covers running it from CI with an API key.


Where this fits

A Quarto report is one shape of a recurring problem: someone produces rich HTML and the audience lives outside the tool that made it. The same flow publishes Jupyter notebooks, Plotly and other data dashboards, and internal docs behind the same company login.


FAQ

Do viewers need R, Python, or Quarto installed?+

No. The rendered HTML carries everything it needs. Readers open a URL in a browser with nothing installed.

Will `htmlwidgets`, Leaflet maps, and Plotly charts still work?+

Yes, as long as the report is rendered self-contained so the widget JavaScript is embedded in the file. Quarto does this with embed-resources: true; R Markdown's html_document does it by default. Widgets that need a live R or Python process behind them (like a running Shiny app) won't, because a static file has no server.

Isn't this what Posit Connect is for?+

Posit Connect handles auth, scheduling, and Shiny hosting, and it's the right call if you need all of that. For the common case of sharing a rendered report behind company login, it's a licensed server to deploy and maintain. Gated publishing covers the read-only sharing case in one command with no server.

Can I keep the same URL when the data changes?+

Yes. Re-publish with --id <shortId> and the current --base-version. The content updates and the link stays the same, so bookmarks and pasted URLs keep working.

What about a Shiny app, not a static report?+

Shiny needs a running R server, so it can't be published as a static file. If the app can export its current state as a self-contained HTML report, publish that. For a live, interactive Shiny app, you need server hosting.

Publish your first artifact in 15 seconds.

Free tier. No credit card. One-time password auth for viewers on free, Google + Microsoft SSO on Pro (€49/month flat).

Get started free →See pricing