HomeAdd a widgetany website
Add a booking calendar to any website
Let visitors book you straight from Any website. Set your real working hours — split days included — and the widget offers slots in the visitor’s own timezone, checking your connected calendar so it never double-books you.
Free plan, no card. Paid plans start at $19 a month.
Why do it this way on any website
Paste it into the page where you want to be booked and you are done — no scheduling service in the middle, no redirect to a third-party booking page with someone else’s branding on it. The calendar renders in your own markup, so your fonts and your section width apply, and the confirmation emails come from your booking, not from a booking platform.
See it working
This is a real Sorraia booking calendar — the one we use for product demos, embedded here exactly the way you would embed yours. Pick a slot and it books.
How to add a booking calendar to any website
The snippet Sorraia gives you is three lines: a comment, an empty placeholder <div>, and a <script> tag. The div is the anchor — the widget renders exactly where you put it and nowhere else.
In Sorraia, add the website and verify it — a DNS TXT record, or a meta tag in your homepage’s <head>. Verification is what lets you attach a widget to that site, so it comes before there is anything to paste.
Save the calendar and the Copy Embed Code popup appears; the Install wizard on the calendar’s row on the Calendars page does the same job with a verification step.
Copy the snippet from Sorraia. It already has your widget’s id and the right URL baked in, so copy it rather than retyping it.
Open the .html file (or the template, component, or partial) for that page and paste all three lines at the spot in the body where the widget should appear.
Save and deploy.
Load the live page. If nothing renders, open DevTools — the form, calendar and shop loaders log with a [WG] prefix — and check your Content-Security-Policy first.
What you get
Let visitors book you straight from any website. Set your real working hours — split days included — and the widget offers slots in the visitor’s own timezone, checking your connected calendar so it never double-books you.
Split days, not one block
A working day is an ordered list of up to four windows, so 9:00–12:00 plus 13:00–17:00 is one calendar rather than a compromise — the lunch gap serves no slots at all. The honest limit: that window list applies to every working day you tick. Split days are supported; giving Monday different hours from Tuesday is not.
Slots in the visitor’s own timezone
The widget detects the visitor’s timezone in their browser and renders every slot in it, with the zone named and changeable from a dropdown — and if their zone is not in the list, it gets added rather than snapping them to a wrong one. Nobody has to work out in their head whether your 3pm is their 3pm, which is the most common way a booking gets missed.
It fails safe, so it never double-books
When a host has a calendar connected, busy time is checked before a slot is offered. If that check cannot complete — the provider is down, the token is stale — the day is treated as busy rather than offered. You may occasionally show less availability than you have; you will not get booked over something.
Name and email are yours to rename
The built-in Name and Email rows are ordinary rows in the field list: rename them, reorder them, put your own questions above them. The booking payload keeps its fixed shape underneath, so renaming a label can never break a workflow that reads it.
Every booking gets a manage link
The confirmation carries a token link the guest uses to reschedule or cancel — rescheduling keeps the same link working, cancelling retires it, so a cancelled meeting’s link stops being a working key the moment the meeting is off.
More detail in the Help Center: Calendars & bookings · Embedding on your website
Things worth knowing about any website
- Astro bundles any <script src> that carries no other attribute — which is exactly the shape of the snippet. Add the is:inline directive so Astro leaves it alone.
- Hugo strips raw HTML out of Markdown unless markup.goldmark.renderer.unsafe is true. Put the tag in a layout or partial instead of in a content file.
- In React, dangerouslySetInnerHTML never executes a script — that is the HTML spec, not a React bug, and it fails silently. Render the placeholder <div> in JSX and load the script separately. In Next.js use next/script: lazyOnload in app/layout.tsx for a floating launcher, the default afterInteractive on the page itself for an inline widget.
- If your site sends a Content-Security-Policy, the directive that catches people out is style-src. The loader builds its stylesheet at runtime — createElement("style"), set textContent, append to <head> — which counts as an inline style, and it sets no nonce anywhere. So it needs 'unsafe-inline' there or the widget loads and renders completely unstyled. A nonce-only style-src breaks it, and 'strict-dynamic' does not help because that is a script-src feature. You also need the Sorraia API origin under connect-src and the host printed in your snippet under script-src.
- Because the widget renders into your DOM rather than an iframe, your own CSS reaches it — an aggressive global rule on form, input or button can restyle it, and an ancestor with overflow:hidden can clip it. That is the trade for having no sandbox: no isolation bugs, but no isolation either.
Questions
Can I have a lunch break, or two separate blocks in a day?
Yes — that is exactly what the windows are for. A day holds up to four working-hours windows, so a morning block and an afternoon block is the normal setup rather than a workaround, and the gap between them offers nothing. What it does not do is per-day hours: the same window list applies to every day you have ticked as a working day.
What timezone do visitors see?
Their own, detected in their browser, with the zone shown on the widget and changeable if they are travelling. Your own timezone is displayed alongside so both sides can see what they are agreeing to.
Does it check my real calendar?
Yes, when you connect one — Google Calendar today. Busy time is read before slots are offered, and if that read fails the day is treated as busy rather than offered, so an outage costs you a few visible slots instead of a double booking. Multi-host modes like round-robin and collective scheduling are available on organisation accounts.
Do I need to install anything?
No. There is no plugin, no package and no build step — the whole install is one script tag. It works on a static site, a hand-written page, a Rails or Laravel template, an SSG like Hugo or Eleventy, or a React app, because it is plain HTML from the browser’s point of view.
Will it work behind a Content-Security-Policy?
Yes, with three directives. Allow the host printed in your own snippet under script-src, allow the Sorraia API origin under connect-src, and allow 'unsafe-inline' under style-src — the loader builds its stylesheet as an injected style element and sets no nonce, so a nonce-only style-src leaves the widget rendered but completely unstyled. If your widget uses a Google webfont, also allow fonts.googleapis.com under style-src and fonts.gstatic.com under font-src.
Add a booking calendar to any website
Build it in Sorraia, paste one line into your site, and change it later without touching the embed again.