JavaScript API
Everything goes through one function, SportNinja.push([command, ...args]). Start every script with the queue line, so commands work whether or not embed.js has loaded yet:
window.SportNinja = window.SportNinja || [];Before the loader arrives, push just adds to the queue; the loader runs the queued commands in order when it starts. Commands never throw: a problem is logged to the console with a [SportNinja] prefix.
SportNinja.push(['mount', target, options]);target: a CSS selector ('#sportninja') or an element. The plugin’s iframe is added inside it.options: see the Options Reference.
Each element holds one plugin; mounting on an element that already has one is ignored with a warning.
Update
Section titled “Update”Change the look or layout of a mounted plugin without reloading it:
SportNinja.push(['update', { theme: { mode: 'dark' }, display: { hideHeader: true } }]);- Only
theme,tabsanddisplaycan change. Anything else (key,view, the IDs,initialTab,syncUrl) is fixed at mount; to change those,unmountandmountagain. - Each section you send replaces that whole section. Send the full
themeyou want, not just the key that changed. - Values must be plain data (no functions or DOM objects).
Example: follow your site’s dark-mode toggle.
const theme = { primary: '#1C7ED6' };function setDark(isDark) { SportNinja.push(['update', { theme: { ...theme, mode: isDark ? 'dark' : 'light' } }]);}Unmount
Section titled “Unmount”SportNinja.push(['unmount']); // the only plugin on the pageSportNinja.push(['unmount', '#sportninja']); // a specific oneRemoves the plugin’s iframe. The element itself stays.
Events
Section titled “Events”SportNinja.push(['on', 'registration:completed', (data, { element }) => { console.log('Registered', data.registrationId, 'in', element);}]);The handler gets the event data and { element }, the element the plugin is mounted on. Event data carries IDs only, never personal details.
| Event | When | Data |
|---|---|---|
ready |
The plugin has loaded | { view, id }: the entry page and its ID |
signin |
A visitor signs in inside the plugin | { userId } |
signout |
A visitor signs out | {} |
registration:completed |
A visitor finishes a registration | { registrationId, sessionId } |
A ready handler added after the plugin is already ready is still called once, straight away. Handlers apply to every plugin on the page; use element to tell them apart.
Example: send registrations to your analytics.
SportNinja.push(['on', 'registration:completed', (data) => { window.gtag?.('event', 'sportninja_registration', { registration_id: data.registrationId });}]);Several Plugins on One Page
Section titled “Several Plugins on One Page”Give each plugin its own element and mount call. With more than one plugin, update and unmount need the target first:
SportNinja.push( ['mount', '#standings', { key, view: 'competition', competitionId, initialTab: 'standings', syncUrl: false }], ['mount', '#schedule', { key, view: 'competition', competitionId, initialTab: 'schedule' }],);SportNinja.push(['update', '#standings', { display: { hideHeader: true } }]);Only the first plugin can sync the address. Set syncUrl: false on the others to make that explicit.
Single-Page Apps (React, Vue, etc.)
Section titled “Single-Page Apps (React, Vue, etc.)”- Load
embed.jsonce, e.g. in your page template. - Mount when the container element is in the DOM (after render), and unmount before it’s removed, so a later mount on a new element works.
// ReactuseEffect(() => { const element = ref.current; window.SportNinja = window.SportNinja || []; window.SportNinja.push(['mount', element, options]); return () => window.SportNinja.push(['unmount', element]);}, []);- Leave
syncUrlon only if your router doesn’t use the hash; the plugin keeps its page in#sn=….