Add an editable dataset in OpenLayers
Copy JavaScript and React examples for loading a published dataset revision as GeoJSON from the Mappinest Dataset API in OpenLayers.
Overview
This guide shows how to fetch the latest published dataset revision as one GeoJSON FeatureCollection and render it in OpenLayers. Use this path when the full dataset fits your application flow and you want to manage supported features in Dataset Studio.
Create a dataset from .geojson or .json in Datasets, or start drawing in Studio. The examples use the `mappinest.world-cities` sample. Copy the owner-scoped Dataset ID from the Datasets page when working with your own data.
The example uses ol-mapbox-style for the background map, then parses the Dataset response with the OpenLayers GeoJSON format using the map projection.
API key scopes
The browser API key needs datasets:read. The examples also use the light map style as a background, so add maps:read when the key has explicit scopes. Add every development and production origin to the allowed-domain policy.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Mappinest Dataset GeoJSON with OpenLayers</title>
<link href="https://unpkg.com/ol@10.9.0/ol.css" rel="stylesheet" />
<script src="https://unpkg.com/ol@10.9.0/dist/ol.js"></script>
<script src="https://unpkg.com/ol-mapbox-style@13.4.1/dist/olms.js"></script>
<style>
body { margin: 0; }
#map { height: 100vh; width: 100vw; }
</style>
</head>
<body>
<div id="map"></div>
<script>
const apiKey = 'YOUR_MAPPINEST_KEY';
const datasetId = 'mappinest.world-cities';
async function initMap() {
const map = new ol.Map({
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([0, 20]),
zoom: 2
})
});
await window.olms.apply(
map,
`https://api.mappinest.com/v1/maps/light/style.json?key=${apiKey}`
);
const response = await fetch(
`https://api.mappinest.com/v1/datasets/${datasetId}.geojson?key=${encodeURIComponent(apiKey)}`
);
if (!response.ok) {
throw new Error('Dataset GeoJSON request failed.');
}
const dataset = await response.json();
const features = new ol.format.GeoJSON().readFeatures(dataset, {
featureProjection: 'EPSG:3857'
});
const source = new ol.source.Vector({ features });
map.addLayer(new ol.layer.Vector({
source,
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
fill: new ol.style.Fill({ color: '#2563eb' }),
stroke: new ol.style.Stroke({ color: '#ffffff', width: 1.5 })
})
})
}));
const extent = source.getExtent();
if (!ol.extent.isEmpty(extent)) {
map.getView().fit(extent, { padding: [40, 40, 40, 40], maxZoom: 13 });
}
}
initMap();
</script>
</body>
</html>import { useEffect, useRef } from 'react';
import Map from 'ol/Map';
import View from 'ol/View';
import GeoJSON from 'ol/format/GeoJSON';
import { isEmpty } from 'ol/extent';
import VectorLayer from 'ol/layer/Vector';
import { fromLonLat } from 'ol/proj';
import VectorSource from 'ol/source/Vector';
import CircleStyle from 'ol/style/Circle';
import Fill from 'ol/style/Fill';
import Stroke from 'ol/style/Stroke';
import Style from 'ol/style/Style';
import { apply } from 'ol-mapbox-style';
import 'ol/ol.css';
const apiKey = 'YOUR_MAPPINEST_KEY';
const datasetId = 'mappinest.world-cities';
export default function MappinestOpenLayersDatasetMap() {
const containerRef = useRef<HTMLDivElement | null>(null);
const mapRef = useRef<Map | null>(null);
useEffect(() => {
if (!containerRef.current || mapRef.current) return;
let cancelled = false;
const map = new Map({
target: containerRef.current,
view: new View({ center: fromLonLat([0, 20]), zoom: 2 })
});
mapRef.current = map;
async function loadDataset() {
await apply(
map,
`https://api.mappinest.com/v1/maps/light/style.json?key=${apiKey}`
);
const response = await fetch(
`https://api.mappinest.com/v1/datasets/${datasetId}.geojson?key=${encodeURIComponent(apiKey)}`
);
if (!response.ok) throw new Error('Dataset GeoJSON request failed.');
const dataset = await response.json();
if (cancelled) return;
const features = new GeoJSON().readFeatures(dataset, {
featureProjection: 'EPSG:3857'
});
const source = new VectorSource({ features });
map.addLayer(new VectorLayer({
source,
style: new Style({
image: new CircleStyle({
radius: 6,
fill: new Fill({ color: '#2563eb' }),
stroke: new Stroke({ color: '#ffffff', width: 1.5 })
})
})
}));
const extent = source.getExtent();
if (!isEmpty(extent)) {
map.getView().fit(extent, { padding: [40, 40, 40, 40], maxZoom: 13 });
}
}
void loadDataset().catch((error) => {
if (!cancelled) console.error(error);
});
return () => {
cancelled = true;
map.setTarget(undefined);
mapRef.current = null;
};
}, []);
return <div ref={containerRef} style={{ height: 420, width: '100%' }} />;
}Dataset GeoJSON URL pattern
Create a browser API key in API Keys & Access, then replace YOUR_MAPPINEST_KEY. The examples use the `mappinest.world-cities` sample. Replace the Dataset ID when working with your own data.
Adjust the example center or let the map client fit the returned feature bounds when your dataset is in another location.
Refresh after publishing
Publishing in Studio or applying a server mutation creates a new immutable revision. Fetch the same endpoint URL again to receive the latest authorized revision. For explicit revalidation, store the response ETag and send it in If-None-Match. A 304 Not Modified response has no GeoJSON body, so keep the FeatureCollection already loaded by the application.
Common errors
What to read next
Last updated: September 10, 2026