To embed a sportsbook on your website, your server opens a player session with a secret API key, your page loads a small SDK with the launch URL that call returns, and you give each player free tokens to bet with. With The Sportsbook that's one API call and two lines of HTML, and the Free plan covers one sport, three leagues and 250 players a month. It's a play-for-fun sportsbook: players bet free tokens, never real money.
Key takeaways
- The whole integration is three moving parts: a server call (
POST /b2b/v1/sessions), two lines of HTML, and a way to credit free tokens. - Launch URLs are single use and expire after 60 seconds. Create one right before you render the page and never cache it.
- The player's identity is your own stable, pseudonymous
user_ref. Never an email, a real name or anything the browser sends you. height: "auto"makes the iframe follow its content, and the layout adapts to phones on its own.- The "Get more tokens" button fires a
tokens-requestedevent. Point it at a free refill, never a price.
On this page10 sections
- What you need to embed a sportsbook on your website
- Step 1: create your sportsbook and API key
- Step 2: pick sports and leagues
- Step 3: open a player session on your server
- Step 4: add two lines of HTML
- Step 5: give players free tokens
- Step 6: brand it
- Test on phones
- Common mistakes
- Frequently asked questions
What you need to embed a sportsbook on your website
Three things, and most sites already have two of them.
Players who log in to your site. The embedded sportsbook has no sign-up screen of its own. It trusts your server to say who the player is. If your site has no accounts yet, add login first: every bet and balance hangs off a stable player id.
A server you control. Anything that can make an HTTPS POST with a secret header works: Node, PHP, Python, Go, a serverless function. The API key never leaves that server.
About ten minutes for a first bet. Plan an afternoon if you also want a token policy, a refill flow and your colors in place before launch.
Step 1: create your sportsbook and API key
Go to the Free sign-up (opens in a new tab) and register with an email and password, or with Google. You confirm that you're 18 or older and acting for a business, and you accept the Terms, the Play-for-Fun Policy and the Data Processing Addendum. If you used email, type the 6-digit code we send you.
Then name the sportsbook (players see the name) and pick its primary sport. Two optional fields are worth filling in now:
- The website where you'll embed it. The console adds that origin to your allowed origins for you.
- The token label players see next to amounts: a word such as
TOKENS,COINSor your community's own term. Currency symbols and codes like$,€orUSDaren't allowed as labels.
The sportsbook starts on Free straight away. Nobody has to approve it.
The confirmation screen shows your first API key once. It looks like sbk_<prefix>_<secret>. Copy it into an environment variable or your secret manager, such as SPORTSBOOK_API_KEY, and nowhere else. We only store a hash, so if you lose it you create a new one in Integration → API keys and revoke the old one; a revoked key stops working on the next request. The Free plan has one API key; paid plans have as many as you want, which makes rotation easier. The getting started section of the docs (opens in a new tab) walks through the same screens.
Step 2: pick sports and leagues
Your primary sport is already on. Now choose leagues in the console. There's a catalog of more than a thousand leagues, and you add them one by one; there is deliberately no "select all" switch. A league you add starts showing its matches within about two minutes.
What you can turn on depends on the plan (prices at the time of writing, September 2026; see pricing for current figures):
| Free | Custom | Full | |
|---|---|---|---|
| Sports | 1 | 1 in the base, more at $25/month each | all 11 |
| Leagues | up to 3 | 5 per sport, plus packs of 5 | unlimited, picked one by one |
| Pre-match betting | yes | yes | yes |
| Live betting | no | add-on | yes |
| Monthly active players | up to 250 | up to 5,000 | no cap (fair use) |
| Price | $0 | from $49/month ($39 billed yearly) | $490/month ($399 billed yearly) |
On Free, choose the three leagues your audience actually argues about. You can also hide individual markets per sport under Markets, on every plan, if some bet types don't suit your community.
Step 3: open a player session on your server
When a logged-in player opens the page that holds the sportsbook, your server calls the sessions endpoint:
curl -X POST https://api.thesportsbook.app/b2b/v1/sessions \ -H "Authorization: Bearer $SPORTSBOOK_API_KEY" \ -H "Content-Type: application/json" \ -d '{"user_ref": "viewer-42", "display_name": "Viewer 42", "locale": "en"}'The response:
{ "launch_token": "eyJhbGciOi...", "launch_url": "https://play.thesportsbook.app/embed?token=eyJhbGciOi...", "expires_in": 60}The three fields you send:
| Field | Required | Rules |
|---|---|---|
user_ref | yes | Your own stable id for the player, 1 to 128 characters. The player is created on first use and reused afterwards. |
display_name | no | A nickname shown in the sportsbook and your console. |
locale | no | en or es (or a tag such as en-US). Defaults to your sportsbook's language. |
user_ref deserves care, because it's the only thing that ties bets and balances to a person:
- Use a stable internal id, such as
user-1834from your accounts table. A display name changes; if you use it asuser_ref, a rename creates a new player with an empty history. - Keep it pseudonymous. Our Play-for-Fun Policy (AUP 9.1) forbids emails, phone numbers and legal names in any field,
display_nameincluded. A nickname the player chose is fine. - Take it from your server-side session, never from a query string, a form field or a header the browser can set. Otherwise anyone can play as anyone.
The launch token inside launch_url is single use and expires after 60 seconds. The embed exchanges it for a player session that lasts 12 hours and strips it from the URL. If you've blocked a player in the console, this call returns 403 with USER_BLOCKED, and you can show your own message instead of the sportsbook.
In practice you wrap this call in a route of your own, for example POST /api/sportsbook/session, that reads the logged-in user from your session cookie and returns { launch_url }. The snippets below assume that route exists; it's your code, and it's short in any stack. The WordPress version shows one written in PHP.
Step 4: add two lines of HTML
Put the launch URL your server just created into this markup:
<div data-thesportsbook data-launch-url="LAUNCH_URL_FROM_YOUR_SERVER"></div><script src="https://play.thesportsbook.app/sdk.js"></script>That's the whole embed. The SDK finds every element with data-thesportsbook when the page loads, creates the iframe inside it and sizes it to its content. You can render the URL straight into the HTML on the server, which is the simplest option, or fetch it from your route and fill the attribute before the script runs.
When you want to react to what happens inside the sportsbook, mount it in JavaScript instead:
<div id="sportsbook"></div><script src="https://play.thesportsbook.app/sdk.js"></script><script> const sportsbook = TheSportsbook.init({ container: "#sportsbook", launchUrl: "LAUNCH_URL_FROM_YOUR_SERVER", height: "auto", onBetPlaced(bet) { refreshBalance(); }, onTokensRequested() { openFreeRefill(); }, async onSessionExpired(e) { if (e.reason === "user_blocked") return; const { launch_url } = await fetch("/api/sportsbook/session", { method: "POST" }).then((r) => r.json()); sportsbook.updateToken(launch_url); }, });</script>refreshBalance, openFreeRefill and the /api/sportsbook/session route are your own code. The session handler matters more than it looks: after 12 hours the session ends, and updateToken() swaps in a fresh one without reloading the iframe, so a player who left the tab open all day keeps their place. A user_blocked reason means you blocked them; don't retry.
If your site is a React or Next.js app, the React and Next.js embed guide wraps this in a component with cleanup and session renewal. If you'd rather skip the SDK and use a plain <iframe> with your own postMessage listener, that works too. The sportsbook iframe integration guide covers the raw iframe, the ten events, origin checks and resizing by hand.
Step 5: give players free tokens
A player with no tokens can browse odds but can't bet. Every plan includes the managed mode, the Hosted Token Balance: we keep each player's token balance as a record, and you add tokens through the API.
The credit call is POST /b2b/v1/users/{user_ref}/credit with an amount, an idempotency_key and an optional reason that shows in the player's history in your console. Three details make it pleasant to build on:
- It creates the player if they don't exist yet, so you can load a starting balance before their first session.
- Idempotency is built in. Send the same
idempotency_keyagain (after a timeout, say) and you get the original result back with"replayed": true; tokens never move twice. Derive the key from the thing you're granting, likestart-user-1834orrefill-user-1834-2026-09-28, and a double click or a retry can't double a refill. - Bets and settlement update the balance automatically. You never debit stakes or credit returns yourself.
A simple policy that works for most communities: an equal starting balance for everyone, plus a free daily refill. You can add tokens for taking part (watch time, chat activity, attending an event) as long as the rate is the same for everyone.
Inside the sportsbook, players see a Get more tokens button. Pressing it fires the tokens-requested event, which the SDK passes to onTokensRequested. Open your free refill there: a page or modal that explains how to get more tokens and, if they're eligible, credits them from your server. Two rules from the Play-for-Fun Policy apply to whatever that button opens: it can't sell tokens, show a price or lead anywhere tokens can be bought (AUP 3.4), and every player must always have a free way to get enough tokens to keep playing (AUP 3.5).
Don't grant tokens from the browser event itself. Events are informational; the source of truth is the API. Your refill page calls your server, your server decides and credits.
If you'd rather keep balances in your own system, the seamless mode (Operator-Held Token Balance) calls your wallet endpoint for every movement. It's a Custom add-on or included in Full, and because your wallet URL and signing secret are set on our side, you contact us to switch it on. For starting balances, refill sizes, seasons and what's off-limits, read the free token economy guide.
Step 6: brand it
Open the Studio in the console. On every plan you can:
- start from one of six presets (Light neutral, Dark neutral, Midnight blue, Forest, Crimson, Mono) and change every color;
- upload or link your logo and favicon, and set the corner radius;
- choose navigation as a sidebar or a top bar, match cards as a list or a grid, and a floating or docked betslip.
Paid plans add fonts (18 Google Fonts or your own uploaded files), a separate heading font, density and the style of odds buttons. The Studio checks text and odds colors against WCAG AA before you save, and saved changes reach open sportsbooks within seconds, so you don't need to redeploy anything. On Free, a small "Powered by" badge stays visible.
To try looks before you sign up, open the live sportsbook demo (opens in a new tab): it's the real embed with demo tokens, and you can switch colors, layout and betslip position in place.
Test on phones
The layout follows the width of the iframe, not the window. On a narrow container the sidebar becomes a drawer and the betslip becomes a bottom sheet. That has two consequences:
- Give the container the full content width. A sportsbook squeezed into a 600-pixel column on desktop will look like the phone layout. Use a full-width page or section.
- Let the height be automatic. With
height: "auto"the iframe grows with its content and your page does the scrolling. The SDK also tells the sportsbook which part of the iframe is on screen, so the betslip and notifications stay visible even when the iframe is taller than the viewport. Avoid wrapping it in a fixed-height box withoverflow: hidden; that's the usual cause of a betslip nobody can reach.
Walk through a whole bet on a real device: build a two-leg accumulator, place it, and check that your onBetPlaced handler refreshed any balance you show outside the iframe.
Common mistakes
These come up in almost every first integration.
| Mistake | What happens | Fix |
|---|---|---|
| Caching the page or the launch URL (page cache, CDN, static build) | The second visitor gets a token that was already used, and the sportsbook asks for a new session | Create the session on every render; exclude the sportsbook page from page and edge caches |
| API key in browser JavaScript or a mobile app | Anyone can open sessions for any player | Keep it server-side only; if it leaked, create a new key and revoke the old one |
user_ref taken from the browser | Players can impersonate each other | Read the player from your server-side session |
Display name or email as user_ref | Renames split histories; emails break AUP 9.1 | Use a stable internal id; send a nickname as display_name |
New idempotency_key on every retry | A timeout plus a retry credits tokens twice | Derive the key from the grant and reuse it |
Granting tokens on bet-placed or tokens-requested in the browser | Tokens move on events anyone can fake | Let your server decide and call the credit API |
Handling both tokens-requested and the old deposit-requested | Your handler runs twice | Handle tokens-requested only |
| Site not in Settings → Allowed origins | Browser API access from that site isn't allowed | List every exact origin, including www and staging |
Before you go live, run through the short version of the security checklist:
- The API key lives in an environment variable or secret manager, one key per environment.
- Sessions are created by your server for the player who is logged in. Never accept a
user_reffrom the browser. - Launch tokens are created right before rendering and never logged, cached or reused.
- Every site that embeds the sportsbook is listed in allowed origins, as exact origins with no paths or wildcards.
- You never move tokens because of a
postMessageevent.
The full list, including the seamless wallet items, is in the docs security checklist (opens in a new tab). If your site runs on WordPress, the WordPress guide turns all of the above into a shortcode, and the embeddable sportsbook guide covers everything around it: live betting, settlement, branding, costs and how to choose a provider.
Frequently asked questions
How do I add a sportsbook to my website?
Sign up for an API key, have your server call POST /b2b/v1/sessions for the logged-in player, and paste two lines of HTML with the launch URL it returns. The sportsbook loads in an iframe that sizes itself. Then give players free tokens through the credit API so they have something to bet with.
Can I embed a sportsbook on a site builder like Wix or Webflow?
The two lines of HTML go into any custom-code block. The session call needs a server, because it uses your secret API key. If your builder can't run server code, host that one small function somewhere else and call it from the page. Never put the API key in page code.
Is it free to embed a sportsbook?
Yes, on the Free plan: one sport, up to three leagues, pre-match betting and up to 250 players a month, with a 'Powered by' badge. There's no time limit today. Paid plans add sports, live betting and more players; see the pricing page for current prices.
Do I need a license to embed a play-for-fun sportsbook?
We can't answer that for your situation. The Sportsbook is play-for-fun by design: no money in, no money out, and players are 18+. You're responsible for running your community and its tokens lawfully wherever your players are, so check the rules there with a lawyer in your jurisdiction.
Does the embedded sportsbook work on phones?
Yes. The layout follows the width of the iframe, so on a phone the sidebar turns into a drawer and the betslip into a bottom sheet. With the SDK's auto height, the iframe grows with its content and your page scrolls normally.
Written by
The Sportsbook team
The people who build The Sportsbook. We have spent seven years building sportsbook software, and we write these guides from that work.
Last updated .