Integration recipes
Filter a listing on section click
map.on("select", (sel) => showOnly(sel.sections ?? [sel.section])); // areas cover several sections
map.on("deselect", () => showAll());
Highlight the map from a listing card
card.querySelector("button").onclick = () => map.select(card.dataset.section);
Inventory-aware shading
Pass event (with apiBase) and the map fetches that event's sellable
sections itself. To shade from your own data instead, fetch availability
server-side or client-side and pass or set it:
const { sections } = await fetch(`${apiBase}/v1/venues/${venue}/availability?event=${event}`,
{ headers: { "X-Api-Key": key } }).then((r) => r.json());
map.setAvailability(sections); // null → show everything
Event configuration comes from the event
A Bulls game and a Blackhawks game are different products with different renders, polygons and surfaces. Pass the product for the page's event and the map will not show a dropdown:
Seatpano.load({ …, product: event.venueConfiguration /* "bulls" | "blackhawks" */ });
Omit product only on pages with no event context; the SDK then shows an
in-map dropdown as a fallback.
Named areas (clubs, lounges) on team charts
Bands the chart names instead of numbering are clickable areas. select
fires with the area id and sections, every space the area stands for:
filter by sections. Calling map.select("CLUBA") for a space that has no
shape of its own selects its area.
Row bands
Sections keep one shape by default. Pass vantages: "bands" to let a click
zoom into a section and reveal its row bands for a second, row-level pick;
pass rows: "front" | "central" | "back" to choose which row a plain click
shows and to limit the gallery to it. See the SDK reference.
Present the venue's own 3D viewer
Some venues require their own viewer. Their builds declare
presentation.views: "iomedia" and the map then opens the venue's IOMEDIA
Virtual Venue in an iframe with no gallery of Seatpano's stills. To force
either behaviour yourself:
popover: { source3d: "iframe", galleryScope: "none" } // venue's viewer only
popover: { source3d: "auto", galleryScope: "product" } // Seatpano's stills + 360°
Dark pages
The map has no background of its own. On a dark page it outlines the chart's
ink automatically; set --vm-accent, --vm-fill and --vm-fill-hover to
suit your palette.
"View 3D" behaviours
popover.view3d: "viewer"(default) opens the section viewer: embedded 3D Virtual Venue plus a gallery of the section's seat/interior stills.popover.view3d: "image"opens the seat-view still in a lightbox.popover.view3d: "iomedia"opens the venue's own Virtual Venue in a new tab.popover.view3d: "none"only emitsview3d; render your own modal (buildGallery()gives you the same item list).
Deep links
Read section from your URL on load and call map.select(section) after
the ready event. Write it back inside your select handler.
Iframe fallback (no third-party script on your page)
If your page cannot run our script, embed the map as an iframe from
https://embed.seatpano.com and talk to it over postMessage. Your key still
applies: the embed page forwards your page's origin to the API, so the
licence's domain binding is enforced (your page must not set
Referrer-Policy: no-referrer).
Simplest form, with the small host helper (served to licensed keys):
<div id="venue-map"></div>
<script src="https://api.seatpano.com/v1/sdk/embed.js?key=YOUR_KEY"></script>
<script>
const map = SeatpanoEmbed.mount({ container: "#venue-map", key: "YOUR_KEY",
venue: "united-center", product: "bulls", event: "EVT1", theme: "flat" });
map.on("select", ({ section, vantage }) => filterOffers(section, vantage));
map.on("deselect", () => filterOffers(null));
// map.select("117"); map.setAvailability([...]); map.openViewer("117"); map.destroy();
</script>
Or with no script at all:
<iframe src="https://embed.seatpano.com/?key=YOUR_KEY&venue=united-center&product=bulls&event=EVT1&theme=flat"
style="width:100%;height:480px;border:0" title="Seat map" allow="fullscreen"></iframe>
<script>
window.addEventListener("message", (e) => {
if (e.origin !== "https://embed.seatpano.com" || e.data?.source !== "seatpano") return;
if (e.data.type === "select") filterOffers(e.data.payload.section, e.data.payload.vantage);
if (e.data.type === "resize") frame.style.height = e.data.payload.height + "px";
});
// commands: frame.contentWindow.postMessage({ source: "seatpano", type: "select", args: ["117"] }, "https://embed.seatpano.com");
</script>
Messages from the embed: { source: "seatpano", type, payload } where type is
ready | select | deselect | hover | view3d | viewerClose | level | product | error | resize. Commands to the embed: { source: "seatpano", type, args } with
type in select | clearSelection | setAvailability | setProduct | setLevel | setView | openViewer. URL parameters mirror Seatpano.load options:
key, venue, product, event, level, view, theme, accent, vantages, rows, availability (comma list).
Server-side access
Licensed customers can also call the hosted API directly from their own servers, for example to read which sections are sellable for an event or to list licensed venues. That reference is provided with your license key; contact [email protected].
Replacing an existing 3D Digital Venue embed
The event model is intentionally close: DVM.loadModule("map_viewer", …) →
Seatpano.load(…); DVM click with nodes[0].id → select with
section; enter/leave → hover. Section ids are the same venue
section keys.