Share the analysis, not a screenshot of it

The analysis is done. It renders beautifully at localhost:8888. Then someone asks for it, and the options are all bad: a 30 MB HTML export Slack refuses to preview, a file:// link that opens blank on their machine, a GitHub URL that shows raw JSON, or — most commonly — a screenshot of the chart pasted into a deck, which destroys the only thing that made the chart worth building.

Publish the export

jupyter nbconvert --to html --embed-images analysis.ipynb
import os, requests

r = requests.post(
    "https://commareports.com/api/v1/reports",
    headers={"Authorization": f"Bearer {os.environ['COMMA_API_TOKEN']}"},
    json={
        "title": "Churn cohort analysis — September",
        "html": open("analysis.html").read(),
    },
)
print(r.json()["url"])

The stakeholder gets a URL. No Python, no kernel, no clone, no nbviewer, no "can you re-run it for me."

The same path works for whatever you actually use: Jupyter · Quarto · R Markdown · marimo · Observable · Colab · Databricks · Papermill · Voilà.

And for charts published on their own: Plotly · Altair · Bokeh · Vega-Lite · ECharts · HoloViews · D3 · SHAP · Folium.

Interactivity is the point

A published report runs its scripts in a sandboxed iframe (allow-scripts, no allow-same-origin). Concretely: hover tooltips work, legend toggles work, zoom and brush selection work, a sortable DataFrame.to_html() table sorts, a ydata-profiling or Sweetviz report keeps its tabs.

Two exports that famously break, and why:

  • Widgets render blank — ipywidgets need embedded widget state or a live kernel. Export flag, not hosting.
  • Plotly chart missing — the export pointed at a CDN the reader's network blocked, or include_plotlyjs was set to False. Embed it.

Questions land on the number

This is the part that changes how the work goes. Stakeholder feedback on analysis is almost always about one figure — a cohort that looks wrong, a denominator they expected to be different, a date range they assumed. Sent as a Slack message, that question arrives detached from the thing it's about and costs you twenty minutes of reconstruction.

Anchored comments keep it attached. They highlight the cell; the thread lives on the cell. See commenting on HTML.

When the answer is "you're right, it was deduplicated wrong," re-run and publish a revision at the same URL. The link in the ticket stays valid, and the earlier version stays visible — which is what you need when someone quotes a number from a version you have since corrected.

When the analysis should refresh itself

A weekly cohort refresh is a routine: a schedule, a re-run, a revision at the same address. Nobody asks "is this the latest?" because there is only one link. See weekly analytics digest.

Worth knowing

  • Start private. Analysis usually names customers, revenue, or headcount. Publish private, widen once you've read it — see sharing & access control.
  • Readers are free. Pricing is per publisher. Sharing with the whole commercial team costs nothing.
  • Export folders wholesale. Quarto and nbconvert output with a _files/ sibling directory should be published as a whole folder so relative asset links resolve.
  • Limits. Entry HTML 5 MB; assets 25 MB per file, 250 MB and 500 files per report. Embedded base64 images are the usual reason an export is large — publishing the folder is the fix.

Try it

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

Start free →

Related