Seatmap Pro 1.71.0
Section photos delivered to your ticketing site, prices and availability loaded separately, faster background conversion, and a lighter renderer.
Layer navigation and global search in the editor, honest decimal prices in the renderer, lighter venue backgrounds, and four changes to check before upgrading.
If you only read one paragraph: the editor now navigates by layers instead of a mode dropdown, there is a search box that takes any id you paste into it, and large venues load lighter and animate cleaner. If you send webhooks, embed the editor with URL parameters, or parse prices yourself, skip to the last section before you upgrade.
The mode dropdown is gone. A pill sits on the canvas, shows the active layer and switches in one click. Interaction is scoped to that layer, and every layer keeps its own selection, so switching away and back brings your selection with you rather than clearing it.
The top menu became a two-way switch between Edit and Prices. Prices no longer requires a published schema, which removes a step that never had a reason to exist. The chosen mode lives in the URL as ?mode=prices and survives a reload.
Two layers disappeared. Objects only ever carried a shape lock that did nothing, and Image had no interactive surface. Shapes are still selectable in schema mode exactly as before.
Support tickets arrive with an id and no context. The navbar now has a search box that resolves event ids, schema ids, schema names, venue names and event names, groups what it finds by type, and takes you to the entity. Exact id matches rank first, then prefixes, then partial matches, and the whole thing is keyboard-driven.
Results are scoped on the server rather than filtered in the browser. A global admin searches everything. A super admin is limited to their tenant, and everyone else sees only their own organisation.
An event hit opens the schema editor with that event already active, so there is no flash of the wrong event while the page settles. The same route backs the “Open in editor” link on the event detail modal.
Picking an event used to mean opening a dropdown buried in the sidebar. Events now live in a column between the canvas and the sidebar, each row showing status, date and a pricing-coverage bar, so you can see at a glance which events still have unpriced seats. Filter chips narrow the list to events with no pricing at all or events with some.
The column only appears when a schema has more than one event, and it starts collapsed until you open it from the sidebar. Your choice is remembered per browser.
One thing to check if you embed the editor: the hidden=events URL parameter now hides this column. If you already pass that token, the column will not appear.
The booking renderer derives the numeric price in its callbacks from the price label. It used to throw the decimals away, so a seat labelled 12.50 was reported as 12. It now reports 12.5.
That affects price on section-click and section-selection callbacks, and on cart seats and general-admission entries in onSeatsSelect and getCart. A non-numeric label such as Gold still comes back as undefined, and a 0 label still comes back as 0, so the value is always either a finite number or nothing at all. If your checkout re-parsed the label itself or assumed integers, this is the change to look at.
Related fixes in the same area: cart price matching now compares numerically, so labels like 42 EUR line up with their price entry; a general-admission entry with a broken stored price can be removed from the cart again; and restoring a saved cart resolves sections by name, so a section named with digits is no longer confused with a different section whose id happens to match.
Label styling also works again. A schema’s labelStyle travels on the wire as a JSON string and the renderer never parsed it, which quietly killed every setting it carries: hiding a general-admission label, hiding the price dot, and all the style overrides. It is parsed at ingest now.
Zooming into a venue background used to pull detail from the full-size image, so one crop of a big stadium could drag down several megabytes. The converter now emits a chain of progressively smaller levels alongside the tile grid and encodes tiles as WebP, and the renderer picks the smallest level that covers the region you asked for. On a 9500px stadium background the worst case dropped from roughly 2.5 MB to roughly 400 KB per crop.
Inside the renderer, operations that used to walk every seat now go through indexes. Filtering, locking and state changes no longer rebuild the spatial hit-test index, minimap pins are drawn from the cart instead of scanned out of the full seat list, and key lookups are constant time. On the GPU side, row geometry uploads only when it changes, and the per-seat selection and hover overlay is rebuilt only when something actually moves rather than on every frame. No method signatures or callback values changed.
Zoom behaves better too. A zoom into a point near the venue edge now settles inside the pan limits instead of resting past them, a pinch that ends out of bounds snaps back, and entering a section view waits for the fit animation to finish rather than guessing with a fixed timer.
Webhook targets must be public HTTPS. Targets are validated when saved and again before every delivery. Anything on http, or resolving to a loopback, private, link-local, CGNAT or reserved address, is rejected, including the cloud metadata endpoints. Self-hosted deployments with a legitimate internal receiver can set seatmap.webhooks.allow-private-targets: true in the operator config, and the https requirement still applies.
Concurrent schema saves return 409. Schemas carry an optimistic-lock version. When two saves overlap, the first wins and the second is rejected instead of silently overwriting. Reload and retry on 409.
A save that references an unknown pricing zone returns 404. Previously the seat was saved with no zone at all, which produced wrong pricing and no error.
Booking widget branding follows the plan. An active organisation on a paid plan renders with no branding. An active organisation without one gets a small “Powered by Seatmap.pro” badge. A suspended organisation gets a blocking overlay. Branding resolution fails open, so an error resolving the organisation renders nothing and cannot break a booking flow. Self-hosted deployments can disable it with SEATMAP_WATERMARK_DISABLED.
A seatmap save whose payload left out the zones key deleted every pricing zone on the schema and unassigned them from all seats and rows. The editor never sends that key, so an ordinary geometry save destroyed the schema’s pricing zones, and nothing in the interface said so until you reloaded. An omitted key now means leave the zones alone. Sending "zones": [] still clears them, so clients that send the field keep the behaviour they had.
Schema saves are also atomic now: the geometry write and the SVG regeneration share one transaction, and a failed bulk seat insert rolls the save back instead of returning success with the seats missing.
The full technical notes for this release live in the knowledge base.
Section photos delivered to your ticketing site, prices and availability loaded separately, faster background conversion, and a lighter renderer.
How stadiums handle 30k+ seat charts in real time: WebGL rendering, level-of-detail switching, lock-per-click flow, and on-sale traffic resilience.
A guide to interactive seating charts for theatres: multi-level rendering, accessibility zones, price tiers, obstructed-view seats, and SVG plan import.