SWMAPS DocumentationAPI portal

Build a map

Embed a web map

Render a complete map with hosted modules, npm, or a React component.

On this page

Complete hosted HTML example #

Prerequisites: a WebGL-capable browser, an HTTPS application page, the actual maps origin, and a maps-scoped key. Save this as an HTML page served by your application. All library URLs below come from the maps host.

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>SW map</title>
  <link rel="stylesheet" href="https://maps.example/vendor/maplibre-gl/maplibre-gl.css">
  <style>html,body,#map{height:100%;margin:0}</style>
</head>
<body>
  <div id="map" aria-label="Philippine map"></div>
  <script type="module">
    import { createMap } from 'https://maps.example/sw-map.js';
    const map = createMap({
      container: 'map', baseUrl: 'https://maps.example/',
      apiKey: 'YOUR_API_KEY', style: 'dark',
      mapOptions: { center: [120.9842, 14.5995], zoom: 12 }
    });
    map.on('error', event => console.error(event.error));
  </script>
</body>
</html>

Expected result: Manila in the dark style, navigation controls and a metric scale. A map needs an explicit container height. Your application CSP must allow the maps origin for modules, CSS, fonts/images, and fetches, and the renderer’s worker mechanism. This documentation does not relax your application’s CSP.

Bundle the client #

bash
npm install https://maps.example/npm/sw-maps-core-1.0.0.tgz   maplibre-gl@6.15.0 pmtiles@4.5.0
javascript
import 'maplibre-gl/dist/maplibre-gl.css';
import { configure, createMap } from '@sw-maps/core';
configure({ baseUrl: 'https://maps.example/', apiKey: 'YOUR_API_KEY' });
const map = createMap({ container: 'map', style: 'light' });

Use /npm/index.json on the maps host to discover published tarballs. Packages are served directly; there is no SW Maps npm registry. Peer dependencies must be available during your connected application build. Commit the lockfile and bundle the application for disconnected deployments.

React lifecycle and cleanup #

Install the same package and CSS above. This component uses the shared MapLibre instance from the core package. It creates the map after the container exists and removes it during cleanup, including React development remounts.

jsx
import { useEffect, useRef } from 'react';
import { createMap } from '@sw-maps/core';
import 'maplibre-gl/dist/maplibre-gl.css';

export function StationMap({ mapsRoot, apiKey }) {
  const container = useRef(null);
  useEffect(() => {
    const map = createMap({ container: container.current,
      baseUrl: mapsRoot, apiKey, style: 'dark',
      mapOptions: { center: [123.9, 10.3], zoom: 11 } });
    return () => map.remove();
  }, [mapsRoot, apiKey]);
  return <div ref={container} style={{ height: '70vh', minHeight: 320 }} />;
}

Configuration is shared within a module instance. Use one configured maps root/key for that instance; do not switch global configuration between concurrent maps expecting independent credentials. Render only on the client in server-rendered frameworks.

text
https://maps.example/?style=dark&panel=sectors&grid=mgrs,graticule#13/14.56/121.02
https://maps.example/?locate=1

The viewer’s fragment is #zoom/latitude/longitude, unlike the API’s longitude-first convention. A one-time ?key= can initialize its browser key, but a shared public URL should not contain a private application credential. URL options select tools; they do not give the parent page a viewer control API.

The current maps nginx configuration does not set a frame-ancestors or X-Frame-Options restriction. An iframe can be used only if the deployed gateway also permits framing. The API portal itself sends frame-ancestors 'none' and cannot be embedded. Prefer the module API when you need programmatic control.

html
<iframe title="SW Maps viewer"
  src="https://maps.example/?style=dark#11/10.3/123.9"
  width="100%" height="600" allow="geolocation"></iframe>

The viewer still needs its own API-key setup. Cross-origin parents cannot directly read its map state. Location additionally depends on HTTPS, browser permissions and the embedding site’s Permissions-Policy.

If the map stays blank #

  • Confirm the container has height, WebGL is enabled, and the CSS was loaded.
  • Inspect the style and tile requests: 401/403 indicates key/scope problems; a failed TLS request indicates certificate trust.
  • Check that PMTiles requests use Range and return 206. Proxies must preserve Content-Range, ETag and Accept-Ranges.
  • Do not mix MapLibre instances when registering protocols or adding controls. Use the maplibregl export from the shared package.
  • A style URL must resolve to JSON, not an application HTML fallback. Check baseUrl includes the configured gateway prefix.