Task for an AI agent: integrate Live 3D Tracker
Purpose of this document
This file contains a task for an AI agent that must integrate Live 3D Tracker into an existing client website or web application.
Implement the integration according to the project’s architecture and style. Do not change existing functionality, design, or project structure unless needed.
Information required before starting
Inspect the project and find or request the following information from the user:
- The page or component where the tracker must be displayed.
- An access key in the
pk_live_...format issued by a SportAPI manager. - A production or test domain activated for that key.
- The SportAPI sports-line data source.
- The
zpfield in the selected match data. - The sport ID from the table below.
- The required interface language.
- Height and mobile-layout requirements.
If the key or other required information is missing, do not invent it. Prepare the integration with clear placeholder variables and tell the user what still needs to be obtained.
To obtain a key and activate a domain, the user must contact the
SportAPI manager on Telegram. For local
development, tell the manager separately that the key must work on localhost.
Core rules
- The tracker works only for matches with live status.
- The tracker does not provide a sports line or a match list.
- A SportAPI sports-line subscription is required to obtain match data and the
zpfield. - The
gameidparameter always comes fromzp:gameid = zp. - If
zpis missing or equalsnull, the tracker is unavailable for that match. Do not create an empty widget. - Pass the correct sport ID in the
sportparameter. - Available sports and languages may be limited by the key’s plan.
- The key may be used in client-side code because it is protected by an allowlist of authorized domains.
- Do not add unsupported styling parameters or modify the tracker design. SportAPI provides custom visual changes as a separate service.
Demo
The tracker appearance can be viewed on the demonstration page.
The demonstration does not use real live data and does not replace testing the
integration with a live match whose zp value is not null.
Sport IDs
| ID | Sport |
|---|---|
| 1 | Football |
| 2 | Ice hockey |
| 3 | Basketball |
| 4 | Tennis |
| 5 | Baseball |
| 6 | Volleyball |
| 7 | Rugby |
| 8 | Handball |
| 10 | Table tennis |
| 13 | American football |
| 17 | Water polo |
| 21 | Darts |
| 26 | Formula 1 |
| 28 | Australian football |
| 44 | Horse racing |
| 66 | Cricket |
| 86 | CS:GO / esports |
Do not assume that an internal sport ID in the client project matches an ID in this table. If the project uses its own identifiers, create an explicit mapping.
Choose an integration method
Use a direct iframe when the page only needs to display one match and the
project does not require advanced widget control.
Use embed.js when the user switches matches on the same page or when the
project needs to control standard parameters through JavaScript.
Method 1. Direct iframe
Basic example:
<iframe
id="live-tracker"
src="https://bet-embed-sport-tracker.vercel.app/?key=pk_live_yourkey&gameid=745829876&sport=1&lang=en"
style="width: 100%; height: 360px; border: none; display: block;"
allowfullscreen
title="Live tracker"
></iframe>
Standard URL parameters:
key— client access key;gameid— value of thezpfield;sport— sport ID;lang— interface language;mobile=1— mobile layout;view=2dorview=3d— available display mode.
The simplest way to switch a match is to change gameid and sport in the
iframe element’s src attribute.
A match can also be changed without reloading the iframe by using
postMessage. Send the message only after the iframe has loaded or in response
to a user action:
const trackerFrame = document.querySelector('#live-tracker');
let trackerLoaded = false;
trackerFrame.addEventListener('load', () => {
trackerLoaded = true;
});
function switchMatch(gameid, sport) {
if (!trackerLoaded) return;
trackerFrame.contentWindow.postMessage(
{
type: 'CONFIG',
payload: { gameid, sport }
},
'https://bet-embed-sport-tracker.vercel.app'
);
}
Do not use '*' as targetOrigin.
Method 2. Integration with embed.js
Loader URL:
https://bet-embed-sport-tracker.vercel.app/embed.js
Basic example:
<div id="zone"></div>
<script src="https://bet-embed-sport-tracker.vercel.app/embed.js"></script>
<script>
let trackerReady = false;
window.addEventListener('message', (event) => {
if (event.origin !== 'https://bet-embed-sport-tracker.vercel.app') return;
if (event.data?.type === 'READY') {
trackerReady = true;
}
});
const zone = BetZoneEmbed.init({
container: '#zone',
key: 'pk_live_yourkey',
gameid: 745829876,
sport: 1,
lang: 'en',
height: 360
});
function switchMatch(gameid, sport) {
if (!trackerReady) return;
zone.update({ gameid, sport });
}
function switchLanguage(lang) {
if (!trackerReady) return;
zone.update({ lang });
}
</script>
Do not call zone.update() immediately after init(). The iframe may still be
loading, so the message would be lost. Call update() after receiving READY
or later in response to a user action.
Standard init() parameters:
| Parameter | Required | Type | Default | Purpose |
|---|---|---|---|---|
container | yes | string or Element | — | widget container |
key | yes | string | — | access key |
gameid | yes | number | — | value of the zp field |
sport | yes | number | — | sport ID |
lang | no | string | ru | interface language |
height | no | number | 360 | height in pixels |
mobile | no | boolean | false | mobile layout |
The update() method can change gameid, sport, lang, mobile, and view
without recreating the widget.
When the tracker component or block is removed from the page, call:
zone.destroy();
React, Vue, Svelte, and other SPAs
When integrating into an SPA:
- Load the external script after mounting the component or use the framework’s standard script-loading mechanism.
- Do not add the same
<script>on every render. - Do not access
windowor the DOM during server-side rendering. - Call
init()only after the container exists in the DOM andembed.jshas loaded. - Store the object returned by
init(). - When the match changes, call
update()only after the widget is ready. - On unmount, call
destroy()and remove the event listeners you created.
Use the project’s existing conventions for script loading, configuration storage, state handling, and responsive layout.
States and errors
Handle the following situations:
| Situation | Action |
|---|---|
| key is missing | do not start the widget; explain which key is required |
| current domain is unauthorized or key is disabled | show an access error and tell the user to contact SportAPI |
403 response | verify the key and domain binding |
| match is not live | do not display the tracker |
zp is missing or equals null | do not create the widget; show a fallback or hide the block |
| sport or language is not included in the plan | do not treat this as an integration error; explain the key limitation |
| user selects another match | call update() after the widget is ready |
| component is removed | call destroy() and remove event listeners |
Do not leave the page in an infinite loading state. Use the project’s existing loading, empty-state, and error components.
Responsive behavior
- The tracker width must be
100%of its container. - Recommended desktop height: 360–420 px.
- Recommended mobile height: 220–280 px.
- Use
mobile: trueormobile=1for the mobile layout. - Do not set a fixed pixel width.
Use the existing project’s breakpoints and design system.
Verify the result
After implementation, verify that:
- The widget loads on an authorized domain with a valid key.
- The widget is not created when
zp: null. - A non-live match does not display the tracker.
gameidreceives the value of thezpfield.- The sport code matches the table or an explicit project ID mapping.
update()is not called beforeREADY.- The match and language change without a full page reload.
- A direct iframe receives
CONFIGonly after loading. - Appropriate dimensions are used on mobile and desktop.
- Repeated mounting does not create duplicate scripts, iframes, or listeners.
destroy()is called when the component is removed.- Available tests, linting, type checks, and the project build pass.
If the integration cannot be fully tested because a key, authorized domain, or
live match with zp is unavailable, perform every available check and list what
the user must verify after obtaining access.
Report format
After completion, tell the user:
- which files were changed;
- which integration method was selected and why;
- where
gameidandsportcome from; - which error states were implemented;
- which checks were completed;
- which data or external checks are still required.
SportAPI support: @suport_sportapi.