# Share a Leaflet Map — A URL, Not a File That Opens Blank

Canonical: https://commareports.com/share-leaflet-map
Published: 2026-09-14

> A Leaflet page loads its tiles and GeoJSON over the network, which a file:// origin blocks. Publish it to Comma and the map pans, zooms and popups work for everyone.

# Share a Leaflet map

A Leaflet map is about fifteen lines of HTML and it almost never survives being
sent to someone. The file arrives, it opens, and the page is grey.

Two causes, both boring, both fatal:

**The data does not load.** The map fetches its features at runtime:

```javascript
fetch("routes.geojson")
  .then((r) => r.json())
  .then((d) => L.geoJSON(d).addTo(map));
```

From a `file://` origin the browser blocks that as a cross-origin request. The
map object exists, the container has a height, and nothing is ever drawn — with
the failure visible only in the console. See
[why HTML reports go blank](/fix/plotly-chart-not-showing-in-html).

**The tiles do not load.** An `http://` tile URL or an `http://` Leaflet CDN
script inside an `https://` page is blocked as
[mixed content](/fix/mixed-content-blocked-html-report), silently.

## Publish the folder

Drop the HTML — together with the GeoJSON, any CSVs and any marker images —
into [Comma](https://commareports.com/):

- The HTML becomes the **report body**.
- `routes.geojson` and the rest upload alongside it, with relative references
  rewritten to the uploaded copies. `fetch("routes.geojson")` now resolves over
  `https://`, which is the step the filesystem cannot do.
- Scripts run inside a sandboxed iframe (`allow-scripts`, no
  `allow-same-origin`), so Leaflet initialises, tiles load, and popups, layer
  controls and the scale bar work.

Or generate it in a job and publish with one call:

```bash
curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html map.html \
        --arg t "Service coverage — $(date -u +%F)" '{title: $t, html: $html}')"
```

See the [API reference](/docs/api).

## Inline the library for anything durable

```html
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
```

is fine for a draft and a liability for a map attached to a decision — no
version pin, and a third party you have no agreement with. For a map that has
to render the same way next year, bundle Leaflet and its CSS into the page.

Small GeoJSON is worth inlining too: one file, nothing to fetch, nothing to
break.

## Keys and data

- Tile providers that need a key put that key in the published file. Use a
  domain-restricted public key.
- The features are real data. A map of customer addresses is personal data —
  aggregate to areas when the finding is a pattern, and set report access to
  private or team. See [sharing & access control](/docs/sharing).

## The map is where the question is

Maps get sent to people who are not going to open a repository: an operations
manager, a client, a council. Anchored comments keep their question on the map
— "is this catchment the new boundary or the old one?" — and the answer next to
it. See [commenting on HTML](/comment-on-html).

## Limits

- **Entry HTML: 5 MB** (inlined GeoJSON counts). Assets: 25 MB per file,
  **250 MB and 500 files total** — simplify geometry with `mapshaper` rather
  than shipping full-resolution boundaries a viewer cannot perceive.
- **Scripts run, sandboxed** — no same-origin access.
- **60 requests/minute per token.**

## Try it

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

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

### Related

- [Share a Folium map](/share-folium-map) · [Share a kepler.gl map](/share-kepler-gl-map)
- [Share a pydeck map](/share-pydeck-map) · [Share a D3 visualization](/share-d3-visualization)
- [Share an HTML folder](/share-html-folder) · [Interactive HTML reports](/interactive-html-reports)
