Events

Events tell your page what is happening in the map. They are opt-in: the map sends nothing until you subscribe, so an embed that only displays a map costs nothing extra.

Subscribing

const stop = map.on("viewChanged", (view) => { /* ... */ });
stop();                        // remove this handler
map.off("viewChanged");        // remove every handler for the event

You can subscribe before the map is ready, and you can name events at mount so nothing is missed during start-up:

embed(el, { publishId, events: ["rendered", "featureClick"] });

Subscriptions survive map.reload().

reason: avoiding echo loops

If your page and the map mirror each other - a list that follows the map, a URL that stores the view - each of your own commands comes back to you as an event. Without care, that loops.

Every state event therefore says why it happened:

reason Meaning
user The reader did it - dragged, clicked, used a control in the map
command Your page did it, through the API
bookmark A bookmark was applied
tour A playing tour did it
scene applyScene did it
load Initial state while the map starts

So a two-way sync is one line:

map.on("viewChanged", (v) => { if (v.reason === "user") writeViewToUrl(v); });

The events you will use most

viewChanged

Fires when the camera settles, with the same shape getView() returns plus reason. By default you get one event per gesture, at most every 200 ms. Both are adjustable:

embed(el, { publishId, events: ["viewChanged"], subscribeOptions: { viewChangedThrottleMs: 500 } });
embed(el, { publishId, events: ["viewChanged"], subscribeOptions: { continuousView: true } });   // while moving, too

The last position always arrives, however fast the reader moves.

featureClick

map.on("featureClick", (f) => {
  if (!f) return closeMyPanel();            // the reader clicked empty map
  // f = { layerId, layerName, featureKey, fields, lngLat }
});

fields holds the fields the layer shows in its tooltip - what the reader can already see - and nothing else. If you need another column to join on, ask the map's author to add it to the layer's tooltip. featureKey is stable for the life of the publish and is what selectByKey and highlight accept.

featureHover has the same shape and null when the pointer leaves. It is spaced at least 100 ms apart; a leave is never delayed, so you will not be left believing the pointer is still over something.

selectionChanged, slicerChanged, filtersChanged, visibilityChanged

Each carries the new state and a reason. Use them to keep your own controls honest when the reader uses the map's:

map.on("visibilityChanged", ({ visibility }) => {
  for (const [id, on] of Object.entries(visibility.layers ?? {})) myToggles[id].checked = on;
});

linkClicked

Maps can contain hyperlinks and link buttons. By default a click navigates. To handle it inside your application instead, set the behaviour at mount:

const map = embed(el, { publishId, hyperlinkBehavior: "raiseEvent", events: ["linkClicked"] });
map.on("linkClicked", ({ url, layerId, featureKey, buttonId }) => router.push(toMyRoute(url)));

"navigateAndRaiseEvent" does both.

menuCommandTriggered

Raised when the reader chooses an action you added with addMenuCommand.

analysisResult

Raised when an analysis operation completes, whether your page ran it or the reader did. See Analysis.

loaded, rendered, dataStateChanged

loaded means the map is up; rendered means its first frame is on screen, with durationMs from the frame's start - useful for your own performance monitoring. dataStateChanged reports live data loading, ready, stale or error.

tokenExpiring

For token-gated maps, fires a minute before the embed token expires. Answer with setToken. See Getting started.

error

Problems after the session opened. Start-up failures go to the onError option instead, and make ready reject.

Ordering and dropped events

Every event carries a seq that increases by one for the life of the session. The SDK handles it for you; it matters only if you log events and see a gap, which means one was dropped. The map drops an event rather than send a broken one in exactly one case: a payload over 32 KB.

The sequence restarts when the frame reloads.

The full list

Every event, with its payload type, is in the API reference. The map also tells you which events it can raise in capabilities.events.