Here’s a list of recipes with sample code on how to perform specific tasks.

Temporarily reserve seats

A common requirement is to temporarily block seats, while the ticket buyer finishes the order flow (payment, etc.). supports this out of the box: You can configure your floor plan in such a way that when a user clicks on a seat, his browser will directly tell the server to temporarily reserve the seat.

This also means that the seat immediately becomes unavailable for other users. To those other users, it will seem as if the seat has been booked.

Once a seat has been reserved for 15 minutes, it will either get a status (booked or your own custom status), or it will be automatically released again. At that moment in time, it will be available again for other users to reserve and book.

Configure your seating chart

You need to supply reserveOnSelect: true to your floor plan configuration, to make the magic happen. With that option enabled, seats that get selected on will be reserved automatically for 15 minutes.

However, it’s important that only the user who selected a seat can actually book it later on. For that, you’ll need to use the reservation token mechanism.

Reservation Tokens

It’s important to make sure that only the person who reserved the seat can actually book it later on. To ensure this, the renderer will generate a reservation token and store it in the browser’s session storage. This reservation token uniquely identifies the user (or rather: browser) who selected the seat.
To prevent other users from booking that seat, you need to provide the correct reservation token when confirming the booking of seats that were temporarily reserved before: you need to provide it as a parameter to /book, /release and /changeStatus calls for reserved objects.

The reservation token is either available to you either in your client-side code via JavaScript or in a hidden form field.

Confirming the booking of a seat that was temporarily reserved

To actually book a seat that’s been reserved - and so that’s unavailable for anyone else but you -, you need to call the /book endpoint and provide the reservation token. Like so:

    'objects': ['A-3', 'A-5', 'A-7'],
    'eventKey': '767f0050-5af5-4cba-b262-7bf905dd5acf',
    'secretKey': 'c7366b35-b08d-4fc3-b8ab-f3e706dd3a2a',
    'reservationToken': 'f5786c28-6f55-11e6-8b77-86f30ca893d3'

The possible responses are:

Note: It’s perfectly possible to successfully book seats even after the reservationToken has expired, but only if all of the objects are free of course. This may seem counter intuitive, but if you think about it, there is no reason for to not allow a booking if the seats are free.
An example: suppose that you, as a ticket buyer, temporarily reserved seat A-1 (using reserveOnSelect: true). Then there are two possibilities:

Regeneration of the reservation token

As explained before, the reservation token uniquely identifies a ticket buyer. In other words, it’s very much like a session token.
This token is stored in the local storage of the user’s browser, to make sure that the user still has the same seats selected after a page refresh (in case of validation errors in the rest of the registration form, e.g.).

In some cases, however, you may want to explicitly throw away the current reservation token (or session if you will), and have the ticket buyer start over with a new one. That’s what the regenerateReservationToken flag is for. By default it is set to false, but when set to true, the floor plan will ignore any previously stored reservation tokens, and use a new one.
Any previously selected seats will not be available to the current user anymore: they were auto-reserved using the old reservation token. But don’t worry, they will get automatically released again when the old token expires.

Note: if you do use a timer in your app, we recommend to set the reservation period value to just a couple of minutes higher than your own timer. This will ensure tickets won’t get released before your own timer expires.


Frequent Questions

Can I change the 15 minutes to another value?
Yes, via your Settings page.

Will you charge me for seats that get temporarily reserved?
No we won’t. Only seats or other object that get booked or assigned another status will be billable.

When objects are temporarily reserved, do I always have to pass the reservation token to /book and /changeStatus?
No, you only have to pass the reservation token when doing a /book or /changeStatus on behalf of the user that made the reservation. That way, can verify that no other user is trying to claim the same seats.

But in all other cases, you don’t have to pass in the reservation token. A good example would be a back office application, in which a venue manager
issues the /changeStatus call. You can safely issue it without passing in the reservation token.

In Safari, when browsing in private mode, I get the following warning: “Session storage not supported; reservation token will be lost after page refresh”
That’s a known limitation of Safari: in private mode, Safari does not allow data to be saved in session storage.
There is a workaround, which is explained in the documentation for the reservationToken rendering parameter.

Translation and i18n

Our users come from all over the globe, and so naturally English isn’t necessarily the language used by all of our users. gives you a flexible way to internationalize (i18n) your floor plan, making it easy to translate a seating chart, and display it to your users in their language.

Translating built-in texts

Built-in texts are the ones that provides by itself, like the texts in the tooltips that get shown when a user hovers over a seat or a section. These are the currently built-in texts:

  1. unavailableSeat: “This seat is not available”
  2. unavailableTable: “This table is not available”
  3. unavailableBooth: “This booth is not available”
  4. unavailableGeneralAdmissionArea: “Not available”
  5. sectionAvailability.none: “No seats available”
  6. selected: “selected”
  7. noOrphanSeats: “Please leave no empty seats”
  8. available.seats: “available seats”
  9. Unavailable: “Unavailable”
  10. choosePriceLevel: “Please choose”
  11. singleTicketAvailableInSection: “1 ticket available at %1” (%1 will be replaced by a price, e.g. €20)
  12. multipleTicketsAvailableInSection: “%1 tickets available from %2” (%1 will be replaced by a number, %2 will be replaced by a price)

