> ## Documentation Index
> Fetch the complete documentation index at: https://restoo.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Restoo Widget Events

> Events emitted by the Restoo widget, their payloads, and how to listen for them.

The Restoo widget emits [custom browser events](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) for the main steps of the booking funnel. Listen for them with standard [event listeners](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to measure the funnel in your own analytics, or in any other system that consumes browser events.

<Tip>
  If you use GA4, Google Ads, Meta Pixel, TikTok Pixel, OpenAI Pixel, or Google Tag Manager,
  see [Restoo Connect](/widget/connect). It forwards these
  events without requiring a custom listener for each one.
</Tip>

## Listen for events

Each event is a standard browser `CustomEvent`. Its name starts with `restoo:`, and its payload is available in `event.detail`.

For example, to receive a confirmed booking:

```js theme={null}
window.addEventListener("restoo:booking_created", (event) => {
  const { booking } = event.detail.data;

  console.log("Booking confirmed:", booking.date, booking.time, booking.pax);
});
```

Register your listeners on the page that embeds the widget.

<Note>
  **These events always arrive, with or without consent.** The widget emits them
  on your page so you can measure with your own tools; what consent controls is
  what [Restoo Connect](/widget/connect) delivers to each platform. If you forward
  them to a third party, the consent is yours to apply. The exception is the
  customer's identity: the hashed email and phone are only emitted with
  advertising permission granted ([customer
  identity](/widget/consent#customer-identity)).
</Note>

## Event reference

### Widget and navigation

| Event                   | When it fires                                          | `data`                        |
| ----------------------- | ------------------------------------------------------ | ----------------------------- |
| `restoo:widget_mounted` | The widget has mounted and business data is available. | [`WidgetEvent`](#widgetevent) |
| `restoo:page_viewed`    | The visitor navigates to a widget page.                | [`PageViewed`](#pageviewed)   |

### Booking funnel

| Event                                   | When it fires                                                             | `data`                              |
| --------------------------------------- | ------------------------------------------------------------------------- | ----------------------------------- |
| `restoo:booking_start_viewed`           | The booking start page is shown.                                          | `null`                              |
| `restoo:booking_start_submitted`        | The availability search is submitted with valid party size and date.      | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_no_availability_viewed` | The current search has no availability.                                   | [`NoAvailability`](#noavailability) |
| `restoo:booking_conditions_viewed`      | Optional booking conditions are shown.                                    | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_conditions_accepted`    | The visitor accepts the booking conditions.                               | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_details_form_viewed`    | The guest details form is shown.                                          | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_details_form_started`   | The visitor starts completing the guest details form.                     | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_details_form_submitted` | The guest details are saved successfully.                                 | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_cp_viewed`              | An applicable cancellation policy is shown.                               | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_cp_acknowledged`        | The visitor toggles "I have read and accept" for the cancellation policy. | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_cp_accepted`            | The cancellation policy is accepted — the card is validated successfully. | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_created`                | A new booking is created.                                                 | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_updated`                | An existing booking is modified.                                          | [`BookingFunnel`](#bookingfunnel)   |

<Note>
  Some events depend on the booking configuration. For example, conditions and
  cancellation-policy events only appear when those steps are presented.
</Note>

<Note>
  These two events are mutually exclusive and fire once each time a booking is
  saved, at the moment the backend confirms it — not when the confirmation page
  renders, so reloading that page does not emit them again. Editing a booking
  emits `booking_updated`, never `booking_created`. Both carry
  `is_update_flow` set accordingly.
</Note>

### Item list events

| Event                               | When it fires                                           | `data`                                            |
| ----------------------------------- | ------------------------------------------------------- | ------------------------------------------------- |
| `restoo:booking_item_list_viewed`   | A list of experiences, time slots, or add-ons is shown. | [`BookingViewItemList`](#bookingviewitemlist)     |
| `restoo:booking_item_detail_viewed` | The visitor opens the details of an experience or area. | [`BookingViewItemDetail`](#bookingviewitemdetail) |
| `restoo:booking_item_selected`      | The visitor selects one or more items from a list.      | [`BookingSelectItem`](#bookingselectitem)         |

### Customer

| Event                        | When it fires                                                 | `data`                                      |
| ---------------------------- | ------------------------------------------------------------- | ------------------------------------------- |
| `restoo:customer_identified` | A customer is identified from the form or remembered details. | [`CustomerIdentified`](#customeridentified) |
| `restoo:customer_signed_out` | The customer signs out of remembered details.                 | `null`                                      |

<Warning>
  `customer_identified` carries personal data, so it is emitted **only when the
  visitor has granted `ad_user_data`** — see
  [Consent](/widget/consent#customer-identity). It is not lost if permission
  arrives later: the widget holds the identification and emits it as soon as the
  visitor grants it, which is what happens when someone is recognized from
  remembered details before answering the cookie notice.
</Warning>

### Actions

| Event                 | When it fires                                                                                                           | `data`                        |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| `restoo:action_taken` | The visitor uses an important action, such as contact, calendar, directions, sharing, or a no-availability alternative. | [`ActionTaken`](#actiontaken) |

## Fields common to every event

Every event has the same top-level structure in `event.detail`:

```js theme={null}
{
  id: "550e8400-e29b-41d4-a716-446655440000",
  session_id: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  name: "booking_created",
  type: "booking",
  timestamp: "2026-07-22T10:15:00.000Z",
  source: {
    account_id: "best-burger",
    widget_id: "restoo_w-reservations",
    widget_display_mode: "INLINE",
    business_name: "Best Burger"
  },
  acquisition: {
    utm_source: "google",
    utm_medium: "cpc",
    utm_campaign: "summer",
    utm_content: null,
    utm_term: null
  },
  is_update_flow: false,
  data: {
    // Shape depends on the event.
  }
}
```

**Fields**

<ResponseField name="id" type="string" required>
  Unique identifier for **this emission**, not for the kind of event. Modern
  browsers generate an RFC 4122 UUID, but treat it as an opaque string because the
  fallback used by older browsers has a different format.

  Every dispatch gets a new one: three taps on the contact button produce three
  `action_taken` events with three different `id` values.
</ResponseField>

<ResponseField name="session_id" type="string" required>
  Identifier shared by events from the same widget session. It follows the same
  format rules as `id`.
</ResponseField>

<ResponseField name="name" type="string" required>
  Event name without the `restoo:` prefix.
</ResponseField>

<ResponseField name="type" type="string | null" required>
  Payload model. It determines the shape of `data`; both `type` and `data`
  are `null` for events without a payload.

  | Value                      | `name` values                                                                                                                                                                                                                                                                                       | `data` shape                                      |
  | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
  | `widget`                   | `widget_mounted`                                                                                                                                                                                                                                                                                    | [`WidgetEvent`](#widgetevent)                     |
  | `page_view`                | `page_viewed`                                                                                                                                                                                                                                                                                       | [`PageViewed`](#pageviewed)                       |
  | `booking`                  | `booking_start_submitted`, `booking_conditions_viewed`, `booking_conditions_accepted`, `booking_details_form_viewed`, `booking_details_form_started`, `booking_details_form_submitted`, `booking_cp_viewed`, `booking_cp_acknowledged`, `booking_cp_accepted`, `booking_created`, `booking_updated` | [`BookingFunnel`](#bookingfunnel)                 |
  | `no_availability`          | `booking_no_availability_viewed`                                                                                                                                                                                                                                                                    | [`NoAvailability`](#noavailability)               |
  | `booking_view_item_list`   | `booking_item_list_viewed`                                                                                                                                                                                                                                                                          | [`BookingViewItemList`](#bookingviewitemlist)     |
  | `booking_view_item_detail` | `booking_item_detail_viewed`                                                                                                                                                                                                                                                                        | [`BookingViewItemDetail`](#bookingviewitemdetail) |
  | `booking_select_item`      | `booking_item_selected`                                                                                                                                                                                                                                                                             | [`BookingSelectItem`](#bookingselectitem)         |
  | `customer_identification`  | `customer_identified`                                                                                                                                                                                                                                                                               | [`CustomerIdentified`](#customeridentified)       |
  | `action`                   | `action_taken`                                                                                                                                                                                                                                                                                      | [`ActionTaken`](#actiontaken)                     |
  | `null`                     | `booking_start_viewed`, `customer_signed_out`                                                                                                                                                                                                                                                       | `null`                                            |
</ResponseField>

<ResponseField name="timestamp" type="string" required>
  Event time as an ISO 8601 UTC timestamp. Example:
  `"2026-07-22T10:15:00.000Z"`.
</ResponseField>

<ResponseField name="source" type="object" required>
  Widget context.

  <Expandable title="properties">
    <ResponseField name="account_id" type="string" required>
      Restaurant account identifier. Example: `"best-burger"`.
    </ResponseField>

    <ResponseField name="widget_id" type="string" required>
      Widget identifier. Example: `"restoo_w-reservations"`.
    </ResponseField>

    <ResponseField name="widget_display_mode" type="string" required>
      Display mode used by the widget.

      | Value     | Meaning                                               |
      | --------- | ----------------------------------------------------- |
      | `INLINE`  | The widget is rendered within the host page's layout. |
      | `OVERLAY` | The widget opens above the host page.                 |
    </ResponseField>

    <ResponseField name="business_name" type="string" required>
      Public business name. Example: `"Best Burger"`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="acquisition" type="object" required>
  Marketing attribution associated with the visit.

  <Expandable title="properties">
    <ResponseField name="utm_source" type="string | null" required>
      UTM traffic source, or `null` when absent.
    </ResponseField>

    <ResponseField name="utm_medium" type="string | null" required>
      UTM marketing medium, or `null` when absent.
    </ResponseField>

    <ResponseField name="utm_campaign" type="string | null" required>
      UTM campaign name, or `null` when absent.
    </ResponseField>

    <ResponseField name="utm_content" type="string | null" required>
      UTM content identifier, or `null` when absent.
    </ResponseField>

    <ResponseField name="utm_term" type="string | null" required>
      UTM paid-search term, or `null` when absent.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="is_update_flow" type="boolean" required>
  `true` when the event belongs to an update flow; otherwise `false`.
</ResponseField>

<ResponseField name="data" type="object | null" required>
  Event-specific payload. See [Event data](#event-data) for more information.
</ResponseField>

## Event data

The examples below show the value of `event.detail.data`, not the whole event.

Definitions: [`WidgetEvent`](#widgetevent), [`PageViewed`](#pageviewed),
[`BookingFunnel`](#bookingfunnel), [`NoAvailability`](#noavailability),
[`BookingViewItemList`](#bookingviewitemlist),
[`BookingSelectItem`](#bookingselectitem),
[`BookingViewItemDetail`](#bookingviewitemdetail),
[`ActionTaken`](#actiontaken), and
[`CustomerIdentified`](#customeridentified).

<Note>
  Looking for a field that isn't here — a catalogue name, or more customer
  details? Some are deliberately omitted; see [What Restoo deliberately
  omits](/widget/connect-mappings#what-restoo-deliberately-omits).
</Note>

### WidgetEvent

Used by `widget_mounted`.

```json theme={null}
{
  "url": "https://best-burger.myrestoo.net/widget/restooWidget.html?view=experiences"
}
```

**Fields**

<ResponseField name="url" type="string" required>
  URL of the internal document Restoo loads inside the iframe.

  **It is not your page's URL, and it is not an address you can open**: on its
  own it stays blank, because the widget draws nothing until Restoo.js sends it
  the settings on mount.

  The path is always the same and only its parameters change, so this field
  identifies the starting view, not where the visitor was. For that, read
  `window.location.href` on your own page.
</ResponseField>

### PageViewed

Used by `page_viewed`.

```json theme={null}
{
  "page_name": "reservation"
}
```

**Fields**

<ResponseField name="page_name" type="string" required>
  Internal view path — mirrors the widget's own routes, one per screen (there
  are 50+). A few representative examples: `"reservation"` (calendar),
  `"reservation/details"` (guest details form), `"reservation/confirmed"`,
  `"experiences"`, `"store"`, `"store/checkout"`, `"booking/cancel"`, and
  `"my-account"`.
</ResponseField>

### BookingFunnel

Used by the booking funnel events whose `type` is `booking`. The payload is a **snapshot of the booking at the moment the event is emitted**, so fields that have not been selected or assigned yet can be `null`.

```js theme={null}
{
  booking: {
    account_id: "best-burger",
    status: "CONFIRMED",
    shift_type: {
      id: "DINNER",
      name: "Dinner"
    },
    pax: 2,
    pax_children: 0,
    high_chairs: 0,
    strollers: 0,
    date: "2026-07-25",
    weekday: "saturday",
    time: "20:30:00",
    floor_plan_area: {
      id: "best_burger:floor_plan_area:3",
      name: "Terrace"
    },
    experience: {
      id: "best_burger:experience:7",
      price_per_ticket: 6500,
      currency: "EUR",
      tickets: 2
    },
    add_ons: [
      {
        id: "best_burger:add_on:12",
        unit_price: 2500,
        currency: "EUR",
        quantity: 2
      }
    ],
    currency: "EUR",
    total_amount: 18000,
    is_time_limited: false,
    cancellation_policy: {
      type: "PREPAYMENT",
      amount: 3000,
      amount_type: "PER_PAX",
      cancellation_fee_amount: 6000,
      charged_amount: 6000,
      cancellation_notice_hours: 24,
      currency: "EUR"
    }
  }
}
```

**Fields**

<ResponseField name="booking" type="object" required>
  Booking state when the event was emitted.

  <Expandable title="properties">
    <ResponseField name="account_id" type="string" required>
      Restaurant account identifier. Example: `"best-burger"`.
    </ResponseField>

    <ResponseField name="status" type="string" required>
      Current booking or reservation status. See
      [BookingStatus](/getting-started/enums#bookingstatus) for the possible
      values and their meanings. During a new booking, the usual values are
      `CONFIRMED`, `REQUESTED`, and `PENDING_WAIT_LIST_BOOKING`.
    </ResponseField>

    <ResponseField name="shift_type" type="object | null" required>
      Service the booking belongs to, or `null` before one is available.

      <Expandable title="properties">
        <ResponseField name="id" type="string" required>
          Service type. See [ShiftType](/getting-started/enums#shifttype) for the
          possible values and their meanings. Example: `"DINNER"`.
        </ResponseField>

        <ResponseField name="name" type="string" required>
          The service's public name, as the business named it. Example:
          `"Dinner"`.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="pax" type="number" required>
      Number of adult guests. Example: `2`.
    </ResponseField>

    <ResponseField name="pax_children" type="number" required>
      Number of children. Example: `0`.
    </ResponseField>

    <ResponseField name="high_chairs" type="number" required>
      Number of high chairs requested. Example: `0`.
    </ResponseField>

    <ResponseField name="strollers" type="number" required>
      Number of strollers. Example: `0`.
    </ResponseField>

    <ResponseField name="date" type="string" required>
      ISO 8601 calendar date in `YYYY-MM-DD` format. Example:
      `"2026-07-25"`.
    </ResponseField>

    <ResponseField name="weekday" type="string | null" required>
      Lowercase English weekday corresponding to `date`, or `null` when the
      date is invalid.

      | Value       | Meaning    |
      | ----------- | ---------- |
      | `monday`    | Monday.    |
      | `tuesday`   | Tuesday.   |
      | `wednesday` | Wednesday. |
      | `thursday`  | Thursday.  |
      | `friday`    | Friday.    |
      | `saturday`  | Saturday.  |
      | `sunday`    | Sunday.    |
    </ResponseField>

    <ResponseField name="time" type="string | null" required>
      Local venue time in ISO 8601 `HH:mm:ss` format, or `null` before
      a time is selected. Example: `"20:30:00"`.
    </ResponseField>

    <ResponseField name="floor_plan_area" type="object | null" required>
      Selected seating area, or `null` when no area applies.

      <Expandable title="properties">
        <ResponseField name="id" type="string" required>
          Namespaced resource ID. Example:
          `"best_burger:floor_plan_area:3"`.
        </ResponseField>

        <ResponseField name="name" type="string" required>
          Public area name. Example: `"Terrace"`.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="experience" type="object | null" required>
      Selected experience or menu, or `null` when none applies.

      <Expandable title="properties">
        <ResponseField name="id" type="string" required>
          Namespaced resource ID. Example: `"best_burger:experience:7"`.
        </ResponseField>

        <ResponseField name="price_per_ticket" type="number" required>
          Price per ticket in the currency's smallest unit. Example: `6500`
          means €65.00 when `currency` is `EUR`.
        </ResponseField>

        <ResponseField name="currency" type="string" required>
          ISO 4217 currency code. See
          [Currency](/getting-started/enums#currency) for more information.
        </ResponseField>

        <ResponseField name="tickets" type="number" required>
          Number of experience tickets selected. Example: `2`.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="add_ons" type="object[]" required>
      Selected add-ons. The array is empty when none are selected.

      <Expandable title="item properties">
        <ResponseField name="id" type="string" required>
          Namespaced resource ID. Example: `"best_burger:add_on:12"`.
        </ResponseField>

        <ResponseField name="unit_price" type="number" required>
          Unit price in the currency's smallest unit. Example: `2500` means
          €25.00 when `currency` is `EUR`.
        </ResponseField>

        <ResponseField name="currency" type="string" required>
          ISO 4217 currency code. See
          [Currency](/getting-started/enums#currency) for more information.
        </ResponseField>

        <ResponseField name="quantity" type="number" required>
          Number of units selected. Example: `2`.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      ISO 4217 currency code for the booking total. See
      [Currency](/getting-started/enums#currency) for more information.
    </ResponseField>

    <ResponseField name="total_amount" type="number" required>
      Total price of the experience and add-ons in the currency's smallest
      unit. Example: `18000` means €180.00 when `currency` is `EUR`.
    </ResponseField>

    <ResponseField name="is_time_limited" type="boolean" required>
      Whether the selected time slot has a fixed end time.
    </ResponseField>

    <ResponseField name="cancellation_policy" type="object | null" required>
      Applied cancellation policy, or `null` when no policy applies.

      <Expandable title="properties">
        <ResponseField name="type" type="string" required>
          Policy type. This object uses `PREPAYMENT` or
          `GUARANTEE_AUTHORIZATION`. See
          [CancellationPolicyType](/getting-started/enums#cancellationpolicytype)
          for their meanings.
        </ResponseField>

        <ResponseField name="amount" type="number" required>
          Policy amount per guest or per booking, depending on `amount_type`,
          in the currency's smallest unit.
        </ResponseField>

        <ResponseField name="amount_type" type="string" required>
          How `amount` is applied. See
          [CancellationPolicyAmountType](/getting-started/enums#cancellationpolicyamounttype) for more information.
        </ResponseField>

        <ResponseField name="cancellation_fee_amount" type="number" required>
          Total cancellation fee in the currency's smallest unit.
        </ResponseField>

        <ResponseField name="charged_amount" type="number | null" required>
          Amount charged upfront in the currency's smallest unit, or `null`
          when nothing has been charged yet.
        </ResponseField>

        <ResponseField name="cancellation_notice_hours" type="number" required>
          Number of hours before the booking when the cancellation penalty
          begins to apply.
        </ResponseField>

        <ResponseField name="currency" type="string" required>
          ISO 4217 currency code. See
          [Currency](/getting-started/enums#currency) for more information.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

### Resource IDs

Experience, add-on, area, and time-slot IDs use the following format:

```text theme={null}
{account_id}:{resource_type}:{source_id}
```

Each segment is lowercase. Non-alphanumeric characters are normalized to underscores.

```text theme={null}
best_burger:experience:7
best_burger:add_on:12
best_burger:floor_plan_area:3
best_burger:time_slot:20_30
```

A time-slot ID identifies the account and local time of day. Use the item's
`date` and `floor_plan_area_id` fields when you need the complete booking
context.

### NoAvailability

Used by `booking_no_availability_viewed`.

```js theme={null}
{
  availability: {
    outcome: "SHIFT_FULL",
    fallback_actions: ["CONTACT", "SEARCH_ALTERNATIVE_DATES"]
  },
  booking: {
    // Same fields as BookingFunnel.booking.
  }
}
```

**Fields**

<ResponseField name="availability" type="object" required>
  Result shown when no availability is found.

  <Expandable title="properties">
    <ResponseField name="outcome" type="string" required>
      Machine-readable reason for the unavailable search. See
      [AvailabilityOutcome](/getting-started/enums#availabilityoutcome) for the
      possible values and their meanings.
    </ResponseField>

    <ResponseField name="fallback_actions" type="string[]" required>
      Alternatives offered to the visitor. See
      [AvailabilityFallbackOption](/getting-started/enums#availabilityfallbackoption)
      for the possible values and their meanings.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="booking" type="object" required>
  Booking snapshot documented in [BookingFunnel](#bookingfunnel).
</ResponseField>

### BookingViewItemList

Used by `booking_item_list_viewed`. It follows the e-commerce
`view_item_list` pattern and is emitted once when the list view is shown.

**Fields**

<ResponseField name="list_type" type="string" required>
  Type of list shown.

  | Value                 | Meaning                                             |
  | --------------------- | --------------------------------------------------- |
  | `booking_experiences` | Experiences or menus available to book.             |
  | `booking_time_slots`  | Available booking times.                            |
  | `booking_add_ons`     | Optional products that can be added to the booking. |
</ResponseField>

<ResponseField name="items" type="object[]" required>
  Items shown in the list. Their fields depend on `list_type`.

  <Expandable title="booking_experiences item">
    <ResponseField name="id" type="string" required>
      Namespaced experience ID. Example: `"best_burger:experience:7"`.
    </ResponseField>

    <ResponseField name="price_per_ticket" type="number" required>
      Price per ticket in the currency's smallest unit.
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      ISO 4217 currency code. See [Currency](/getting-started/enums#currency) for more information.
    </ResponseField>

    <ResponseField name="is_time_limited" type="boolean" required>
      Whether the experience has a fixed end time.
    </ResponseField>
  </Expandable>

  <Expandable title="booking_time_slots item">
    <ResponseField name="id" type="string" required>
      Namespaced time-slot ID. Example: `"best_burger:time_slot:20_30"`.
    </ResponseField>

    <ResponseField name="date" type="string" required>
      ISO 8601 calendar date in `YYYY-MM-DD` format.
    </ResponseField>

    <ResponseField name="time" type="string" required>
      Local venue time in ISO 8601 `HH:mm:ss` format.
    </ResponseField>

    <ResponseField name="floor_plan_area_id" type="string | null" required>
      Namespaced seating-area ID, or `null` when no area applies.
    </ResponseField>
  </Expandable>

  <Expandable title="booking_add_ons item">
    <ResponseField name="id" type="string" required>
      Namespaced add-on ID. Example: `"best_burger:add_on:12"`.
    </ResponseField>

    <ResponseField name="unit_price" type="number" required>
      Unit price in the currency's smallest unit.
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      ISO 4217 currency code. See
      [Currency](/getting-started/enums#currency) for more information.
    </ResponseField>
  </Expandable>
</ResponseField>

<Tabs>
  <Tab title="Experiences">
    ```js theme={null}
    {
      list_type: "booking_experiences",
      items: [
        {
          id: "best_burger:experience:7",
          price_per_ticket: 6500,
          currency: "EUR",
          is_time_limited: false
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Time slots">
    ```js theme={null}
    {
      list_type: "booking_time_slots",
      items: [
        {
          id: "best_burger:time_slot:20_30",
          date: "2026-07-25",
          time: "20:30:00",
          floor_plan_area_id: "best_burger:floor_plan_area:3"
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Add-ons">
    ```js theme={null}
    {
      list_type: "booking_add_ons",
      items: [
        {
          id: "best_burger:add_on:12",
          unit_price: 2500,
          currency: "EUR"
        }
      ]
    }
    ```
  </Tab>
</Tabs>

### BookingSelectItem

Used by `booking_item_selected`. It follows the e-commerce `select_item`
pattern. The item shapes match [BookingViewItemList](#bookingviewitemlist);
selected experiences also include `tickets`, and selected add-ons include
`quantity`.

**Fields**

<ResponseField name="list_type" type="string" required>
  Type of item selected.

  | Value                 | Meaning                          |
  | --------------------- | -------------------------------- |
  | `booking_experiences` | An experience or menu selection. |
  | `booking_time_slots`  | A booking-time selection.        |
  | `booking_add_ons`     | An add-on selection.             |
</ResponseField>

<ResponseField name="items" type="object[]" required>
  Selected items. Their fields depend on `list_type`.

  <Expandable title="booking_experiences item">
    <ResponseField name="id" type="string" required>
      Namespaced experience ID.
    </ResponseField>

    <ResponseField name="price_per_ticket" type="number" required>
      Price per ticket in the currency's smallest unit.
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      ISO 4217 currency code. See [Currency](/getting-started/enums#currency) for more information.
    </ResponseField>

    <ResponseField name="is_time_limited" type="boolean" required>
      Whether the experience has a fixed end time.
    </ResponseField>

    <ResponseField name="tickets" type="number" required>
      Number of tickets selected.
    </ResponseField>
  </Expandable>

  <Expandable title="booking_time_slots item">
    <ResponseField name="id" type="string" required>
      Namespaced time-slot ID.
    </ResponseField>

    <ResponseField name="date" type="string" required>
      ISO 8601 calendar date in `YYYY-MM-DD` format.
    </ResponseField>

    <ResponseField name="time" type="string" required>
      Local venue time in ISO 8601 `HH:mm:ss` format.
    </ResponseField>

    <ResponseField name="floor_plan_area_id" type="string | null" required>
      Namespaced seating-area ID, or `null` when no area applies.
    </ResponseField>
  </Expandable>

  <Expandable title="booking_add_ons item">
    <ResponseField name="id" type="string" required>
      Namespaced add-on ID.
    </ResponseField>

    <ResponseField name="unit_price" type="number" required>
      Unit price in the currency's smallest unit.
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      ISO 4217 currency code. See
      [Currency](/getting-started/enums#currency) for more information.
    </ResponseField>

    <ResponseField name="quantity" type="number" required>
      Number of units selected.
    </ResponseField>
  </Expandable>
</ResponseField>

<Tabs>
  <Tab title="Experience">
    ```js theme={null}
    {
      list_type: "booking_experiences",
      items: [
        {
          id: "best_burger:experience:7",
          price_per_ticket: 6500,
          currency: "EUR",
          is_time_limited: false,
          tickets: 2
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Time slot">
    ```js theme={null}
    {
      list_type: "booking_time_slots",
      items: [
        {
          id: "best_burger:time_slot:20_30",
          date: "2026-07-25",
          time: "20:30:00",
          floor_plan_area_id: "best_burger:floor_plan_area:3"
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Add-on">
    ```js theme={null}
    {
      list_type: "booking_add_ons",
      items: [
        {
          id: "best_burger:add_on:12",
          unit_price: 2500,
          currency: "EUR",
          quantity: 2
        }
      ]
    }
    ```
  </Tab>
</Tabs>

### BookingViewItemDetail

Used by `booking_item_detail_viewed`. It follows the e-commerce `view_item`
pattern.

```js theme={null}
{
  type: "experience",
  list_type: "booking_experiences",
  item: {
    id: "best_burger:experience:7"
  }
}
```

**Fields**

<ResponseField name="type" type="string" required>
  Kind of item opened.

  | Value             | Meaning                |
  | ----------------- | ---------------------- |
  | `experience`      | An experience or menu. |
  | `floor_plan_area` | A seating area.        |
</ResponseField>

<ResponseField name="list_type" type="string" required>
  List from which the detail was opened: `booking_experiences`,
  `booking_time_slots`, or `booking_add_ons`. See the definitions in
  [BookingViewItemList](#bookingviewitemlist).
</ResponseField>

<ResponseField name="item" type="object" required>
  Item whose detail was opened.

  <Expandable title="properties">
    <ResponseField name="id" type="string" required>
      Namespaced resource ID.
    </ResponseField>
  </Expandable>
</ResponseField>

### ActionTaken

Used by `action_taken`.

```js theme={null}
{
  category: "contact",
  option: "whatsapp"
}
```

**Fields**

<ResponseField name="category" type="string" required>
  Group to which the action belongs.

  | Value                      | Meaning                                                         |
  | -------------------------- | --------------------------------------------------------------- |
  | `contact`                  | The visitor contacts the business.                              |
  | `add_to_calendar`          | The visitor saves a booking to a calendar.                      |
  | `invite_guests`            | The visitor shares a booking invitation.                        |
  | `get_directions`           | The visitor opens directions to the venue.                      |
  | `recommend`                | The visitor recommends the business.                            |
  | `share_experience`         | The visitor shares or reviews the experience.                   |
  | `update_booking`           | The visitor opens the flow to update a booking.                 |
  | `cancel_booking`           | The visitor opens the flow to cancel a booking.                 |
  | `add_to_contacts`          | The visitor saves the business's contact details.               |
  | `visit_website`            | The visitor opens the business's website.                       |
  | `no_availability_fallback` | The visitor selects an alternative after an unavailable search. |
</ResponseField>

<ResponseField name="option" type="string" required>
  Specific choice made within the category.

  | Value                       | Meaning                                                  |
  | --------------------------- | -------------------------------------------------------- |
  | `open`                      | Opens a menu, modal, or picker before a concrete choice. |
  | `click`                     | Performs a direct action with no submenu.                |
  | `phone`                     | Uses a phone call.                                       |
  | `email`                     | Uses email.                                              |
  | `whatsapp`                  | Uses WhatsApp.                                           |
  | `sms`                       | Uses SMS.                                                |
  | `instagram`                 | Uses Instagram.                                          |
  | `facebook`                  | Uses Facebook.                                           |
  | `google`                    | Uses Google.                                             |
  | `copy_link`                 | Copies a link to the clipboard.                          |
  | `share`                     | Opens the device's native share interface.               |
  | `copy_tag`                  | Copies the business's tag to the clipboard.              |
  | `copy_hashtags`             | Copies suggested hashtags to the clipboard.              |
  | `copy_sticker`              | Copies the story sticker to the clipboard.               |
  | `open_instagram`            | Opens Instagram to publish a post or story.              |
  | `google_calendar`           | Adds the booking to Google Calendar.                     |
  | `apple_calendar`            | Adds the booking to Apple Calendar.                      |
  | `outlook_calendar`          | Adds the booking to the Outlook desktop calendar.        |
  | `outlook_com`               | Adds the booking to Outlook.com.                         |
  | `venue_address`             | Opens directions to the venue address.                   |
  | `nearest_parking`           | Opens directions to the nearest parking location.        |
  | `contact`                   | Contacts the business after an unavailable search.       |
  | `request_booking`           | Requests a booking for the business to confirm.          |
  | `join_wait_list`            | Joins the business's wait list.                          |
  | `search_alternative_dates`  | Searches availability on other dates.                    |
  | `search_alternative_venues` | Searches availability at other venues in the group.      |
  | `update_search`             | Changes the current search.                              |
</ResponseField>

<Note>
  **A contact through the menu emits two events, not one.** Opening the contact
  menu sends `option: "open"`, and picking the channel sends the channel —
  `"whatsapp"`, `"phone"`, or `"email"` — both with `category: "contact"`. Where
  the channels are shown directly, with no menu, only the second one arrives.

  So to count contacts, filter on `option` and not just on `category`.
  Conversions are unaffected: `"open"` and `"click"` never fire them ([Event
  Mapping](/widget/connect-mappings#ga4-action-data)).
</Note>

### CustomerIdentified

Used by `customer_identified`.

```js theme={null}
{
  method: "form",
  customer: {
    email: "b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514",
    phoneE164: "8c3b8b4a7db6e8d8b2f3f0d3a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0",
    phoneMsisdn: "14976e7970d2191d37cb8853db2d372d671594e432cae1f6602668060303222a"
  }
}
```

**Fields**

<ResponseField name="method" type="string" required>
  How the customer was identified.

  | Value         | Meaning                                          |
  | ------------- | ------------------------------------------------ |
  | `form`        | The customer submitted the guest-details form.   |
  | `remember_me` | The widget restored remembered customer details. |
</ResponseField>

<ResponseField name="customer" type="object" required>
  Identified customer. Personal text values are normalized by trimming leading
  and trailing whitespace and converting them to lowercase before hashing.

  <Expandable title="properties">
    <ResponseField name="email" type="string | null" required>
      SHA-256 hash of the normalized email, represented as 64 lowercase
      hexadecimal characters, or `null` when absent.
    </ResponseField>

    <ResponseField name="phoneE164" type="string | null" required>
      SHA-256 hash of the phone number in
      [E.164](https://en.wikipedia.org/wiki/E.164) format (with the leading
      `+`), represented as 64 lowercase hexadecimal characters, or `null` when
      absent.
    </ResponseField>

    <ResponseField name="phoneMsisdn" type="string | null" required>
      SHA-256 hash of the same phone number in
      [MSISDN](https://en.wikipedia.org/wiki/MSISDN) format (the same digits,
      without the `+`), or `null` when absent. Meta requires this format for
      matching; every other destination uses `phoneE164`.
    </ResponseField>
  </Expandable>
</ResponseField>

## Send selected events to your data layer

You can forward only the events that matter to your site:

```js theme={null}
const restooEvents = [
  "booking_start_submitted",
  "booking_details_form_submitted",
  "booking_created",
];

restooEvents.forEach((name) => {
  window.addEventListener(`restoo:${name}`, (event) => {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: `restoo_${name}`,
      restoo: event.detail,
    });
  });
});
```

For automatic mappings to supported analytics platforms, use [Restoo Connect](/widget/connect).

## Next steps

<CardGroup cols={2}>
  <Card title="Event Mapping" icon="table" href="/widget/connect-mappings">
    What each of these events becomes in GA4, Google Ads, Meta, TikTok, ChatGPT Ads, and GTM.
  </Card>

  <Card title="Consent" icon="shield-check" href="/widget/consent">
    What needs permission and what does not, and why customer identity is
    handled separately.
  </Card>
</CardGroup>
