Share a Clinic.js report
Clinic.js is three tools and they answer three different questions:
clinic doctor --dest .clinic -- node app.js # what kind of problem is this?
clinic flame --dest .clinic -- node app.js # which function is burning CPU?
clinic bubbleprof --dest .clinic -- node app.js # where is the async time going?
doctor is the one to run first, because it classifies: event loop blocked,
I/O bound, garbage collection, or genuinely CPU bound. Its recommendation panel
is the most useful paragraph in Node performance tooling, and it is the part
that gets flattened when the report becomes a screenshot.
The reports are HTML, and they are stubbornly local. Depending on the tool and
version, the page pulls parts of its dataset at load time — and a browser blocks
those fetches from a file:// origin. So a colleague who double-clicks the file
you sent gets a page that renders, and charts that never populate.
Publish it
Point Clinic at a known directory and publish the folder:
clinic doctor --dest .clinic --autocannon [ -c 100 -d 30 http://localhost:3000/ ] \
-- node app.js
Drag .clinic/ (or a zip of it) into the app:
- The generated
*.htmlbecomes the report body. - The data directory beside it uploads as assets and its relative references
are rewritten to the uploaded copies — which is the step
file://cannot do. - Scripts run inside a sandboxed iframe (
allow-scripts, noallow-same-origin), so the charts, the brush-to-zoom on the timeline, and the recommendation panel all work.
Publish the verdict and the follow-up together
A flame report on its own is a picture of some functions. A doctor report
that says "the event loop is blocked" followed by the flame graph showing
crypto.pbkdf2Sync at the top is a diagnosis anybody can follow.
PATCH both to one report id:
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 "$(ls -t .clinic/*.html | head -1)" \
--arg t "Clinic flame — /login, sync hashing" '{title: $t, html: $html}')"
One URL, a revision per capture. The revision list is the investigation.
From CI
Event-loop regressions are invisible until latency alarms fire. Run a fixed load in the job:
clinic doctor --dest .clinic --autocannon [ -c 50 -d 20 http://localhost:3000/api ] \
-- node server.js
then PATCH the HTML to the same report id every run. A stable URL per service turns "is p99 creeping?" into a comparison rather than a hunch.
What review adds
- Anchored threads on the stall — see commenting on HTML.
- Revisions, so a fix is verifiable against the run that motivated it.
- Access per report — private, team, domain-gated or named reviewers. See the sharing model.
Limits
- Entry HTML: 5 MB. Assets: 25 MB per file, 250 MB and 500 files total. Clinic's data directory is the part that grows with capture length — a 20-30 second load run is the right size for something meant to be read.
- 60 requests/minute per token.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.