CoursesGIS Basics — A Complete Introduction17.5 Lab — Publish a Web Map End-to-End
Module 17: Web GIS & APIsHands-on Lab

17.5 Lab — Publish a Web Map End-to-End

Ship a public interactive map: prepare vector tiles with Tippecanoe, host on a CDN, style with MapLibre.

Lesson 86 of 100·55 min read

Key takeaways

  • You can publish a production web map with free tools and a static host.
  • Tippecanoe generates vector tiles; MapLibre renders them; any static host serves them.
  • The entire pipeline is reproducible and cheap.

Introduction

In this lab you'll go from raw GeoJSON to a live interactive web map published on a public URL. Total time: about an hour. Tools: Tippecanoe, MapLibre GL, any static host (Netlify, Vercel, GitHub Pages, S3).

Prerequisites

  • tippecanoe installed (brew install tippecanoe or from source on Linux).
  • A basic HTML / JS environment.
  • Sample GeoJSON — use any open dataset (city buildings, parks, points of interest). We'll use "buildings in your city" as the running example.

Step 1 — Prepare GeoJSON

Download building footprints for a city from OSM / Overpass Turbo or an open-data portal. Clean:

Shell
ogr2ogr -f GeoJSON buildings.geojson input.gpkg buildings

Verify:

Shell
ogrinfo -so buildings.geojson buildings | head

Step 2 — Generate vector tiles

Shell
1tippecanoe -o buildings.mbtiles \
2  --name "Copenhagen buildings" \
3  --description "Building footprints" \
4  --minimum-zoom 10 \
5  --maximum-zoom 16 \
6  --drop-densest-as-needed \
7  --extend-zooms-if-still-dropping \
8  -l buildings \
9  buildings.geojson

Flag explanation:

  • -o output file.
  • --minimum-zoom / --maximum-zoom — tile pyramid range.
  • --drop-densest-as-needed — drop features at low zooms to keep tile sizes manageable.
  • -l layer name inside the MVT.

Tippecanoe output is an MBTiles file (SQLite-backed).

Step 3 — Convert MBTiles to PMTiles

Shell
pmtiles convert buildings.mbtiles buildings.pmtiles

(pmtiles CLI is a Go binary; install from the Protomaps GitHub.)

PMTiles is a single file the browser can read over HTTP range requests.

Step 4 — Host on a CDN or static hosting

Any of:

  • Netlify drop — drag and drop.
  • Vercelvercel deploy.
  • GitHub Pages — commit the file to a repo.
  • AWS S3aws s3 cp buildings.pmtiles s3://bucket --acl public-read.
  • Cloudflare R2 — similar.

Ensure CORS allows browser access if hosting on S3:

JSON
[{"AllowedMethods": ["GET"], "AllowedOrigins": ["*"], "AllowedHeaders": ["*"]}]

Step 5 — Write the MapLibre page

html
1<!DOCTYPE html>
2<html>
3<head>
4  <title>Copenhagen Buildings</title>
5  <link href="https://unpkg.com/maplibre-gl@3/dist/maplibre-gl.css" rel="stylesheet" />
6  <script src="https://unpkg.com/maplibre-gl@3/dist/maplibre-gl.js"></script>
7  <script src="https://unpkg.com/pmtiles@2/dist/index.js"></script>
8  <style>body, html, #map { margin: 0; padding: 0; height: 100vh; width: 100vw; }</style>
9</head>
10<body>
11  <div id="map"></div>
12  <script>
13    const protocol = new pmtiles.Protocol();
14    maplibregl.addProtocol('pmtiles', protocol.tile);
15[object Object]
16

Replace YOUR-URL with your hosted PMTiles URL.

Step 6 — Test

Open the HTML in a browser. You should see an OSM base map with your buildings extruded in blue. Pan, zoom, tilt — everything should work.

Step 7 — Add interactivity

Click handler to show building attributes:

JavaScript
1map.on('click', 'buildings', (e) => {
2  const f = e.features[0];
3  new maplibregl.Popup()
4    .setLngLat(e.lngLat)
5    .setHTML(`<strong>Height: ${f.properties.height || 'unknown'} m</strong>`)
6    .addTo(map);
7});

Step 8 — Publish and share

Commit your HTML to the same repo / host. Share the URL.

Congratulations — you've published a modern web map with zero server infrastructure.

Alternative path: if your goal is to share the dataset and get feedback rather than practise the full web stack, upload the GeoJSON to Atlas, style it, configure popups, and share the map link. The coded MapLibre path teaches infrastructure; the Atlas path is useful when the deliverable is a working map for collaborators.

Step 9 — Reflection

Record:

  • How big is your .pmtiles file?
  • What's the average tile size?
  • How long does initial load take?
  • What could you add next (filtering, legend, tooltip styling)?

Troubleshooting

  • Tiles not loading — check CORS headers on the PMTiles URL.
  • Buildings flat — verify the height attribute is in the source.
  • Map blank — check the browser console; usually a missing source-layer or a misformatted style.
  • Performance poor — reduce max zoom in tippecanoe, use --drop-densest-as-needed.

Self-check exercises

1. Why host as PMTiles instead of a tile server?

Zero infrastructure. PMTiles is one file on any static host — no compute, no tile-server process, no scaling concerns. Perfect for data that updates infrequently (daily or less) and for anyone wanting a cheap, reliable public map. Traditional tile servers add complexity, cost, and a running process to maintain.

2. What's the role of Tippecanoe in the pipeline?

Tippecanoe converts raw GeoJSON into a properly indexed, generalised vector tile pyramid. It decides which features to drop at low zoom (so tiles don't explode), respects attribute preservation, and outputs MBTiles — which pmtiles convert then packages into a single-file archive.

3. How would you add a filter that only shows buildings over 20 m tall?

Use a MapLibre filter:

JavaScript
1map.addLayer({
2  id: 'tall-buildings',
3  type: 'fill-extrusion',
4  source: 'buildings',
5  'source-layer': 'buildings',
6  filter: ['>', ['get', 'height'], 20],
7  paint: { ... }
8});

Or add a filter to an existing layer at runtime with map.setFilter().

Summary

  • Pipeline: GeoJSON → Tippecanoe → MBTiles → PMTiles → static host → MapLibre client.
  • Zero infrastructure, fully interactive, global-scale capable.
  • The same pattern scales from a single city to a planet-scale map.

Further reading

  • Tippecanoe documentation.
  • Protomaps PMTiles documentation.
  • MapLibre GL JS documentation.
  • GeoHipster "Maps without servers" tutorials.
Module test

Module 17: Web GIS & APIs

Answer these quick multiple-choice questions to check your understanding before moving on.

1. What is a web map made from?
2. What do vector tiles contain?
3. WMS, WFS, and WMTS are examples of what?