# Playwright HTML Report Is Blank or Won't Open — Fixes That Survive CI

Canonical: https://commareports.com/fix/playwright-report-blank
Published: 2026-09-07

> playwright-report/index.html renders empty when opened from disk, and the CI zip makes it worse. Why show-report works, what --reporter=html,open does, and how to get a shareable link.

# Playwright's report opens empty

`npx playwright test` finishes, `playwright-report/index.html` exists,
you double-click it — and get the header, the theme toggle, and no
tests.

## The cause

Playwright's reporter is a single-page app. For small runs it inlines a
base64 payload; past a threshold it splits results into sibling files
and fetches them at runtime. Either way it needs a real origin:
`file://` pages have an opaque origin, and `fetch` against sibling files
from there is blocked by the same-origin policy.

**Console says:** a CORS error against `file:///…`, or
`Failed to fetch`.

Attachments and traces make it worse — traces are zip archives the
viewer streams, so even a report whose test list loads can fail the
moment you click a trace.

## Locally: use the server Playwright ships

```bash
npx playwright show-report            # serves ./playwright-report over HTTP
npx playwright show-report path/to/report
```

Or configure it to open on failure:

```ts
// playwright.config.ts
reporter: [["html", { open: "on-failure" }]],
```

Both do the same thing — bind a local HTTP server so the fetches
resolve.

## In CI: the zip is the problem

The standard recipe uploads the report as an artifact:

```yaml
- uses: actions/upload-artifact@v4
  if: always()
  with:
    name: playwright-report
    path: playwright-report/
```

GitHub returns artifacts as **zip downloads** — there is no viewer, by
design ([why](/fix/github-actions-artifact-html-not-viewable)). So the
reviewer downloads it, unzips it, double-clicks `index.html`, and lands
back on the blank page at the top of this article. Two failure modes
stacked on each other.

GitLab's artifact browser can serve a single HTML file, but its own CSP
and path rules break the multi-file report; Jenkins' HTML Publisher
fights [its Content-Security-Policy](/ci/jenkins-html-report) for
anything with scripts.

## Publish the directory instead

Upload `playwright-report/` as a unit. `index.html` becomes the report
body; the `data/` payloads, trace zips, screenshots and videos upload
alongside it, and their relative references are rewritten to the
uploaded copies. The report loads over HTTPS, the trace viewer streams,
and the whole thing is a link.

```yaml
- name: Publish report
  if: always() # red builds are the ones with a reader
  run: |
    curl -sS -X PATCH \
      "https://commareports.com/api/v1/reports/${{ vars.COMMA_REPORT_ID }}" \
      -H "Authorization: Bearer ${{ secrets.COMMA_API_TOKEN }}" \
      -H "Content-Type: application/json" \
      --data @<(jq -Rs '{html: .}' playwright-report/index.html)
```

The multi-file call — the one that carries traces and videos — is in
[publish from CI](/docs/ci).

**Limits:** entry HTML 5 MB; assets 25 MB per file, 250 MB and 500 files
per report. Videos are the usual ceiling; `video: 'retain-on-failure'`
in the config keeps the payload sane.

## The part that changes review

A flaky test argument is unresolvable in a chat thread. On a published
report, the reviewer selects the failing assertion and comments **on
it** — the thread stays anchored to that test across revisions, so the
next person who hits the same flake reads the previous conclusion
instead of re-deriving it. See [comment on HTML](/comment-on-html).

## Try it

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

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

### Related

- [Share a Playwright report](/share-playwright-report)
- [GitHub Actions artifact HTML won't open](/fix/github-actions-artifact-html-not-viewable)
- [Allure report is a blank page](/fix/allure-report-blank-page)
- [Publish from CI](/docs/ci)
