Share a pkgdown site

pkgdown turns roxygen comments, vignettes and a NEWS.md into a real documentation site — a reference index, one page per exported function with its examples rendered, articles from the vignettes, and full-text search.

pkgdown::build_site()      # → docs/

The output is a multi-page site:

docs/
├─ index.html
├─ reference/  index.html  fit_model.html  predict.fit.html …
├─ articles/   getting-started.html …
├─ search.json          ← fetched at load
└─ deps/  bootstrap-5/  …

Two things go wrong from here.

Locally, docs/index.html opens and looks correct, and the search box does nothing. pkgdown fetches search.json at load, and the browser blocks that fetch from a file:// origin. There is no error on screen; search just returns no results forever.

In review, the docs change is a roxygen diff in a pull request. Nobody can see the rendered page, so documentation gets reviewed as source comments — which is why so much R package documentation has examples that do not run.

Publish the folder

Drag docs/ (or a zip of it) into the app:

  • index.html becomes the report body.
  • Every reference page, vignette, search.json and the Bootstrap deps upload alongside it, with relative references rewritten to the uploaded copies — so navigation works and the search index actually loads.
  • Scripts run inside a sandboxed iframe (allow-scripts, no allow-same-origin).

Review docs on the branch

This is where it earns its place. Build the site in CI and PATCH a report id per branch:

Rscript -e 'pkgdown::build_site(preview = FALSE)'

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 docs/index.html \
        --arg t "pkgdown — $GITHUB_HEAD_REF" '{title: $t, html: $html}')"

Post the URL on the pull request and the reviewer reads the rendered function reference — with the examples' output as it will actually appear — instead of reading #' comments and guessing.

build_site(preview = FALSE) matters in CI: the default tries to open a browser, which fails on a headless runner.

Private and internal packages

A large share of R code lives in packages that are never going to CRAN: internal modelling packages, a company's data-access layer, a regulated client's analysis toolkit. GitHub Pages is a poor fit for those — it is world-readable by default and needs the repo configured for it.

Publishing the folder gives you the same site with real access control: private, team, domain-gated, or named reviewers. See the sharing model.

For a released public package

If the package is public and released, a stable Pages URL is genuinely the right home for its documentation, and usethis::use_pkgdown_github_pages() sets that up in one call. Use this for the cases Pages does not cover: pre-release review, private packages, and sending a client the docs for the version you delivered rather than the current main.

What review adds

  • Anchored threads on a function's reference page — see commenting on HTML.
  • Revisions, so docs changes across a review round are a diff.
  • Access per report for internal packages.

Limits

  • Entry HTML: 5 MB. Assets: 25 MB per file, 250 MB and 500 files total. A package with several hundred exported functions generates a page each — the 500-file cap is the one to watch on very large packages.
  • 60 requests/minute per token.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Publish a docs site →

Related