To show these in your language, just pass in a “language” config parameter:

new seatsio.SeatingChart({
    "language": "fr"

The currently supported languages are:

If your language is not in this list, please feel free to send us translations for the built-in texts mentioned above, we’ll be happy to add them for you.

You can also override individual built-in texts, using the key (e.g. unavailableSeat) with the messages config parameter.

Translating your own labels and texts

You also enter your own texts and labels in the chart designer, when you’re
drawing your seating chart. You can for example add static texts on the seating
chart itself (e.g. STAGE and ORGAN on our example chart), there’s the
category labels that get displayed when you hover an available seat, etc.

To translate these, you need to pass in a messages config variable, like so:

new seatsio.SeatingChart({
    "messages": {
        "STAGE": "Podium",
        "ORGAN": "Orgue"

(Please​ note: the keys in the messages object are cAsE sEnSiTivE!)


  1. set the language config param to translate built-in texts.

  2. use a messages array to translate your own labels and texts.

Frequent Questions

Can I change the language after the chart has been rendered?
Currently not. As a workaround, you can re-render the chart when your user changes his language

Multilevel pricing

Once you start selling reserved seating tickets, you’ll realise that ticket categorization suddenly becomes a harder problem.
First, we’ll explain why, and then we’ll show you how can help you solve this.

The Problem

Ticket prices can be determined by many factors, like the physical location of the seat (e.g. ground floor, balcony), ticket buyer properties (e.g. age, VIP status, … ), the moment of purchase (e.g. early bird tickets) and many more.

Most ticketing applications allow their users to define ticket types. In other words, they allow ticket sellers to determine price levels on just one of these dimensions. And rightfully so: you’ll want to make it as easy as possible to both sell and buy a ticket.

However, once assigned seating comes into the picture, it’s important to realise that pricing could become a matrix, as opposed to a one-dimensional list, simply because the ticket buyer will need to take two decisions at the same time:

An example

Let’s take an example. We’re selling tickets for a concert in a theatre at the following prices:

Now if we want to use assigned seating for our event, we’ll want to adapt our pricing to a two-dimensional matrix, like so:


The point is this: any way you look at it, your ticket buyer will have to make two decisions: whether he’s a student or not, and whether he wants a seat on the ground floor, level 1 or level 2.

Categories vs Ticket Types

We make a clear and clean distinction between those two dimensions:

The dimension that is directly linked to the physical location on the chart are what we call seat categories.
In the example above: ground floor, balcony level 1 and balcony level 2. Those are defined when drawing the chart, so from within the chart designer.

The other dimension, in the above example student vs normal tickets, are what we call ticket types.
They are passed in as a parameter when rendering a chart for an event, and so are not stored in the database. The same is true for the actual ticket prices.


Since they are directly linked to the physical location of the seats on the chart, seat categories are defined when drawing the chart. You can add, remove and edit categories directly from within the chart designer: go to category mode in the chart designer, drag to select some seats and you’ll get this handy popup:


It’s important to note that only stores a key, name and color for a category. Or more explicitly: we don’t store pricing information at all, but you can pass in prices as an argument when rendering the a chart for a specific event.

Ticket types

The exact prices per seat category and per ticket type can vary per event. Therefore, you can pass those in as a pricing parameter when rendering a seating chart for an event, like so:

<div id="chart"></div>

<script src=""></script>
    new seatsio.SeatingChart({
        divId: "chart",
        publicKey: "publicDemoKey",
        event: "smallTheatreEvent2",
        pricing: xxx   //     <-- the pricing parameter

If you want to price your tickets just based on seat categories, you can pass in a simple array of objects, defining the prices:

pricing: [
    {'category': 1, 'price': 30},
    {'category': 2, 'price': 40},
    {'category': 3, 'price': 50}

If you want ticket buyers to select a ticket type as wel as a seat, you can pass in a more complicated structure as well, e.g.:

pricing: [
    {'category': 1, 'ticketTypes': [
        {'ticketType': 'student', 'price': 10},
        {'ticketType': 'normal', 'price': 20}
    {'category': 2, 'ticketTypes': [
        {'ticketType': 'student', 'price': 20},
        {'ticketType': 'normal', 'price': 30}

If you do so, a popup will be rendered when a ticket buyer clicks on a seat, allowing him or her to select the appropriate ticket type:

Finally, it’s worth noting you can mix and match these two styles, like so:

pricing: [
    {'category': 1, 'ticketTypes': [
        {'ticketType': 'adult', 'price': 30},
        {'ticketType': 'child', 'price': 20}
    {'category': 2, 'ticketTypes': [
        {'ticketType': 'adult', 'price': 40},
        {'ticketType': 'child', 'price': 30},
        {'ticketType': '65+', 'price': 25}
    {'category': 3, 'price': 50},


When you use assigned seating, it’s important to understand you can categorize tickets by the physical location on the seating chart (aka seat categories), and by other dimensions like ticket buyer age (aka ticket types).

Seat categories are defined when drawing the seating chart, whereas ticket types are different for every event and as such can be passed in when rendering a chart for an event.
The same is true for the actual prices, whether they are defined per seat category only, or as a two-dimensional seat category/ticket type matrix.

Access my own data in callbacks provides you with a number of callbacks you can implement yourself, like objectColor(), isObjectSelectable(), objectCategory and isObjectVisible.

However, when you try to access data or call functions that are defined somewhere else in your web app, this does not seem to work.
Why is that, and what is the solution?

Why can’t I just access my data ?

When you call new seatsio.SeatingChart({..}).render(), the floor plan renderer (‘chart.js’) adds an iFrame inside your chart div, to have a sandbox in which it can render the floor plan.

This sandbox is a Good Thing in many cases. Except when it’s not.

For example, the iFrame sandbox prevents data that’s in scope in the parent window, from being available to the iFrame content, in this case the chart itself. And so within an ‘objectColor’ implementation, you can’t just access functions that are available on your own page’s scope. Even though it looks like you could.

An example

Let’s look at an example. Suppose you would like to give all available seats a color that depends on the time of the day: blue in the morning, red in the afternoon. And that you have a function `colorByTimeOfDay()’ /} somewhere in your app, that calculates this color.

This won’t work:

function colorByTimeOfDay() {
    var isAm = new Date().getHours() < 12;
    return isAm ? "blue" : "red";

var chart = new seatsio.SeatingChart({
    // other configuration
    objectColor: function (object) {
        if (object.isSelectable()){
            return colorByTimeOfDay();
            // Problem

Why? Because because colorByTimeOfDay() is only available in the parent window, i.e. your page. Not within the iFrame that is rendered inside your chart div.

How then?

To access this function from within the iframe, use the extraConfig option:

function colorByTimeOfDay() {
    var isAm = new Date().getHours() < 12;
    return isAm ? "blue" : "red";

var chart = new seatsio.SeatingChart({
    extraConfig: {
        color: colorByTimeOfDay()
    objectColor: function (object, defaultColor, extraConfig) {
        if (object.isSelectable()){
            return extraConfig.color;
        return defaultColor;


To access external data from within callback implementations that you pass into the floor plan renderer, you’ll need to:

  1. Pass your data as an object to the extraConfig option

  2. access them through the last parameter that’s passed to the callback

Tips for embedding the floor plan designer

You want to allow your users to create their own floor plans, and to do so, you’ve embedded the floor plan designer in your backoffice application.
In this recipe we’ll show you some tips and tricks to improve usability in such a scenario.

Disable features

In case you want to limit the floor plan designer functionality that’s offered to your users, you can enable or disable specific features.
For example, you can remove the ‘Focal Point’ button from the toolbar, if you don’t want your users to have best available seat selection available.

You can choose to either enable only specific features, or to disable some (not both at the same time).
The difference between the two is important. If you choose to enable features, any new features that are added at some point in the future will not automatically be available for your users. If you disable features instead, then newly added features will be automatically available to your users.

Check out the features config param documentation for more info.

Remove the venue type selector when creating a new chart

By default, when you create a new floor plan, the floor plan designer requires you to choose a venue type, like so:


If you want your users to only draw table plans, or only floor plans without sections, you will want to hide this floor plan selector. To do so, follow these steps:

  1. create an empty chart via the API, specifying the desired venue type. E.g. 'venueType': 'TABLES' for a tables-only floor plan. This API call will return a new chart key.
  2. use that chart key to open the floor plan designer for that newly created & empty chart.

That way, your users will not have to choose a chart type anymore.

Manage categories from your app

Want your users to manage categories from within your backoffice app instead of creating & editing them from within the floor plan designer?
Perfectly possible, just follow these steps:

  1. have your users create categories in your application
  2. Before opening the floor plan designer in your web app, first call the create chart API and pass in the categories.
  3. Configure the features config param when embedding the designer like so: 'features: {readOnly: ['categoryList']}. This will hide the “create category” button etc.
  4. when the user updates the categories list in your application, be sure to call the update chart API, to update the category config for te floor plan as well.

Manage the chart name from your app

You may want to disallow your users from naming charts from within the floor plan designer.

The workflow is the same as when you want to manage categories from outside of the designer, and the two can effectively be combined together:

  1. Have your users specify the chart name in your application.
  2. call the create chart API with the specified name.
  3. make the chart name input that’s shown in the top left corner readonly, or even hide it completely, by providing the features flag when embedding the designer.
  4. when the user updates a chart name, call the update chart API, passing in the new name.