StatsHub is an "out-of-the-box," fully hosted fan-engagement solution that provides real-time live
scores and deep sports statistical analysis. Because Sportradar hosts, develops, and maintains all of the
backend infrastructure and data pipelines, there is no technical overhead or maintenance required on
your side. The solution is delivered as a hosted application URL.
This guide outlines how to integrate StatsHub seamlessly into your sports betting or media website
using an HTML <iframe>.
Your customized StatsHub application is accessible via a unique URL configured by the Sportradar integration team. The standard URL format is:
Example Baseline URL: https://statshub.sportradar.com/sportradar/en
To display the StatsHub module directly within your container page, place the following <iframe> block inside your HTML:
<div class="statshub-container">
<iframe
id="statsIframe"
src="https://statshub.sportradar.com/{your_alias}/{language}/sport/1"
scrolling="yes"
style="width: 100%; border: none;">
</iframe>
</div>StatsHub is fully responsive and auto-adapts dynamically to any parent container width. For a responsive, scroll-friendly integration across desktop and mobile browsers, use the following CSS structure:
/* Container sizing */
.statshub-container {
width: 100%;
overflow: hidden;
}
/* Iframe layout optimization */
#statsIframe {
width: 100%;
border: none;
height: 100%;
}Scrolling: The scrolling="yes" attribute must be enabled.
Sportradar enforces strict security and frame-ancestor constraints on the StatsHub platform.
The Rule: If your web application loads StatsHub inside an <iframe>, the parent page's top-level domain must be whitelisted within our platform.
If no domains are explicitly configured, the application will fail to render, and browsers will block the frame due to Content Security Policy frame-ancestors violations. Contact the client setup team to configure the domains.
If you encounter a blank screen or connection errors in your browser console (e.g., “Refused to connect to statshub.sportradar.com” or “Firefox can’t open this page”), please verify your domain configuration.
If the issue persists, copy the error from your browser's developer console and send it to our support team.
Please note that StatsHub operates as a secure, independent hosted system. Interactive buttons inside the application framework (such as favourite pinning or bookmarking) execute within the StatsHub application context and does not trigger custom window.postMessage events back to your parent application
Integrating StatsHub inside a modal window (also referred to as a lightbox or pop-up overlay) is the preferred implementation for sportsbooks and media portals that want to keep users on their active match list or betting sheet while offering immediate, deep statistical analysis.
This integration uses a lightweight trigger button on your parent page that dynamically injects the appropriate StatsHub deep-link into a hidden overlay containing an <iframe>.
Following Sportradar's standard design standards:
Add the hidden modal container directly before the closing tag of your main page. This structure isolates the modal backdrop, the close button, and the iframe wrapper:
<!-- Trigger Button Example (e.g., in your Match List) -->
<button class="stats-trigger-btn" data-match-id="61513882" onclick="openStatsModal(this)">
View Stats
</button>
<!-- StatsHub Modal Window Container -->
<div id="statsHubModal" class="statshub-modal-overlay" aria-hidden="true" style=
To prevent visual bugs, such as double scrollbars on mobile or layout cut-offs, use this unified CSS stylesheet. It enforces full-screen rendering on mobile and applies a standard light-box constraint on desktop screens.
/* Modal backdrop/overlay */
.statshub-modal-overlay {
position: fixed;
top: 0;
left: 0;
width:
This script dynamically generates the secure StatsHub deep-link when a match is selected, populates the iframe, handles the backdrop display, and freezes the parent page's scrolling behavior to prevent "double scrollbar" bugs on mobile:
const CLIENT_ALIAS = 'your_alias'; // Replace with your Sportradar alias
const LANGUAGE = 'en'; // Set dynamic display language
function openStatsModal(buttonElement) {
Mobile web browsers (especially Safari on iOS) handle 100vh poorly due to collapsing address bars, which historically causes double-scrollbars inside modals. Enforcing height: 100dvh on your wrapper ensures that the modal occupies the exact dynamic viewport size.
A full integration example
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>StatsHub iFrame Integration</title>
<style>
*,
*::before,
*::after {
}
box-sizing: border-box;
html,
body {
height: 100%;
}
body {
margin: 0;
display: flex;
flex-direction: column;
height: 100vh;
height: 100dvh;
}
font-family:
system-ui,
-apple-system,
sans-serif;
background: #0f0f0f;
color: #e5e5e5;
/* Example parent header — replace `.topbar` selector in JS if yours differs */
.topbar {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0 1.25rem;
height: 60px;
background: #1a1a1a;
border-bottom: 1px solid #2a2a2a;
}
transition:
height 0.2s ease,
padding 0.2s ease;
.topbar--tall {
height: 120px;
flex-wrap: wrap;
align-content: center;
}
padding: 1rem 1.25rem;
.header-size-toggle {
display: inline-flex;
align-items: center;
}
gap: 0.5rem;
font-size: 0.875rem;
cursor: pointer;
user-select: none;
.topbar h1 {
margin: 0;
}
font-size: 1.125rem;
font-weight: 600;
.topbar-actions {
}
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
.stats-trigger-btn {
padding: 0.5rem 0.875rem;
border: 1px solid #3a3a3a;
border-radius: 6px;
background: #252525;
color: #fff;
font-size: 0.875rem;
cursor: pointer;
}
transition: background 0.2s ease;
.stats-trigger-btn:hover {
background: #333;
}
.statshub-container {
flex: 1;
min-height: 0;
width: 100%;
overflow: hidden;
}
#statsIframe {
width: 100%;
height: 100%;
border: none;
display: block;
}
/* Modal backdrop/overlay */
.statshub-modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.75);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
backdrop-filter: blur(4px);
/* Modal box wrapper */
.statshub-modal-wrapper {
position: relative;
background-color: #1a1a1a;
width: 85%;
height: 85%;
border-radius: 8px;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
overflow: hidden;
display: flex;
flex-direction: column;
}
/* Iframe container */
.statshub-iframe-container {
}
width: 100%;
flex-grow: 1;
height: 100%;
/* Float Close Button on top-right */
.statshub-close-btn {
position: absolute;
top: 15px;
right: 20px;
background: rgba(0, 0, 0, 0.5);
border: none;
color: #ffffff;
font-size: 30px;
font-weight: bold;
cursor: pointer;
z-index: 10001;
width: 40px;
height: 40px;
}
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s ease;
.statshub-close-btn:hover {
background: rgba(255, 255, 255, 0.2);
}
/* Mobile Responsiveness Breakpoint: Full screen overlay */
@media (max-width: 767px) {
.statshub-modal-wrapper {
}
width: 100% !important;
height: 100% !important;
height: 100dvh !important;
border-radius: 0;
padding: 0 !important;
.statshub-close-btn {
top: 10px;
right: 10px;
width: 35px;
height: 35px;
}
font-size: 24px;
}
</style>
</head>
<body>
<header class="topbar">
<h1>StatsHub Integration Demo</h1>
<div class="topbar-actions">
<label class="header-size-toggle">
<input
type="checkbox"
id="tallHeaderToggle"
onchange="toggleHeaderSize(this)"
/>
(Match Tall header
</label>
<button
class="stats-trigger-btn"
data-match-id="61513882"
onclick="openStatsModal(this)"
>
View Stats ID:61513882)
</button>
</div>
</header>
<div class="statshub-container">
<!-- Replace sportradar with your client alias -->
<iframe
id="statsIframe"
src="https://statshub.sportradar.com/sportradar/en/sport/1"
scrolling="yes"
></iframe>
</div>
<!-- StatsHub Modal Window Container -->
<div
id="statsHubModal"
class="statshub-modal-overlay"
aria-hidden="true"
style="display: none"
>
<div class="statshub-modal-wrapper">
<button
class="statshub-close-btn"
onclick="closeStatsModal()"
aria-label="Close Statistics"
>
×
</button>
<div class="statshub-iframe-container">
<iframe
id="modalIframe"
src="about:blank"
scrolling="yes"
frameborder="0"
style="width: 100%; height: 100%; border: none"
></iframe>
</div>
</div>
</div>
<script>
const statsIframe = document.getElementById("statsIframe");
const { origin: statsHubOrigin, pathname } = new URL(statsIframe.src);
const [, clientAlias, language] = pathname.split("/");
function toggleHeaderSize(checkbox) {
document
.querySelector(".topbar")
.classList.toggle("topbar--tall", checkbox.checked);
}
function openStatsModal(buttonElement) {
const matchId = buttonElement.getAttribute("data-match-id");
if (!matchId) {
console.error("Match ID is missing from trigger button");
return;
}
const modal = document.getElementById("statsHubModal");
const iframe = document.getElementById("modalIframe");
// 1. Dynamically construct the StatsHub Deep-Link URL (no 'm' prefix required)
const statsHubUrl = `${statsHubOrigin}/${clientAlias}/${language}/match/${matchId}`;
// 2. Inject URL and display modal
iframe.src = statsHubUrl;
modal.style.display = "flex";
modal.setAttribute("aria-hidden", "false");
// 3. Prevent parent background body scrolling while modal is open
}
document.body.style.overflow = "hidden";
function closeStatsModal() {
const modal = document.getElementById("statsHubModal");
const iframe = document.getElementById("modalIframe");
// 1. Hide modal container
modal.style.display = "none";
modal.setAttribute("aria-hidden", "true");
// 2. Reset iframe destination immediately to stop streams and clear memory
iframe.src = "about:blank";
// 3. Restore parent body scrolling
}
document.body.style.overflow = "";
// Close modal if user clicks on the darkened backdrop outside the wrapper
window.addEventListener("click", function (event) {
const modal = document.getElementById("statsHubModal");
if (event.target === modal) {
closeStatsModal();
}
});
</script>
</body>
</html>