Frameworks

Microsoft Bookings widget for Next.js

Next.js uses the React package, @bookingsxp/react. The component is marked "use client", renders the custom element during server rendering, and loads the script in the browser, so your booking page can stay a server component with just the widget as a client island.

Plan
Plan: FreeWorks on every plan, including Free ($0, no card).
In short
Use @bookingsxp/react in the App Router: server-rendered element, client-side loader, redirect to your thank-you route.
Microsoft Bookings
Stays your system of record. Bookings land in Outlook and Teams and Microsoft sends the invites and reminders.

How it works

What happens with Next.js

  • @bookingsxp/react ships with the "use client" directive, so you can import it straight into a server component page.
  • The server HTML contains <bookingsxp-widget …>; the loader then draws into its shadow root, which React does not reconcile, so hydration stays clean.
  • redirectUrl accepts relative paths, resolved against the current page, and fills {booking_id}, {service} and {start} after a confirmed booking.
  • Client-side navigation is fine: each mounted component registers with the loader, which is loaded once per page.

Setup

Set up Next.js

4 steps. Names of menus and buttons are as they appear today; vendors rename things, so look for the closest match.
  1. Step 1: Install the React package

    There is no separate Next.js package.

    Shell
    npm i @bookingsxp/react   # npm release pending — until then use the script embed
  2. Step 2: Add a booking route

    The page can remain a server component; the widget is a client component.

    app/book/page.tsx
    import { BookingsXPWidget } from "@bookingsxp/react";
    
    export const metadata = { title: "Book a call" };
    
    export default function BookPage() {
      return (
        <main>
          <h1>Book a call</h1>
          <BookingsXPWidget widget="w_8fk2m1qz" redirectUrl="/thank-you?ref={booking_id}" />
        </main>
      );
    }
  3. Step 3: Read the reference on the thank-you page

    The redirect happens 600 ms after confirmation so pixels can flush. The reference is URL-encoded in the query.

    app/thank-you/page.tsx
    export default async function ThankYou({ searchParams }: { searchParams: Promise<{ ref?: string }> }) {
      const { ref } = await searchParams;
      return <p>You're booked. Your reference is {ref}.</p>;
    }
  4. Step 4: Allow the script in your CSP

    If you send a Content-Security-Policy, allow bookingsxp.com in script-src and frame-src.

    Text
    script-src 'self' https://bookingsxp.com;
    frame-src https://bookingsxp.com;

Outcomes and caveats

What you get

The result

  • A booking page that stays mostly server-rendered.
  • No hydration mismatches from the embed.
  • A typed onBooked callback and a thank-you route with the booking reference.

Good to know

Limits and caveats

  • Put callbacks (onBooked, onEvent) in a client component; functions cannot be passed from a server component.
  • If you load GTM with next/script, make sure it loads on the booking route too, or the dataLayer events have no listener.
  • Static export works; the widget needs no server code in your app.

FAQ

Next.js questions

Something not covered? Email hello@bookingsxp.com.

Start free, no card

One widget, three templates, GTM and GA4 events and attribution in every booking. No card, no time limit.