Immersive Betting is a live, in-play micro-betting experience for tennis, delivered through the immersiveBetting widget. It brings together a
live scoreboard, betting panel, bet history, and an embedded LMT Plus court visualization or AV stream.
Markets, odds, bet placement, settlement, and bet history are handled by the ATP backend, while odds and market state are sourced from UOF. * Limits* are configured on the ATP backend. The wallet remains with the bookmaker.
Integration consists of two parts: embed the widget and supply a punter sessionToken.
Integration consists of two parts:
immersiveBetting with matchId, sportId, and target environment.sessionToken so the widget can load the punter profile, place bets, stream bet updates, and show
bet history.These two workstreams can run in parallel. A typical end-to-end integration takes 1–3 weeks, depending on whether session/auth already exists and whether optional features (AV stream, theming) are in scope — see Typical Timeline.
Before a punter can place a bet, the widget must be mounted on the client's page with a valid matchId. Sportradar supplies markets, odds, live match
data, court visualization, bet placement, and settlement through the widget and ATP backend.
Do not mount a separate match.lmtPlus for the same match. The widget embeds LMT Plus internally for the court view. Only one immersiveBetting
instance per match per page is recommended.
SIR('addWidget', '#sr-widget', 'immersiveBetting', {
matchId: 12345678,
sportId: 5,
environment: 'prod',
});| Parameter | Required | Description |
|---|---|---|
| Widget name | Yes | immersiveBetting |
matchId | Yes | Match id. Obtain via Sports API, Coverage Feed, UOF, or Mapping Feed. |
sportId | Yes | 5 for tennis |
environment | Yes | stage or prod for client integrations. Additional non-production values (demo, dev1–dev3) are used during Sportradar-led onboarding only. |
SIR('updateWidget', '#sr-widget', { matchId: 87654321 });
SIR('removeWidget', '#sr-widget');Changing environment after mount is not supported.
| Area | Description |
|---|---|
| Scoreboard | Player names, sets/games/points, serve indicator |
| Betting panel | Market, stake control, bet confirmation, users' betting statistics |
| Court visualization | Embedded match.lmtPlus (rear court view, momentum/tabs disabled) |
| AV visualization | Alternative to the court visualization; embedded match.lmtPlus |
| Bet history | Per-set timeline of bets placed by authorized users over the last 24 hours |
| Settlement | Win/loss/cancel notifications synced with live rally state |
| Match overlays | Set break, tiebreak, match ended, unauthorized state |
Court surface theme (hard, clay, grass) is resolved automatically from tournament data.
| Item | Value |
|---|---|
| Primary market | Next Point (point winner) |
| Market id | 218 |
| Odds and market state | UOF, streamed to the widget via the ATP backend (NATS + REST) |
| Betting window | Market must be open in UOF (outcomes available); the widget also suspends the UI during an active rally |
| Settlement | ATP backend: results are pushed directly to the widget. |
When a UOF market is open and outcomes are streamed, the widget enables acceptance. When the market is suspended or disabled, placement is blocked regardless of punter session state. See UOF for details.
ATP Immersive Betting integrates exclusively with Sportradar's Unified Odds Feed (UOF). UOF is the single supported source for betting markets, outcomes, odds, and market availability. It provides real-time odds updates through XML messages and exposes additional market metadata through its API.
For the current Next Point market (marketId: 218), the ATP backend consumes the relevant UOF data and makes it available to the widget. The
widget does not connect directly to third-party odds providers and does not support alternative odds feeds or client-side odds adapters.
The widget enables betting only when:
Third-party data providers are out of scope for this integration. Supporting another odds provider would require a separate integration and is not covered by the ATP Immersive Betting product. All market definitions, odds updates, availability states, and related mappings must therefore follow the UOF model and lifecycle.
Sportradar configures ATP backend connectivity and per-client identifiers (customerId, API/WSS URLs) in the widgets license during onboarding.
Additional behaviour can be passed under sportProps (tennis only today):
SIR('addWidget', '#sr-widget', 'immersiveBetting', {
matchId: 12345678,
sportId: 5,
environment: 'prod',
sportProps: {
withPlayerInfo: true,
withMatches: true,
withBetSizeOptions: false,
stakeControlView: 'standard',
avStreamJwtToken: 'JWT',
},
});| Prop | Default | Description |
|---|---|---|
withPlayerInfo | false | Player labels on court; highlight the player linked to the active bet |
withMatches | false | Live match switcher when the current match ends; fires onMatchChange |
withBetSizeOptions | false | Preset stake amount chips |
stakeControlView | standard | Stake control layout: standard or compact |
avStreamJwtToken | — | JWT for live video inside the embedded court visualization |
When the punter places a bet, the widget submits the ticket to the ATP backend using the supplied sessionToken. The token identifies the punter
session for profile loading, bet placement, WebSocket bet updates, and bet history.
Two integration approaches are available:
sessionToken when mounting the widget.onSignIn callback and updateWidget after login.The client passes sessionToken at mount. The widget loads the punter profile (limits from the ATP backend, currency) and
enables bet placement when the market is open and rally is active.
Use when the immersive betting page is behind login or the client already has an ATP session before the widget loads.
SIR('addWidget', '#sr-widget', 'immersiveBetting', {
matchId: 12345678,
sportId: 5,
environment: 'prod',
sessionToken: 'ATP_SESSION_TOKEN',
});On token refresh or logout, update the widget:
SIR('updateWidget', '#sr-widget', { sessionToken: 'NEW_ATP_SESSION_TOKEN' });
// To log out:
SIR('updateWidget', '#sr-widget', { sessionToken: undefined });The widget mounts without sessionToken. Match and market data still load; the betting panel shows an unauthorized state. The client handles login
through the onSignIn callback and passes the token once available.
Use when the client wants to show the live experience before login or authentication completes asynchronously after the page loads.
SIR('addWidget', '#sr-widget', 'immersiveBetting', {
matchId: 12345678,
sportId: 5,
environment: 'prod',
onSignIn: function () {
// Open client login; after success, call updateWidget with sessionToken
},
});// After successful login
SIR('updateWidget', '#sr-widget', { sessionToken: 'ATP_SESSION_TOKEN' });The full bet acceptance flow runs inside the widget:
Responsibility is split across UOF, the ATP backend, and the bookmaker:
| Concern | Owner | In the widget |
|---|---|---|
| Odds and market state | UOF (via ATP backend) | Odds and whether a market is open or suspended come from UOF, streamed to the widget through the ATP backend. |
| Wallet | Bookmaker | Balance is owned and funded by the bookmaker. The widget displays balance from the punter profile API. Errors such as insufficient funds come back from placement via the ATP backend. |
| Limits | ATP backend | Min/max stake, max win, max odds, and preset amounts are configured on the ATP backend and returned with the punter profile. |
| Placement | ATP backend + bookmaker | When the UOF market is open, the widget submits to the ATP backend, which accepts or rejects with the bookmaker. Widget-side rules (e.g. no bets during an active rally, current-point market only) apply on top of market availability. |
| Settlement | ATP backend | Results are pushed to the widget over WebSocket; no client resulting feed. |
| Callback | When fired |
|---|---|
onSignIn | User should log in (no valid sessionToken, or user taps sign-in in the unauthorized panel) |
onClose | User closed the widget (header close action) |
onMatchChange | User switched to another live match (sportProps.withMatches: true) |
SIR('addWidget', '#sr-widget', 'immersiveBetting', {
matchId: 12345678,
sportId: 5,
environment: 'prod',
sessionToken: 'ATP_SESSION_TOKEN',
onClose: () => {
/* navigate away or hide container */
},
onMatchChange: (matchId) => {
/* update page URL/state */
},
});| Pre-authenticated session | Sign-in on demand | |
|---|---|---|
sessionToken at mount | Required | Omitted |
| Betting before login | No | No — markets visible, placement disabled |
| Client's main deliverable | Issue ATP sessionToken before page load | onSignIn handler + updateWidget after login |
| Token refresh | updateWidget with new token | Same |
| Typical effort | ~3–5 days | ~5–7 days |
| Identifier | Role |
|---|---|
clientId | Widgetloader URL path — licensed widgets client |
matchId | Target tennis match |
sportId | 5 (tennis) |
sessionToken | ATP punter session — issued by the client via ATP auth APIs |
Nomenclature note: widget tournamentId / uniqueTournamentId (on other widgets) map to simpleTournamentId / tournamentId in Sports API
responses. immersiveBetting only requires matchId at mount.
Match ids can be resolved from Sports API, Coverage Feed, UOF, or Mapping Feed depending on the integration scenario.
| Step | Description | Estimate |
|---|---|---|
| Kick-off | Shared channel; client id, environment, ATP session contract | < 1 week |
| Widget embed | Widgetloader, immersiveBetting mount, matchId wiring, QA | ~2–3 days |
| Session integration | ATP sessionToken issuance and updateWidget lifecycle | Pre-auth: ~3–5 days · On-demand: ~5–7 days |
| Optional AV stream | avStreamJwtToken issuance and QA | ~3–5 days |
| Theming | Client theme CSS | ~2–3 days |
Embed and session work can largely run in parallel. End-to-end integrations typically require 1–3 weeks when session/auth already exists. Greenfield ATP auth adds time depending on the client's identity stack.
clientId with immersiveBetting enabledmatchId for the target tennis matchsessionToken for logged-in punters (coordinate with ATP onboarding — not the widgets team alone)onSignIn and post-login updateWidgetavStreamJwtToken generationReplace YOUR_CLIENT_ID with your licensed widgets client id:
<script>
var clientId = 'YOUR_CLIENT_ID';
(function (a, b, c, d, e, f, g, h, i) {
a[e] ||
((i = a[e] =
function () {
(a[e].q = a[e].q || []).push(arguments);
}),
(i.l = 1 * new Date()),
(i.o = f),
(g = b.createElement(c)),
(h = b.getElementsByTagName(c)[0]),
(g.async = 1),
(g.src = d),
g.setAttribute('n', e),
h.parentNode.insertBefore(g, h));
})(window, document, 'script', 'https://widgets.sir.sportradar.com/' + clientId + '/widgetloader', 'SIR', { language: 'en' });
</script>