Live Data
maplibre-yaml makes it easy to keep your map data fresh with automatic polling, Server-Sent Events (SSE), and WebSocket streaming.
Polling (auto-refresh)
Section titled “Polling (auto-refresh)”The simplest way to keep data current is polling - fetching data at regular intervals:
source: type: geojson url: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson" refreshInterval: 60000 # Refresh every 60 seconds (milliseconds)Controlling polling
Section titled “Controlling polling”const renderer = new MapRenderer(container, config);
// Pause updates (e.g., when tab is inactive)renderer.pauseRefresh("earthquakes");
// Resume updatesrenderer.resumeRefresh("earthquakes");
// Trigger immediate refreshawait renderer.refreshNow("earthquakes");Update strategies
Section titled “Update strategies”When new data arrives, how should it combine with existing data?
Replace (default)
Section titled “Replace (default)”New data completely replaces old data:
source: type: geojson url: "https://..." refreshInterval: 30000 updateStrategy: replace # Default behaviorUse for: Complete datasets that are re-fetched in full each time.
Update existing features, add new ones, keep features not in the update:
source: type: geojson url: "https://api.example.com/vehicles" refreshInterval: 5000 updateStrategy: merge updateKey: "vehicleId" # Match features by this propertyUse for: Entity tracking where each feature has a unique ID.
Example scenario:
- Initial data: Vehicles A, B, C
- Update contains: A (new position), D (new vehicle)
- Result: A (updated), B (unchanged), C (unchanged), D (added)
Append with window
Section titled “Append with window”Add new features while limiting total count or age:
source: type: geojson stream: type: sse url: "https://stream.example.com/events" updateStrategy: append-window windowSize: 100 # Keep latest 100 features windowDuration: 3600000 # Or features from last hour timestampField: "time" # Property containing timestampUse for: Event streams, activity feeds, time-series data.
Server-Sent Events (SSE)
Section titled “Server-Sent Events (SSE)”For real-time push updates, use SSE streaming:
source: type: geojson stream: type: sse url: "https://stream.example.com/events" reconnect: true # Auto-reconnect on disconnect reconnectMaxAttempts: 10 # Give up after 10 failures reconnectDelay: 1000 # Initial delay (doubles each retry) updateStrategy: merge updateKey: "id"How SSE works
Section titled “How SSE works”- Browser opens persistent HTTP connection
- Server sends data as events occur
- Browser automatically reconnects if connection drops
- Each message updates the map
SSE configuration options
Section titled “SSE configuration options”| Option | Default | Description |
|---|---|---|
reconnect | true | Auto-reconnect on disconnect |
reconnectMaxAttempts | 10 | Max reconnection attempts |
reconnectDelay | 1000 | Initial delay (ms) |
reconnectMaxDelay | 30000 | Max delay between retries |
eventTypes | ['message'] | Event types to listen for |
WebSocket streaming
Section titled “WebSocket streaming”For bidirectional communication, use WebSocket:
source: type: geojson stream: type: websocket url: "wss://stream.example.com/data" reconnect: true updateStrategy: merge updateKey: "id"WebSocket is useful when you need to send messages to the server (e.g., subscribing to specific data channels).
Handling connection states
Section titled “Handling connection states”Monitor streaming connection status:
const renderer = new MapRenderer(container, config);
renderer.on("layer:stream-state", ({ layerId, state }) => { // state: 'connecting' | 'connected' | 'reconnecting' | 'disconnected' | 'failed' console.log(`${layerId} stream: ${state}`);
if (state === "reconnecting") { showNotification("Connection lost, reconnecting..."); } else if (state === "connected") { hideNotification(); }});Error handling
Section titled “Error handling”Handle fetch and stream errors:
renderer.on("layer:error", ({ layerId, error }) => { console.error(`${layerId} error:`, error.message);});
renderer.on("layer:retry", ({ layerId, attempt, delay }) => { console.log(`Retrying ${layerId} (attempt ${attempt}) in ${delay}ms`);});Complete example
Section titled “Complete example”Here’s a complete live tracking example:
type: mapid: vehicle-trackerconfig: center: [-122.4, 37.8] zoom: 12 mapStyle: "https://demotiles.maplibre.org/style.json"
layers: - id: vehicles type: circle source: type: geojson url: "https://api.example.com/vehicles" refreshInterval: 5000 # Poll every 5 seconds updateStrategy: merge # Update existing, add new updateKey: "vehicleId" # Match by vehicle ID cache: enabled: false # Don't cache live data loading: enabled: true message: "Loading vehicles..." paint: circle-radius: 10 circle-color: - match - ["get", "status"] - "active" - "#22c55e" - "idle" - "#eab308" - "offline" - "#6b7280" - "#6b7280" circle-stroke-width: 2 circle-stroke-color: "#ffffff" interactive: hover: cursor: pointer click: popup: - h3: - property: vehicleName - p: - str: "Status: " - property: status - p: - str: "Last update: " - property: lastUpdate
controls: navigation: trueBest practices
Section titled “Best practices”- Choose appropriate intervals - Don’t poll more frequently than data changes
- Use merge for entities - When tracking things with IDs, use merge to avoid flicker
- Set reasonable retry limits - Don’t retry forever if the server is down
- Disable cache for live data - Ensure you’re always getting fresh data
- Handle errors gracefully - Show users when data isn’t updating
Next steps
Section titled “Next steps”- Interactivity - Add popups and hover effects
- Examples - See complete working examples