# pytest-html Report Has No CSS or Shows an Empty Table — Fixes

Canonical: https://commareports.com/fix/pytest-html-report-no-css
Published: 2026-11-01

> report.html from pytest-html opens unstyled, or the results table is empty. The assets/ folder you left behind, --self-contained-html, the v4 JavaScript table, Jenkins CSP, and images that don't embed.

# pytest-html's report lost its styling

The suite finishes, `report.html` exists, and the copy someone opens from
Slack, email or a CI artifact looks like a 1996 web page — or has a summary
line and no test rows at all. Two different causes; one fix covers both.

## Cause 1: the `assets/` folder stayed behind

`pytest --html=report.html` writes two things:

```
report.html
assets/style.css
```

The report links the stylesheet by relative path. Move, attach or upload
`report.html` alone and that path points at nothing. The browser falls back
to default styles: black serif text, borderless tables, no pass/fail colors.

The fix is one flag:

```bash
pytest --html=report.html --self-contained-html
```

The CSS is inlined, and so is anything you pass with `--css custom.css`. The
file stands on its own.

## Cause 2: the table needs JavaScript (pytest-html 4+)

pytest-html 4.0 rewrote the report. The results table is no longer static
HTML. The test data is embedded in the page as JSON, and a script builds the
rows, filters and sort order when the page loads. That makes the report
smaller and faster for big suites. It also means **no script, no rows**.

| Where it's opened                      | What blocks the script                          | What you see                    |
| -------------------------------------- | ----------------------------------------------- | ------------------------------- |
| Jenkins HTML Publisher                 | Default CSP: `sandbox; default-src 'none'; ...` | No styles, no rows              |
| Outlook / Gmail preview                | Mail clients never run scripts                  | Summary only, or a download     |
| Jira / Confluence / Drive file preview | Rendered as text or in a script-less sandbox    | Source code or an empty shell   |
| GitHub Actions artifact                | Zip download; fine once unzipped and opened     | Works locally, not as a link    |
| Your own `<iframe sandbox>`            | No `allow-scripts`                              | Header and environment, no rows |

If you pinned `pytest-html<4` to get a static table back, that works, but you
give up the v4 fixes. Better to open the report somewhere that runs its
scripts.

### Jenkins specifically

Jenkins serves archived files with a strict Content-Security-Policy to stop
one job's HTML from attacking another user's session. It blocks the inline
`<style>` and `<script>` that pytest-html relies on. Your options, best first:

1. **Set a Resource Root URL** (Manage Jenkins → System). Reports are then
   served from a separate origin where the CSP isn't applied.
2. **Publish the report outside Jenkins** and link it from the build.
3. **Relax the CSP** with
   `System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")` in the
   script console. It works, but it turns off the protection for every job on
   the controller, and it resets on restart unless you set it as a JVM flag.

More on that trade-off in [Jenkins HTML reports](/ci/jenkins-html-report).

## Screenshots and attachments

Selenium and Playwright screenshots are the other thing that disappears.

```python
# Linked — breaks when the report moves
extras.append(pytest_html.extras.image("screenshots/login.png"))

# Embedded — survives --self-contained-html
extras.append(pytest_html.extras.png(driver.get_screenshot_as_base64()))
```

When a path-based extra is left over, pytest-html warns
`Self-contained HTML report includes link to external resource`. That warning
is the list of things that will 404 for whoever opens the file. The same
goes for videos and log files. Embed them, or host them next to the report.
See [images not showing in a sent HTML file](/fix/html-images-not-showing) for
the general case.

## Checklist

- [ ] `--self-contained-html` on the pytest command line (or in `addopts`)
- [ ] Screenshots added as base64, not file paths
- [ ] No `Self-contained HTML report includes link to external resource`
      warnings in the run output
- [ ] Opened somewhere that runs JavaScript, over `https://`

```ini
# pytest.ini — so nobody forgets the flag
[pytest]
addopts = --html=report.html --self-contained-html
```

## Getting it to people who don't have Jenkins

A self-contained report is one file, which makes it easy to put behind a
link. Comma stores the HTML as-is and renders it in a sandboxed frame with
scripts allowed. The v4 table, filters and collapsible tracebacks work. QA
leads, PMs and clients open one URL with no CI login. They can comment on a
failing test, and the next run lands as a new revision of the same report.
CI can publish it with one `curl` — see [publish from CI](/docs/ci).

## Try it

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

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

### Related

- [Share a pytest report](/share-pytest-report)
- [My HTML report lost its CSS](/html-report-broken-css)
- [Jenkins HTML reports](/ci/jenkins-html-report)
- [JUnit XML viewer](/tools/junit-xml-viewer) — for `pytest --junitxml=junit.xml` instead
- [Playwright report is blank](/fix/playwright-report-blank)
