Competition Statistics
A competition's season on one page — a progress header, upcoming fixtures and results, player rankings, and season-wide statistics. Fixtures sit in Upcoming / Results tabs with a round picker, grouped by day and, in a multi-stage competition, by stage. Each match row expands: a finished or live match shows its match stats and a goal timeline, an upcoming one both teams' form, a season comparison and the previous meeting.
No authentication required — this widget never needstokenString,tokenCookieName, orfirebasein your config. See Getting Started → Authentication → Read-only widgets.
<div data-component="fu-widget" data-content-type="competition-statistics" data-content-id="fb:c:3"></div>Configuration Attributes
| Attribute | Description | Options/Format | Default |
|---|---|---|---|
data-content-id | Competition ID | e.g. "fb:c:3" | Required |
data-competition-statistics-season-id | Season override | e.g. "fb:c:3:2026/27" | The competition's current season |
data-competition-statistics-stage-id | Scope matches and team statistics to one stage | Stage ID string | Every stage |
data-competition-statistics-sections | Comma-separated sections to render, in the order given (see Sections below) | Any of header, matches, players, season | All four, in that order |
data-competition-statistics-player-rankings-layout | How the player rankings are laid out. "auto" switches to tabs in a container narrower than 600px | "auto", "grid", "tabs" | "auto" |
data-competition-statistics-player-rankings-rows | Rows per ranking before Show all | Integer, clamped to 1–10 | 5 |
data-competition-statistics-live-refresh | Poll live matches, so score and minute stay current | "true", "false" | true |
data-competition-statistics-refresh-interval | Live-refresh poll interval in milliseconds | Positive integer | 30000 (30s) |
data-competition-statistics-labels | JSON object overriding any user-facing string. Keep {{…}} placeholders | CompetitionStatisticsLabels, e.g. '{"upcoming":"Fixtures"}' | Locale strings |
Odds attributes (see Betting Odds below):
| Attribute | Description | Options/Format | Default |
|---|---|---|---|
data-competition-statistics-show-odds | Show 1X2 odds on upcoming and live match rows | "true", "false" | false |
data-competition-statistics-odds-mode | "flash" alternates the operator logo and the prices instead of showing both | "default", "flash" | "default" |
data-competition-statistics-odds-flash-interval | Flash interval in milliseconds. Ignored unless the mode is "flash" | Positive integer | 3000 |
data-competition-statistics-odds-polling-interval | Odds poll interval in milliseconds | Positive integer | 30000 |
data-competition-statistics-odds-operators | Comma-separated operator config ids, in preference order — a row shows one operator, the first with a complete market | e.g. "betano-bg,efbet-bg" | First operator with prices |
data-competition-statistics-odds-affiliate-id | Affiliate id substituted into every operator URL carrying an {affiliate_id} placeholder | Affiliate id string | None |
data-competition-statistics-odds-affiliate-ids | JSON object of per-operator affiliate ids. Wins over data-competition-statistics-odds-affiliate-id | e.g. '{"betano-bg":"aff-123"}' | None |
data-competition-statistics-add-to-betslip | Push a clicked odds price into the Betslip widget on the page | "true", "false" | false |
Per-element attributes override the global competitionStatistics config field by field, including inside its nested objects (odds and its affiliateIds, the three CTAs, labels) — setting data-competition-statistics-odds-operators keeps a globally configured odds.affiliateId.
Sections
| Section | Content |
|---|---|
"header" | The competition, its season and a progress bar of matches played |
"matches" | Upcoming / Results tabs with stage pills and a round picker; expandable rows with live scores, match detail and odds |
"players" | Player rankings — top scorers, assists, goals + assists, clean sheets, minutes, cards |
"season" | Result split, goal timing, goal lines, averages per match, cards, team callouts and record matches |
data-competition-statistics-sections both picks and orders them, so "season,players" puts the season statistics first and leaves the fixtures out. Unknown entries are ignored with a console warning.
In a competition with more than one stage (regular season, championship / relegation groups, play-offs), stage pills sit above the round picker and the rounds are the selected stage's own. The Upcoming tab opens on the stage of the next match, Results on the stage of the latest one. Postponed, cancelled, interrupted and abandoned matches are listed with the results, the reason shown in place of the score.
Link CTAs
Three kinds of card link out through a CTA you configure. No URLs are baked in: without a CTA, the card is inert.
| Card | Attribute prefix | Config field | URL placeholder |
|---|---|---|---|
| The two record-match cards | data-competition-statistics-match-cta | matchCTA | {matchId} (or {id}) |
| The team callouts | data-competition-statistics-team-cta | teamCTA | {competitorId} (or {id}) |
| A player in the rankings | data-competition-statistics-player-cta | playerCTA | {athleteId} (or {id}) |
Each prefix takes three suffixes:
| Suffix | Description | Options/Format |
|---|---|---|
-url | URL template; the placeholder is replaced with the URL-encoded id | URL string |
-target | Link target | "_blank", "_self" |
-onclick | Inline JavaScript run on click. Navigation is prevented so your router handles it | JavaScript code string |
<div
data-component="fu-widget"
data-content-type="competition-statistics"
data-content-id="fb:c:3"
data-competition-statistics-team-cta-url="/football/team/{competitorId}"
data-competition-statistics-player-cta-url="/football/player/{athleteId}"
data-competition-statistics-player-cta-target="_blank"
></div>In FuWidget.init(), a CTA's onClick receives the clicked id — teamCTA: { onClick: (competitorId) => router.push(...) }.
-onclickis evaluated as code, likedata-signin-cta-onclick. Only use it in markup your own site authors — never with values that come from user input or a CMS field.
Betting Odds
Off by default. With data-competition-statistics-show-odds="true", each upcoming match row shows 1X2 odds from the first operator in data-competition-statistics-odds-operators with a complete market, and a live match shows in-play prices — pre-match prices are never shown on a match in progress. One request covers the round on screen. In a container narrower than 600px the odds move to a second line under the teams. When no operator has prices the strip simply does not render, and the operator's own link opens on click either way. The odds settings are the same as the Competitor Card's.
The widget owns no betslip. Set data-competition-statistics-add-to-betslip="true" to push a clicked price into the Betslip widget on the same page as a selection ({matchId}:{market}:{outcome} — e.g. fb:m:123:FT_1X2:1 — the same id FuWidget.betslip.setSelection takes).
<div
data-component="fu-widget"
data-content-type="competition-statistics"
data-content-id="fb:c:3"
data-competition-statistics-show-odds="true"
data-competition-statistics-odds-operators="betano-bg"
data-competition-statistics-add-to-betslip="true"
></div>
<div data-component="fu-widget" data-content-type="betslip"></div>Callbacks
Two callbacks, both programmatic config only (competitionStatistics.callbacks in FuWidget.init()) — each receives an argument, so there is no data-attribute equivalent.
| Callback | Receives | Description |
|---|---|---|
onBroadcastClick | matchId | Setting it is what shows a TV icon next to the kick-off time of every upcoming match. A click calls it and does not expand the row. The widget holds no broadcast data — which channel shows the match, and what the click opens, is yours to implement |
onAddToBetslip | { matchId, market, pick: "1" | "X" | "2", odd } | Observe a clicked odds price — for your own betslip or for analytics. Runs whether or not addToBetslip is on |
Global Configuration
Set defaults for all Competition Statistics widgets in FuWidget.init():
FuWidget.init({
// ... other config
competitionStatistics: {
sections: ["header", "matches", "players", "season"],
playerRankingsLayout: "auto",
playerRankingsRows: 5,
liveRefresh: true,
refreshInterval: 30000,
showOdds: true,
odds: {
operators: ["betano-bg", "efbet-bg"], // Preference order — a row shows one operator
affiliateId: "aff-123", // Substituted into operator URLs carrying {affiliate_id}
},
addToBetslip: true,
matchCTA: { url: "/football/match/{matchId}" },
teamCTA: { url: "/football/team/{competitorId}" },
playerCTA: {
url: "/football/player/{athleteId}",
onClick: (athleteId) => router.push(/* ... */), // Optional: handle the click in your app instead of navigating
},
labels: { upcoming: "Fixtures" },
callbacks: {
onBroadcastClick: (matchId) => openTvSchedule(matchId), // Optional: shows the TV icon on upcoming matches
onAddToBetslip: (selection) => console.log(selection), // Optional: observe clicked odds prices
},
},
});Examples
Fixtures Only
<div
data-component="fu-widget"
data-content-type="competition-statistics"
data-content-id="fb:c:3"
data-competition-statistics-sections="header,matches"
></div>Season Statistics First, Linked Rankings
<div
data-component="fu-widget"
data-content-type="competition-statistics"
data-content-id="fb:c:1"
data-competition-statistics-sections="season,players,matches"
data-competition-statistics-team-cta-url="/teams/{competitorId}"
data-competition-statistics-player-cta-url="/players/{athleteId}"
></div>One Stage of a Past Season
<div
data-component="fu-widget"
data-content-type="competition-statistics"
data-content-id="fb:c:3"
data-competition-statistics-season-id="fb:c:3:2025/26"
data-competition-statistics-stage-id="your-stage-id"
></div>Features
- Upcoming / Results tabs with a round picker, matches grouped by day
- Multi-stage competitions grouped by stage, with Standings-style stage pills
- Expandable rows — match stats and a goal timeline for a finished or live match; form, a season comparison and the previous meeting for an upcoming one
- Live matches with a pulsing minute, the half-time score and polling
- Opt-in 1X2 odds on the match rows — in-play prices for a live match, operator preference, affiliate attribution and opt-in Betslip integration
- Player rankings and season-wide statistics, with team callouts and record matches
- Sections can be picked and reordered; an optional TV icon on upcoming matches, driven by your own callback
Updated about 9 hours ago
