Coming from Power BI Embedded
If you have embedded Power BI reports with powerbi-client, the Icon Map embed API will feel familiar on purpose: an iframe, a handle, promise-returning methods, events you subscribe to, filters you set from your page, bookmarks you capture and apply. This page maps one onto the other.
The same two embedding models
| Power BI | Icon Map |
|---|---|
| Embed for your customers (app owns data) | A published map - embed(element, { publishId }) |
| Embed for your organization (user owns data) | embedForOrganization(element, { mapItem }) |
| Embed token from your server | Embed token from your server, for token-gated publishes (getToken) |
| Entra token for the signed-in user | The same (getToken(scopes)), or sign-in inside the frame |
Bootstrapping
// Power BI
const report = powerbi.embed(element, { type: "report", id, embedUrl, accessToken, settings });
report.on("loaded", () => { /* now it is safe to call things */ });
// Icon Map
const map = embed(element, { publishId, getToken });
await map.ready; // optional - commands sent early are held, not lost
| Power BI | Icon Map |
|---|---|
powerbi.embed(el, config) |
embed(el, options) |
powerbi.get(el) |
getEmbed(el) |
powerbi.reset(el) |
reset(el) |
powerbi.bootstrap() then embed() - start the download before you have a token |
embed(el, { deferRender: true }) then map.render({ getToken }) |
report.setAccessToken(token) |
map.setToken({ token }) |
tokenExpiration handling |
tokenExpiring event |
report.reload() / refresh() |
map.reload() / map.refreshData() |
report.fullscreen() |
map.fullscreen() |
report.print() |
map.print() |
report.iframe |
map.iframe |
One difference worth knowing: you do not have to wait for a loaded event before calling the API. Commands issued early are held until the map can answer them.
Filters
| Power BI | Icon Map |
|---|---|
getFilters() / setFilters() / removeFilters() |
getFilters() / setFilters() / clearFilters() |
updateFilters(operation, filters) with Add, Replace, ReplaceAll, RemoveAll |
updateFilters({ operation, filters }) with add, replace, replaceAll, removeAll |
Basic filter (In) |
A list value: { region: ["EMEA", "APAC"] } |
| Advanced filter (range) | { revenue: { low: 1000, high: 5000 } } |
| Relative date filter | { period: { operator: "inLast", count: 30, unit: "days" } } |
filter.displaySettings (isLockedInViewMode, isHiddenInViewMode, displayName) |
display: { region: { locked, hidden, displayName } } |
| Any table and column in the model | Only filters the author declared - discover them with getFilterSchema() |
The last row is the real difference. In Power BI your page names any column; in Icon Map it names a filter the author chose to offer, and anything else is rejected with undeclared_filter. See Filters.
Slicers, selection and bookmarks
| Power BI | Icon Map |
|---|---|
visual.getSlicerState() / setSlicerState() |
getSlicers() / setSlicerState({ slicerId, state }) |
dataSelected event |
featureClick and selectionChanged |
| Data point selection from your page | selectByKey({ layerId, field, keys }), setSelection() |
| - | highlight() - emphasis without selection, for list hover |
bookmarksManager.getBookmarks() / apply(name) |
getBookmarks() / applyBookmark({ bookmarkId }) |
bookmarksManager.capture() / applyState(state) |
captureScene() / applyScene({ scene }) |
bookmarkApplied event |
bookmarkApplied event |
Report URL with ?bookmarkGuid= or ?filter= |
Deep links: ?bookmark=, ?f.<name>=, #s= |
A captured scene is a plain, documented object rather than an opaque string, and it survives a re-publish: parts that no longer exist are skipped and reported instead of failing.
Presentation and navigation
| Power BI | Icon Map |
|---|---|
settings.panes, filterPaneEnabled, navContentPaneEnabled |
setChrome({ legend, layerControl, bookmarksBar, search ... }) |
settings.background: Transparent |
setBackground({ background: "transparent" }) |
report.applyTheme() |
setTheme({ mode }) - light, dark or auto. Custom themes are not supported |
settings.localeSettings |
language option, setLanguage() |
settings.hyperlinkClickBehavior: RaiseEvent + dataHyperlinkClicked |
hyperlinkBehavior: "raiseEvent" + linkClicked |
getPages() / setPage() |
No pages. The nearest things are bookmarks and getLayers() / setVisibility() |
Page and visual setZoom |
The camera group: setView, flyTo, fitBounds, fitLayer |
visual.exportData() |
No equivalent, by design - see below |
report.saveAs(), edit mode, switchMode() |
No equivalent. An embedded map is view-only |
Custom commands
| Power BI | Icon Map |
|---|---|
settings.extensions command on a visual's context menu |
addMenuCommand({ id, title, layerIds? }) on the feature popup |
commandTriggered event |
menuCommandTriggered event |
Events
| Power BI | Icon Map |
|---|---|
loaded |
ready promise, loaded event |
rendered |
rendered (with durationMs) |
error |
onError option, error event, rejected promises with a code |
pageChanged |
bookmarkApplied, visibilityChanged |
filtersApplied |
filtersChanged |
visualClicked, dataSelected |
featureClick, selectionChanged |
| - | viewChanged - the camera |
Every Icon Map state event carries a reason (user, command, bookmark ...), which Power BI's do not. It exists so a page that mirrors the map can ignore the echo of its own commands - see Events.
Things that work differently
- Feature detection. Instead of checking SDK or service versions, read
(await map.ready).commands. It lists what this particular map answers, taking the map's version, the embed type and the author's switches into account. - The author is in control. Each command group can be switched off per publish, and only sites the author listed can drive the map at all. Plan for
denied_capabilityanddenied_origin. - No bulk data. There is no
exportData().featureClickreturns the fields the layer shows in its tooltip, and nothing returns rows in bulk. If your page needs the data, read it from your own source and useselectByKeyto tie the two together. - Typed errors. Failures are
EmbedErrors with a stablecoderather than error objects whosemessageyou parse. - Size. The SDK is about 17 KB with no dependencies, and there is a script-tag build for pages that cannot bundle.