# What Is Content Security Policy? — CSP, Reports and the Refused-to-Load Error

Canonical: https://commareports.com/glossary/content-security-policy
Published: 2026-09-11

> CSP is an HTTP header that tells the browser which sources a page may load. The directives that matter for published reports, how to read a violation, and why strict hosts break charts.

# Content Security Policy

**Content Security Policy (CSP) is an HTTP response header that tells the
browser which sources a page may load resources from.** Anything outside
the policy is blocked before the request goes out, and the browser writes
a refusal to the console.

```
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net;
  style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'
```

## The directives that decide whether a report renders

| Directive         | Governs                  | Symptom when it blocks             |
| ----------------- | ------------------------ | ---------------------------------- |
| `script-src`      | JavaScript               | Dead tables, empty chart boxes     |
| `style-src`       | CSS, including `<style>` | Unstyled wall of text              |
| `img-src`         | Images, `data:` URIs     | Broken image placeholders          |
| `connect-src`     | `fetch`, XHR, WebSocket  | Blank shell — the data never loads |
| `font-src`        | Web fonts                | Fallback glyphs, shifted layout    |
| `frame-ancestors` | Who may frame the page   | Blank iframe in Notion/Confluence  |

Generated reports trip `script-src` most often, because nearly every
chart library ships as a CDN `<script>` tag and nearly every corporate
host allows only `'self'`.

## Reading a violation

The console message names the cause precisely:

```
Refused to load the script 'https://cdn.plot.ly/plotly-2.27.0.min.js'
because it violates the following Content Security Policy directive: "script-src 'self'".
```

That is a CSP block. This is not:

```
Mixed Content: The page at 'https://…' was loaded over HTTPS, but requested
an insecure resource 'http://…'. This request has been blocked.
```

That is [mixed content](/glossary/mixed-content), and the fix is
different — see
[telling them apart](/fix/mixed-content-blocked-html-report).

## Two ways to survive a strict host

1. **Vendor the dependency.** Most generators can bundle the library
   into the output directory instead of linking a CDN — Plotly's
   `include_plotlyjs="directory"`, Bokeh's `CDN` → `INLINE`, Vega's
   local build. Same-origin scripts satisfy `script-src 'self'`.
2. **Publish where the report body is not subject to the site's policy.**
   Serving report HTML inside a
   [sandboxed iframe](/glossary/iframe-sandbox) lets the report keep its
   own dependencies while the surrounding application keeps a strict
   policy of its own.

The second is how Comma serves report bodies: the page runs with
`allow-scripts` and without `allow-same-origin`, so charts, filters and
drill-downs work as they do locally without the report gaining access to
the account around it ([interactive HTML reports](/interactive-html-reports)).

## Try it

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

**[Publish an interactive report →](https://commareports.com/)**

### Related

- [Mixed content](/glossary/mixed-content) · [iframe sandbox](/glossary/iframe-sandbox) · [Same-origin policy](/glossary/same-origin-policy)
- [Mixed content blocked](/fix/mixed-content-blocked-html-report) · [Plotly chart missing](/fix/plotly-chart-not-showing-in-html)
- [Troubleshooting](/fix) · [Glossary](/glossary)
