# Share a Cucumber HTML Report — One Link, Comments on Failed Scenarios

Canonical: https://commareports.com/share-cucumber-report
Published: 2026-08-22

> Cucumber's HTML formatter writes one self-contained file that CI then buries in an artifact zip. Publish it to Comma with one curl: a stable URL per suite, threads pinned to failing scenarios, a revision per run.

# Share a Cucumber HTML report

Cucumber reports exist to be read by people who don't run the suite. That
is the whole premise of BDD: the scenarios are written in the language of
the business so the business can check them. Then CI takes the report,
zips it, and puts it behind a login the business doesn't have.

The mismatch is the problem, not the format. `@cucumber/html-formatter`
already produces exactly the right artifact — one self-contained file,
the run's messages embedded, a bundled React app rendering the feature
tree. It needs a URL, not a build system.

## Publish it with one curl

```bash
npx cucumber-js --format html:cucumber-report.html

curl -fsS -X PATCH \
  "https://commareports.com/api/v1/reports/$COMMA_REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html cucumber-report.html \
        --arg title "Acceptance — $(git rev-parse --short HEAD)" \
        '{title: $title, html: $html}')"
```

`PATCH` on a saved report id instead of `POST` means every run appends a
revision **at the same URL**. The link in the team channel is written
once and never goes stale. Use a [scoped token](/docs/api-tokens) —
`reports:write` is all this needs.

For cucumber-jvm, the same file comes out of
`@CucumberOptions(plugin = "html:target/cucumber-report.html")`; for
Behave or SpecFlow, point the curl at whatever single HTML file the
reporter wrote. Nothing here is JS-specific.

## What changes when the report has a URL

- **A failing scenario gets a thread on it.** A reviewer highlights the
  step that broke and pins a comment there — "this is the pricing change
  from Tuesday, expected" — and the thread stays put across the next
  dozen runs. See [commenting on HTML](/comment-on-html).
- **Product owners can actually open it.** No CI seat, no repo access, no
  zip. The [sharing model](/docs/sharing) is per report: private,
  team-visible, domain-gated, or named reviewers.
- **Run-over-run diffs.** "Which scenarios flipped since the last green
  build?" is a revision diff rather than two tabs and a memory test.
- **Announcements.** A [webhook](/docs/api) on `revision.created` posts
  each run into Slack.

## Limits worth knowing

- **HTML body: 5 MB.** Base64 screenshots inlined by the formatter add up
  quickly. Past the cap, upload them as [assets](/docs/api) (25 MB per
  file, 250 MB per report) instead of inlining.
- **Scripts run, sandboxed.** The report renders in an iframe with
  `sandbox="allow-scripts"` and no `allow-same-origin`, so the interactive
  feature tree works. Reports that fetch sibling files at view time need
  those files uploaded as assets — see
  [Playwright](/share-playwright-report) for that shape.
- **Rate limits are per token**, 60/minute. One publish per build is not
  close.

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited
revision history. Publish one suite and send the link to someone who has
never logged into your CI.

**[Create your first report →](https://commareports.com/)**

### Related

- [Publish from CI](/docs/ci) — the general pipeline pattern
- [Playwright](/share-playwright-report) · [Cypress](/share-cypress-report) · [pytest](/share-pytest-report) · [Allure](/share-allure-report)
- [Robot Framework](/share-robot-framework-report) — same problem, different runner
