Get startedInstall

CDN script tag

Install any Medos widget with a single script tag from the CDN: deferred, at the end of the body, or loaded on demand in a single-page app.

The CDN bundle is a self-contained IIFE. It ships React, MUI, and every other dependency inside the bundle, so you don't need a build step.

The script tag

<script src="https://widgets.medos.one/v2/unified.js"></script>

This is the production endpoint. It's the same URL for every site — there's nothing to configure per environment.

The other bundles

unified.js is the booking widget, and the rest of this page is about it. The other widgets are separate scripts with the same loading rules — load only what a page uses, since each carries its own copy of React:

WidgetScriptGlobal
Bookinghttps://widgets.medos.one/v2/unified.jswindow.MedosBooking
Patient portalhttps://widgets.medos.one/v2/portal.jswindow.MedosPatientPortal
Enquiry formhttps://widgets.medos.one/v2/enquiries.jswindow.MedosEnquiry
Package purchasehttps://widgets.medos.one/v2/packages.jswindow.MedosPackagePurchase

What's inside

The bundle includes React 19, MUI v7, TanStack Query, Zustand, and every other runtime dependency, so there's nothing else to install.

It's roughly 970 KB uncompressed, served gzipped from CloudFront with a one-year immutable cache (max-age=31536000). Because the URL is versioned, returning visitors get it straight from cache.

Where to put the tag

These patterns are the same for every widget — swap in the script and global from the table above.

<!-- At the end of <body>, before the code that calls init() -->
<script src="https://widgets.medos.one/v2/unified.js"></script>
<!-- In <head>; the global is ready by the time DOMContentLoaded fires -->
<script defer src="https://widgets.medos.one/v2/unified.js"></script>
// For SPAs that only need a widget on some routes. Resolves with the global,
// and skips the request if the script has already loaded.
function loadMedos(src, globalName) {
  return new Promise((resolve, reject) => {
    if (window[globalName]) return resolve(window[globalName]);
    const s = document.createElement("script");
    s.src = src;
    s.onload = () => resolve(window[globalName]);
    s.onerror = reject;
    document.head.appendChild(s);
  });
}

const MedosBooking = await loadMedos(
  "https://widgets.medos.one/v2/unified.js",
  "MedosBooking",
);

After it loads

The bundle exposes exactly one global:

interface Window {
  MedosBooking: {
    init: (config: MedosBookingConfig) => void;
    open: (config?: Partial<MedosBookingConfig>) => void;
    close: () => void;
  };
}

Every option and callback is documented in Configure options. The other bundles each expose their own global with the same init / open / close shape — except the package widget, which has init only. See Widgets.

Checking the script actually loaded

If MedosBooking is undefined at runtime, the script failed to load. Add an error handler to the tag:

<script
  src="https://widgets.medos.one/v2/unified.js"
  onerror="console.error('Medos Booking failed to load')"
></script>

On this page