# What Is the Same-Origin Policy? — And Why file:// Breaks Reports

Canonical: https://commareports.com/glossary/same-origin-policy
Published: 2026-09-11

> The same-origin policy stops one origin reading another's data. What counts as an origin, why a file opened from disk has an opaque one, and why that makes report shells load blank.

# Same-origin policy

**The same-origin policy is the browser rule that a document may only
read data from the same origin it was loaded from.** An origin is the
triple **scheme + host + port**.

| A                        | B                             | Same origin? |
| ------------------------ | ----------------------------- | ------------ |
| `https://example.com/a`  | `https://example.com/b`       | Yes          |
| `https://example.com`    | `http://example.com`          | No — scheme  |
| `https://example.com`    | `https://reports.example.com` | No — host    |
| `http://localhost:3000`  | `http://localhost:8080`       | No — port    |
| `file:///Users/x/a.html` | `file:///Users/x/b.json`      | No — opaque  |

It is the rule that stops a page you opened from reading your webmail in
another tab. Everything below is a consequence of it being unconditional.

## The opaque `file://` origin

A document opened from disk gets an **opaque origin**: one that matches
nothing, including other files in the same folder. Chrome has treated
`file://` this way for years; Firefox followed.

So a report that renders a shell and then fetches its results —
Allure's `data/` tree, Playwright's trace index, several coverage
trees — produces a blank page with a CORS error in the console. Nothing
is corrupt. The page asked for its own data and the browser refused.

```
Access to XMLHttpRequest at 'file:///…/data/suites.json' from origin 'null'
has been blocked by CORS policy: Cross origin requests are only supported
for protocol schemes: http, https…
```

`origin 'null'` is the tell.

## Fixing it locally

Serve the directory instead of opening the file:

```bash
cd allure-report && python3 -m http.server 8000   # then http://localhost:8000
allure open allure-report                         # tool-provided server
npx playwright show-report                        # same idea
```

A real `http://` origin makes the fetches legal. This is the entire
reason those wrapper commands exist
([Allure blank](/fix/allure-report-blank-page) ·
[Playwright blank](/fix/playwright-report-blank)).

## Why it resurfaces when sharing

A local server fixes it for you and nobody else. Emailing the file puts
the recipient back on `file://` with the same blank page —
and [localhost links do not work for other people](/fix/localhost-link-doesnt-work-for-others).

Publishing the output directory gives every reader a real HTTPS origin,
so the runtime fetches resolve for them exactly as they do behind your
local server. The report body runs inside a
[sandboxed iframe](/glossary/iframe-sandbox) with `allow-scripts` and no
`allow-same-origin`, which keeps interactivity working without granting
the report access to the account around it.

## Try it

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

**[Publish a report with a real origin →](https://commareports.com/)**

### Related

- [Allure report opens blank](/fix/allure-report-blank-page) · [Playwright report blank](/fix/playwright-report-blank)
- [iframe sandbox](/glossary/iframe-sandbox) · [Mixed content](/glossary/mixed-content)
- [Serve an HTML file locally](/serve-html-file-locally) · [Glossary](/glossary)
