Booking on your website (embed)

With the embed, customers pick the service and the time and confirm the booking without leaving your website. Paste one line of code on the page: the embed.js script mounts booking in a safe iframe served by https://calendar.sendeasy.app.

Requirements

  • Website booking enabled for your company.
  • A time slot calendar with active event types (services). Lodging calendars have no embed: use the calendar link.
  • Your website on https. Pages on http or opened as a local file cannot show booking.

Installation

Paste the code where booking should show:

<script src="https://calendar.sendeasy.app/embed.js"
  data-sendeasy-calendar="YOUR_CALENDAR"
  data-mode="inline"
  async></script>

YOUR_CALENDAR is the calendar address, the same as in the link https://calendar.sendeasy.app/c/YOUR_CALENDAR.

To place booking inside an element of yours (instead of right after the tag), mark the element and load the script once on the page:

<div data-sendeasy-calendar="YOUR_CALENDAR" data-type="consultation-30"></div>
<script src="https://calendar.sendeasy.app/embed.js" async></script>

Formats

data-modeWhat shows
inline (default)Booking inside the page, right after the tag (or inside the marked element). The height follows the content.
popupA button where the tag is. Clicking it opens booking in a window over the page. On a marked element that is not a <script>, the element itself becomes the button.
buttonA floating button fixed in the bottom right corner of the page, which opens the same window.

The window closes on its X, with Esc, with a click outside it or with the Close button of the confirmation.

Options

  • Name
    data-sendeasy-calendar
    Type
    required
    Description

    Calendar address (letters, digits, ., _, ~ and -, up to 190 characters).

  • Name
    data-type
    Type
    optional
    Description

    Service (event type) address, for example consultation-30. Opens that service directly, hidden services included. Without it, the customer sees the list of services.

  • Name
    data-mode
    Type
    optional
    Description

    inline, popup or button. Any other value becomes inline.

  • Name
    data-label
    Type
    optional
    Description

    Button text for the popup and button formats, up to 60 characters. Default: Agendar.

  • Name
    data-color
    Type
    optional
    Description

    Color of the button and of the booking highlights, in hexadecimal (#0f766e or #0a7).

  • Name
    data-lang
    Type
    optional
    Description

    Booking language: pt, pt-BR, en, en-US, es or es-ES. Without it, the visitor's browser language applies.

  • Name
    data-utm-source, data-utm-medium, data-utm-campaign, data-utm-term, data-utm-content
    Type
    optional
    Description

    Booking campaign, up to 200 characters each. The booking is already marked as coming from the website (with the domain, never the page path); UTM tags help tell pages or actions apart.

Values out of format are ignored: booking opens with the default. No value becomes HTML: the button text goes in as plain text.

JavaScript API

With embed.js on the page, open booking from any button of yours:

<button type="button" id="book">Book now</button>
<script src="https://calendar.sendeasy.app/embed.js" async></script>
<script>
  document.getElementById('book').addEventListener('click', function () {
    if (window.SendeasyCalendar) {
      window.SendeasyCalendar.open({ calendar: 'YOUR_CALENDAR', type: 'consultation-30' })
    }
  })
</script>
  • window.SendeasyCalendar.open(options) opens the window and returns true (or false with an invalid calendar). Options: calendar (required), type, color, lang and utm ({ source, medium, campaign, term, content }).
  • window.SendeasyCalendar.close() closes the open window.

Since the script loads with async, check that window.SendeasyCalendar exists before calling it.

Messages to your website (postMessage v1)

Booking notifies the page with postMessage. Every message has this shape:

{ "source": "sendeasy", "v": 1, "type": "..." }
typeFieldsWhen
readyBooking has loaded.
resizeheight (px, up to 20000)The content height changed. embed.js already adjusts the inline format by itself.
slot_selecteddate (YYYY-MM-DD), time (HH:mm)The customer picked a time. Local date and time of the business.
booking.createdcode, status, startAtThe booking was created. code is the 8 character code (or null), status is HOLD, PENDING_PAYMENT, AWAITING_APPROVAL, CONFIRMED or CANCELLED, and startAt is the start in ISO 8601 (UTC).
booking.payment_requiredcodeThe booking needs payment; the payment button opens the checkout in a new tab.
closedThe customer closed booking (Esc or Close), in the popup and button formats.

Messages carry no personal data: no name, email, phone, answers, payment or management links. Booking accepts no messages from your page. Always check the origin before using them:

window.addEventListener('message', function (event) {
  if (event.origin !== 'https://calendar.sendeasy.app') return
  var data = event.data
  if (!data || data.source !== 'sendeasy' || data.v !== 1) return

  if (data.type === 'booking.created') {
    // Example: conversion event in Google Analytics 4
    gtag('event', 'booking_created', { status: data.status })
  }
})

Messages are only sent to https pages whose origin the browser gives to the iframe. Unknown origin: no message is sent.

Your website CSP

If your website sends a Content-Security-Policy header, allow the calendar domain for the script and for the iframe:

Content-Security-Policy: script-src 'self' https://calendar.sendeasy.app; frame-src https://calendar.sendeasy.app

Add these origins to the directives you already use (script-src and frame-src, or child-src if the site does not use frame-src). On the Sendeasy side, the iframe can be shown by any https website.

Pinned version with SRI (optional)

/embed.js gets fixes automatically (cached for up to one day). To pin a version with Subresource Integrity, read the version and the hash from the response headers:

curl -sI https://calendar.sendeasy.app/embed.js | grep -i x-sendeasy-embed

and use both values:

<script src="https://calendar.sendeasy.app/embed.js?v=VERSION"
  integrity="sha384-HASH"
  crossorigin="anonymous"
  data-sendeasy-calendar="YOUR_CALENDAR"
  async></script>

When the script changes, the old version no longer matches the hash and the browser runs nothing: update both values.

Limits

  • Payment always opens in the top level tab, in a new tab, outside your website. The checkout and the booking management links can never be shown inside an iframe.
  • https websites only. http pages do not show booking.
  • Time slot calendars with event types only. Lodging keeps using the calendar link.
  • The iframe keeps nothing between visits (browsers block third party storage); the confirmation stays on screen until the customer closes it.
  • The booking page inside the iframe is not indexed by search engines. To show up on Google, use your Public page and the Google Business Profile.
  • One window at a time: opening another closes the previous one.

Common problems

SymptomWhat to check
Nothing showsIs the feature enabled for the company? Is the calendar address right? Does the browser console show a CSP block?
Error page inside the frameThe calendar has no active services, or the data-type service does not exist.
Booking does not show on httpThe website must be on https.
Payment opens in another tabThat is expected: the checkout never runs inside your website.

Essa informação foi útil?