Integration Module
integration.js is a small module you copy into your own project. It wraps the raw postMessage protocol in a pub-sub API, creates the iframe element with the right attributes, and handles route syncing for you.
This is the supported way to integrate the iFrame. The module is where the postMessage protocol is dealt with, so the rest of this section documents behaviour in terms of its API rather than raw messages. The protocol itself is documented in All Events, for when you need to know exactly what goes over the wire.
Getting the file
Copy the full source into your project — for example as services/integration.js — then import it as integration.
The examples throughout these docs use services/integration and path_to/integration interchangeably; both just mean “wherever you put the file”.
Because you own the copy, you also own keeping it current. Check the Source page when upgrading, and diff it against your copy.
Setting it up
Configure with init(), then create the iframe with mount(). init() returns the module, so calls can be chained.
Both calls in context, in a full integration with subscriptions and teardown, are in Getting Started. Their signatures follow.
init(options)
Sets the module’s configuration. Call it before mount().
| Option | Type | Required | Description |
|---|---|---|---|
languages | string[] | + | Supported language codes. Used to find and strip the language segment in URLs |
prefix | string | - | URL prefix for the sportsbook section on your site. Default 'sports' |
blacklistedRoutes | string[] | - | Exact route paths to exclude from navigation syncing. See the note below |
isNavigationCaptureDisabled | boolean | - | Set true to stop the module from touching your URL. Default false |
mount(id, inputUrl, onLoadCallback, attributes)
Creates the iframe, appends it to the container you name, and sends the initial iframe-navigation message.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | + | ID of the DOM element the iframe is appended to |
inputUrl | string | + | The iframe URL |
onLoadCallback | Function | - | Assigned to the iframe’s onload. Runs once the iframe’s content and all dependent resources — images, CSS, scripts — have loaded |
attributes | Object | - | Extra attributes merged onto the iframe element, overriding the defaults |
By default the iframe is created with id="betbook", class="betbook", name="target", frameBorder="0", and the allow list that video streaming needs. Anything you pass in attributes replaces the matching default rather than extending it, so passing your own allow drops the permissions the iFrame depends on. See Embedding the iFrame.
mount() returns the iframe element, or null if the same URL is already mounted — it de-duplicates repeat calls.
on(event, callback)
Subscribes to a message from the iframe. Returns { off } — call off() to unsubscribe.
import integration from "path_to/integration";
const on = integration.on;
const unsubscriptions = [];
unsubscriptions.push(
on("login.click", () => {
// handles login-related logic whenever the event is emitted
}),
);
unsubscriptions.push(
on("user.balance", () => {
// triggers a UI or data refresh each time the user's balance updates
}),
);Storing the return values makes cleanup a one-liner:
// Remove all event listeners
unsubscriptions.forEach((sub) => sub.off());The callback receives the whole message object, and the payload is not nested the same way for every event. See Message envelope.
emit(data, type)
Sends a message to the iframe, wrapped as { type, value: data }.
import integration from "path_to/integration";
integration.emit({ mode: "dark" }, "theme-mode-change");
integration.emit({}, "get-user-balance");Omitting type sends the message with the module’s default type, iframe, where each key acts as its own command — see The iframe command envelope.
helpers
Shorthands for the most common messages. Each one is equivalent to the emit() call it wraps, so mixing helpers and raw emit() is fine.
| Helper | Equivalent to | Notes |
|---|---|---|
logout() | emit({ logout: true }) | See Session & Auth |
toggleThemeMode(mode?) | emit({ mode }, 'theme-mode-change') | Without an argument, flips between light and dark. Also stores the choice and sets data-theme on document.body |
getCurrentThemeMode() | — | Reads prefers-color-scheme from Local Storage. Returns null when nothing is stored |
updateCurrency(currency) | emit({ currency }, 'currency-update') | See Balance & Currency |
emitThemeName(name) | emit({ name }, 'theme-mode-change') | Sends a named theme rather than a light/dark mode |
What it handles for you
Once init() and mount() have run, the module already does the following — there is nothing to implement on your side for any of it:
- Route capture — subscribes to
navigationand callshistory.replaceState(), applying yourprefixand skipping blacklisted routes. Turn it off withisNavigationCaptureDisabled: true. - Initial navigation — sends
iframe-navigationwith the current path duringmount(). client-url— sends your page’shrefin response tosdkInit, which video streaming and share links depend on. AddbasePathhere for custom share-link paths.- Theme persistence — applies the stored mode on init, falling back to the iframe’s
defaultThemeMode, then to dark.
Customising it
The file is yours, so anything can be changed — but the parts differ a lot in how safe they are to touch.
Change these
| What | Why |
|---|---|
The postMessage target origin | Published as '*', which lets any page receive these messages. Replace it with your iFrame’s origin. The source carries a @todo for exactly this |
THEME_MODE.DEFAULT | The mode applied when nothing is stored and the iframe sends no defaultThemeMode. Default 'dark' |
The blacklistedRoutes fallback | See the note under init() |
Leave these alone
Changing them breaks the protocol rather than customising it:
messagePubSuband thewindowmessage listener — the dispatch layer every subscription depends on.- The
navigationsubscriber’s guard conditions — the checks for'/', the current language segment andpreviousPathare what stop the module from rewriting your URL on the iframe’s own initial load. - The
jwtdeletion in the query handling — it keeps the token out of the URL the module writes into your address bar. setData/getData/store— internal state used bymount().