Web Widgets
Web Widgets
One loader script adds OnePath's widgets, the booking scheduler and the text-me-back chat form, to your site.
<head>
<script src="https://cdn.onepath.ai/loader.js"></script>
</head>
<body>
<button data-onepath-web-scheduler-trigger>Book a service</button>
<button data-onepath-web-chat-trigger>Text me back</button>
</body>
Put the script in the document head. Add a button anywhere. That is the whole integration: no token, no per-widget scripts, no init call. The loader picks up every widget enabled on the account.
Your domain must be on the account's Allowed websites list
The loader recognizes the account from the domain the page is served on. If that domain (including your staging domain) is not on the list, the widget never renders and the button does nothing. Add it under Account settings → Lead Capture → Channels → Web Widgets card → Allowed websites, or ask whoever manages the account. Channels
Using a speed plugin? Safelist cdn.onepath.ai
If your site runs a performance plugin that delays, defers or combines JavaScript, such as NitroPack, WP Rocket, LiteSpeed Cache, Perfmatters, Flying Scripts or Cloudflare Rocket Loader, safelist the whole cdn.onepath.ai domain in it. In NitroPack that is Excluded Resources → Delayed Scripts; other plugins name the setting similarly.
Safelisting the loader tag alone is not enough. loader.js is only the starting point: while your page loads it fetches the rest of the widget, the scheduler, the chat and their shared runtime, as separate scripts from that same domain. Those are the ones these plugins rewrite or hold back.
When that happens the page looks completely normal and the button appears, but clicking it does nothing, because the scripts behind it never ran. Safelisting the domain covers the loader and everything it fetches.
How the account is recognized
There is no key in the snippet. The loader sends the page's address to OnePath, and OnePath looks up which account lists that domain.
- The domain must be on the account's Allowed websites list (Account settings → Lead Capture → Channels → Web Widgets card → Allowed websites).
- The business website entered under Business Info is always on the list and cannot be removed.
- A root domain entry (
acme.comorwww.acme.com) covers every subdomain, such asstaging.acme.comorbook.acme.com. A subdomain entry covers only that subdomain. - The Web Widgets toggle on the Channels page must be on. Turning it off disables the scheduler and chat on every site at once.
When the domain is not recognized, the loader's request to https://app.onepath.ai/api/public/authentication answers 403 and nothing else loads. That request is the first thing to check in dev tools. See Troubleshooting.
Rules for the script tag
- Exactly one loader tag per page. If a plugin or tag manager already adds it, do not add it again in the theme.
- Do not add an
integrityattribute (SRI).loader.jsis updated continuously, so a pinned hash breaks the embed at the next release. - Keep it in the head. The loader works from anywhere on the page, but an
onepath:webscheduler:openevent dispatched beforeloader.jshas run is lost. Trigger clicks are safe wherever the tag sits: a click that happens before the widget is ready is replayed once it is. - Leave it as a plain
<script src>tag. No attributes are read from it.
What the loader loads
- It fetches the account's public configuration (name, colors, logo, phone, which widgets are enabled) and fires
onepath:config-ready. - It loads the scripts for the enabled widgets from
cdn.onepath.ai. Those scripts are versioned, so there is nothing to cache-bust; new releases reach your site within about five minutes. - If a visitor clicked a trigger while the widgets were still loading, that click is replayed.
Nothing is visible on page load. The scheduler is a modal that opens from a trigger. Chat is a panel that opens from its trigger; no floating bubble is rendered, your site supplies the button. A third, invisible module registers booking tools for AI agents in Chrome; see Booking by AI agents. Both widgets render in isolated styles, so your CSS does not leak into them. Colors and logo come from the account, not from the tag. See What your visitors see.
Buttons, context, and pre-selection
Any element with data-onepath-web-scheduler-trigger opens the scheduler. Add data-onepath-context, data-onepath-serviceable-type and data-onepath-service-type to attach a package to the booking and pre-select the service:
<div data-onepath-context
data-onepath-serviceable-type="Water Heater"
data-onepath-service-type="Estimate">
Better Package — 50 Gallon — $2,695
<button data-onepath-web-scheduler-trigger>Book this package</button>
</div>
→ Every option, URL parameters, and what the context looks like downstream: Buttons, links & context
Open the scheduler from your own form
Dispatch one event with the visitor's details and the scheduler opens pre-filled.
→ Open the scheduler from a form submit
Chat widget
The same loader serves the chat form. It is a short "we'll text you" form, not live chat.
Next steps
| Page | What it covers |
|---|---|
| Add the widgets to your site | WordPress, Webflow, Squarespace, Wix, Google Tag Manager, React/Next.js, and how to verify |
| What your visitors see | The booking flow screen by screen and the setting behind each part |
| Booking by AI agents | Chrome WebMCP tools that let an AI assistant book without the form |
| Events | Booking events for GA4, Tag Manager, and redirects |
| Webhook events | Server-side JSON POST for appointment changes, calls that need attention, and hand-offs to your team |
| Troubleshooting | Symptom → cause → fix |
| Legacy Web Scheduler embed | Migrating from onepath-embed.js |