# Share a pprof Profile — Without Telling People to Run go tool pprof

Canonical: https://commareports.com/share-pprof-profile
Published: 2026-09-15

> go tool pprof -http opens on your machine and nowhere else. Export an SVG flame graph or a speedscope page, publish it to Comma, and the profile becomes a link that still zooms.

# Share a pprof profile

`go tool pprof -http=:8080 cpu.pprof` is one of the best profiling
experiences in any language, and it has exactly one flaw: it runs on
localhost. The moment the finding needs a second reader, the interface
degrades to a screenshot of a flame graph, which is a picture of a thing whose
entire value is that you can click it.

## Option 1: an SVG flame graph

```bash
# apt-get install graphviz  (pprof shells out to dot)
go tool pprof -svg cpu.pprof > cpu.svg
```

The SVG is self-contained and keeps click-to-zoom and hover tooltips, because
the script travels inside the file. Wrap it in a one-line HTML host if you
want a title above it, or publish the SVG as the report body.

## Option 2: speedscope

```bash
npm i -g speedscope
speedscope cpu.pprof   # opens locally; use the app's Export to save an HTML file
```

Speedscope reads pprof's protobuf format directly and its exported page keeps
the time-order view, the left-heavy view, the sandwich view and search. It is
the better option when the reader needs to explore rather than confirm.
See also [sharing a speedscope profile](/share-speedscope-profile).

## Publish it

Drag the file into [the app](https://commareports.com/), or from CI:

```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 cpu.html \
        --arg title "CPU profile — $GITHUB_SHA" '{title: $title, html: $html}')"
```

Scripts run inside a sandboxed iframe (`allow-scripts`, no
`allow-same-origin`), so the zooming works at the URL the same way it worked
locally.

## Profiles from production

```bash
curl -o cpu.pprof "http://prod-host:6060/debug/pprof/profile?seconds=30"
```

Two things follow from that. First, render and publish rather than passing
around the raw `.pprof` — the raw file needs the reader to have Go installed
and the matching binary for symbolisation. Second, **restrict the access
level**: a profile enumerates your internal package and function names. See
the [sharing model](/docs/sharing).

## Why the link beats the screenshot

- **Anchored threads** on the hot frame, so the fix is discussed where the
  cost is visible. See [commenting on HTML](/comment-on-html).
- **Revisions** — publish before and after the optimisation to the same id and
  the improvement is a diff, not an assertion.

## Limits

- **Entry HTML: 5 MB.** Assets: 25 MB per file, 250 MB and 500 files total.
  A deep profile's SVG can be large — `-nodecount` trims it for the shareable
  view.
- **60 requests/minute per token.**

## Try it

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

**[Publish a profile →](https://commareports.com/)**

### Related

- [Share a flame graph](/share-flamegraph) · [Share a speedscope profile](/share-speedscope-profile)
- [Share a Go test report](/share-go-test-report) · [Share a Ginkgo report](/share-ginkgo-report)
- [Share an async-profiler report](/share-async-profiler-report) · [Share a hyperfine benchmark](/share-hyperfine-benchmark)
