# Embed booking on your website

> Add your Workspace369 booking page to any website inline or as a popup button with one script tag, fall back to a plain iframe, or drive it from JavaScript.

- Product: Workspace369
- Documentation version: 2026.3
- Section: Scheduling
- Last updated: 2026-09-07
- Canonical source: https://docs.workspace369.com/v/2026.3/scheduling/embed-booking-on-your-website/

---

Your booking page does not have to live only at 369.dev. Paste one snippet from **Share & embed** into your website and clients can book without leaving your site. The embed shows the same services, availability, and payment steps as the public page.

## Choose an embed style

| Style | Best for |
| --- | --- |
| Inline | A dedicated booking page or section on your site; the booking flow renders in place and grows to fit its content |
| Popup button | Any page on the site; a floating button opens the booking flow in an overlay |
| Plain iframe | Site builders that block custom scripts; fixed height, no popup, no JavaScript API |

All three come ready to copy from Share & embed with your workspace and page already filled in. Every embed shows a "Powered by Workspace369" credit line.

## Add an inline booking page

1. Open the booking page's Share & embed action and copy the inline snippet.
2. Paste it into your site's HTML where the booking flow should appear.

```html
<script src="https://369.dev/booking.js" data-booking
  data-workspace="WS_ID"
  data-page="SLUG" async></script>
```

`WS_ID` is your workspace ID and `SLUG` is the page's link slug; the snippet from Share & embed already contains both, and the default page needs no `data-page` at all. The frame sizes itself to the booking flow as the client moves through it, so it needs no fixed height.

## Add a popup button

1. Open the booking page's Share & embed action and copy the popup snippet.
2. Paste it just before the closing `</body>` tag of every page where the button should appear, or into your site builder's site-wide footer or custom-code area so the button appears everywhere.

```html
<script src="https://369.dev/booking.js" data-booking
  data-workspace="WS_ID"
  data-page="SLUG"
  data-mode="popup" data-label="Book now" data-color="#111827" async></script>
```

`data-label` sets the button text and `data-color` its color. The booking flow opens in an overlay that scrolls inside itself; the client closes it with the close control or by pressing Escape.

To open the popup from your own button or link instead, add `data-w369-booking` to any element on the page:

```html
<a href="#" data-w369-booking>Book a consultation</a>
```

## Use a plain iframe

1. Open the booking page's Share & embed action and copy the iframe snippet.
2. Paste it into your site's HTML where the booking flow should appear.

```html
<iframe src="https://369.dev/ws/WS_ID/book/SLUG?embed=1" title="Book an appointment" width="100%" height="900" style="border:0;display:block" loading="lazy"></iframe>
```

Use this when your site builder strips or blocks script tags. The iframe cannot resize itself, so adjust `height` to fit the longest step of the booking flow. The popup mode, the `data-` attributes, and the JavaScript API are not available with a plain iframe.

## Attributes reference

| Attribute | Required | Purpose |
| --- | --- | --- |
| `data-booking` | Yes | Marks the script tag as a booking embed |
| `data-workspace` | Yes | Your workspace ID |
| `data-page` | No | The booking page slug; omit it for the default page |
| `data-mode="popup"` | No | Shows a floating button instead of an inline frame |
| `data-label` | No | The popup button text; defaults to "Book now" |
| `data-color` | No | The popup button color as a hex value |
| `data-service` | No | Starts the flow with a service already selected |
| `data-member` | No | Starts the flow with a host already selected |
| `data-theme` | No | Applies a specific theme to the embed |
| `data-prefill-name`, `data-prefill-email`, `data-prefill-phone` | No | Prefill the client's details |

Advanced — `data-service`, `data-member`, and `data-theme` take internal identifiers and are meant for developer integrations; most sites should let the visitor choose.

## Keep campaign attribution

`utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, and `utm_content` on the URL of the page hosting the embed are forwarded to the booking page, so campaign links keep their attribution.

## React to bookings from your page

The script installs a small JavaScript API on the page:

```html
<button type="button" onclick="W369Booking.open({ prefill: { name: 'Ada Lovelace', email: 'ada@example.com' } })">Book an appointment</button>
<script>
  window.addEventListener('w369:booked', (event) => {
    const { bookingId, status, startMs } = event.detail;
    // record a conversion, show a thank-you message, and so on
  });
</script>
```

- `W369Booking.open({ page, service, member, theme, prefill })` opens the booking flow in the popup overlay. Every option is optional and overrides the matching script attribute; `prefill` takes `{ name, email, phone }`.
- `W369Booking.close()` closes the popup.
- `w369:booked` fires on `window` when a client completes the flow. `event.detail` carries `bookingId`, `status`, and `startMs`, the appointment's start time in milliseconds.

## Payments inside an embed

When a service requires a deposit or full payment, the embed does not try to take the card inside the frame. The client sees a **Continue to secure payment** button that opens Stripe Checkout at the top level of the browser window. After paying, the client lands on a confirmation page on 369.dev with a **Back to example.com** button, where example.com is your site's domain, that returns them to your website.

The slot stays held for 30 minutes during payment, exactly as on the public page.

## Troubleshooting

| Symptom | Check |
| --- | --- |
| Nothing renders | Your site builder may block custom scripts; confirm the script tag survived publishing, or switch to the plain iframe |
| "Booking is not available" | The page is paused, or the last active page was paused or deleted. Resume it in **Booking Pages** |
| The frame is cut off | Inline embeds size themselves; a plain iframe needs a larger `height`; popups scroll inside the overlay |

Continue to [Manage booking requests](/v/2026.3/scheduling/manage-booking-requests/).

> Embeds always show "Powered by Workspace369". Deposits and full payments open Stripe Checkout in the top-level window and need a connected Stripe account.
