The bookmakerOddsComparison widget renders a per-event 1x2 odds-comparison table across multiple bookmaker brands, served from the per-event snapshot pre-aggregated by the odds-pipeline-worker. Each row is a clickable affiliate link (/go/<cloakedLink>) wrapping logo + brand name + the 1 / X / 2 price cells.
Key features:
Cross-provider odds: one row per configured brand, side-by-side prices for the 1, X, and 2 outcomes. Inactive brands are hidden entirely (no greyed-out rows).
Two config approaches: point the widget at a Sanity-managed config with configid (recommended), or pass the config inline as a configuration JSON. configid takes precedence — see below.
Localized names + logos: team / competition names render translated (and with logos) for the visitor’s locale when the matching Sanity team / league doc is linked to its odds entity; otherwise the canonical name shows and no logo is used.
Affiliate-funnel CTA: each row is a single semantic <a> to the brand’s cloaked tracking link. Optional widget-level CTA button via ctakey / ctatext.
Tracking-link strategy (tlTarget): switch between the default Vulcan cloaked links and the RBO legacy-id links without changing anything else.
Two markets (market): 1x2 (1 / X / 2 columns) or a tournament outright (one column per outcome – e.g. World Cup Winner) set via the market field in the config. See the Outright section at the bottom of this page.
Whichever config approach you use, the display / behaviour attributes — CTA (ctakey / ctatext), ctacolors / ctahovercolors, tlTarget, rel, target, anchorid, eventsubtitle, competitionsubtitle, country, language — always live as top-level attributes on the tag, never inside the configuration JSON. (rel / target control the affiliate anchors; they default to nofollow / _blank when omitted.)
Configuring the widget: configid vs configuration
There are two ways to give the widget its event + brands, and configid takes precedence over configuration — if both are present, configid wins and configuration is ignored:
Approach
Where the config lives
Use when
configid(recommended)
A Sanity Bookmaker Odds config document, referenced by its slug. internalEventId, market, brands, title, subtitle are loaded from Sanity at render time.
Editorial-managed placements — editors curate the event + brands in Sanity; the page only carries the slug.
configuration(inline / legacy)
A JSON object on the tag: internalEventId, market, brands, and optional title / subtitle.
Ad-hoc / hard-coded placements, or where no Sanity config document exists.
⚠️ Precedence, and no silent fallback. When configid is present the widget resolves it from Sanity and does not fall back to configuration. A configid that doesn’t resolve renders a clear error (so a wrong slug is obvious) rather than quietly using an inline config. Use one approach per widget.
Localized names + logos are automatic — no attribute needed. When the event’s teams / competition are linked to their odds entity in Sanity (with translations / images), names render localized for the language / country locale and logos become available to the layout; otherwise the widget falls back to the canonical name with no logo.
All widget attributes — configid (recommended)
The recommended setup, shown first: the event + brands + title / subtitle live in the referenced Sanity Bookmaker Odds document; the tag carries the configid slug plus every top-level display attribute. This is a live widget (the referenced config exists in this environment).
Expand me...
<nw-blocksid="bookmakeroddscomparison"configid="bookmakerodds-fulham-chelsea-20260824"ctakey="bookmaker-odds-cta-bet-now"ctatext="Bet now"ctacolors="#00A000"ctahovercolors="#008000"tlTarget="vulcan"trackinglinktarget="showcase"rel="sponsored nofollow"target="_blank"anchorid="bookmaker-odds-configid"eventsubtitle="Matchday 2, Craven Cottage"competitionsubtitle="Premier League - England"country="UK"language="en"></nw-blocks>
The same widget with the inline configuration JSON instead of a configid, so every config field is visible on the tag. If both configid and configuration are present, configid wins and this JSON is ignored.
Expand me...
<nw-blocksid="bookmakeroddscomparison"configuration='{"internalEventId":"019e6dac-0a37-762f-8f21-13a8b6b28939","market":"1x2","brands":[{"cloakedLink":"rabona-sports","legacyId":"RabonaSport","provider":"altenar"},{"cloakedLink":"1bet-sports","legacyId":"1BetSport","provider":"bahigo"}],"title":"Cross-bookmaker odds","subtitle":"Compare prices across all your favourite sportsbooks"}'ctakey="bookmaker-odds-cta-bet-now"ctatext="Bet now"ctacolors="#00A000"ctahovercolors="#008000"tlTarget="vulcan"trackinglinktarget="showcase"rel="sponsored nofollow"target="_blank"anchorid="bookmaker-odds-all"eventsubtitle="Matchday 2, Craven Cottage"competitionsubtitle="Premier League - England"country="UK"language="en"></nw-blocks>
Error: no snapshot for event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1snapshotKey=event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1
The tlTarget top-level attribute controls how every affiliate link in the widget (brand logo, each odds cell, and the BET NOW button) is built:
tlTarget
Link form
Notes
vulcan(default)
/go/<cloakedLink>?country=…&language=…&wid=…
Standard Vulcan cloaked-link strategy. Used when tlTarget is omitted.
rbo
/go/<legacyId>.html
RBO legacy strategy. Uses each brand’s legacyId; no query params are appended.
The value is case-insensitive (RBO, Rbo, rbo all work) and any unrecognized value falls back to vulcan.
For rbo, each brand’s legacyId is read from the brands[] entry in the configuration JSON (it falls back to the brand’s Sanity reference legacyId when omitted). If no legacyId can be resolved for a brand, that link safely falls back to the Vulcan form.
legacyId is ignored when tlTarget is vulcan, so it is harmless to always include it.
Full attributes (all options)
Expand me...
<nw-blocksid="bookmakeroddscomparison"configuration='{"internalEventId":"019e6dac-0a37-762f-8f21-13a8b6b28939","market":"1x2","brands":[{"cloakedLink":"rabona-sports","legacyId":"RabonaSport","provider":"altenar"},{"cloakedLink":"royalistplay-sports","legacyId":"RoyalListPlaySport","provider":"delasport"},{"cloakedLink":"1bet-sports","legacyId":"1BetSport","provider":"bahigo"},{"cloakedLink":"legendplay-sports","legacyId":"LegendPlaySport","provider":"altenar"}],"title":"Cross-bookmaker odds","subtitle":"Compare prices across all your favourite sportsbooks"}'ctakey="bookmaker-odds-cta-bet-now"ctatext="Bet now"anchorid="bookmaker-odds-full"tlTarget="vulcan"country="UK"language="en"></nw-blocks>
Error: no snapshot for event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1snapshotKey=event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1
Error: no snapshot for event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1snapshotKey=event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1
With CTA translation key (resolved server-side via i18n)
Expand me...
<nw-blocksid="bookmakeroddscomparison"configuration='{"internalEventId":"019e6dac-0a37-762f-8f21-13a8b6b28939","market":"1x2","brands":[{"cloakedLink":"rabona-sports","provider":"altenar"},{"cloakedLink":"royalistplay-sports","provider":"delasport"},{"cloakedLink":"1bet-sports","provider":"bahigo"},{"cloakedLink":"legendplay-sports","provider":"altenar"}],"title":"Today's headline match","subtitle":"World Cup 2026"}'ctakey="bookmaker-odds-cta-bet-now"country="de"language="de"></nw-blocks>
Error: no snapshot for event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1snapshotKey=event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1
With CTA literal text (no translation lookup)
Expand me...
<nw-blocksid="bookmakeroddscomparison"configuration='{"internalEventId":"019e6dac-0a37-762f-8f21-13a8b6b28939","market":"1x2","brands":[{"cloakedLink":"rabona-sports","provider":"altenar"},{"cloakedLink":"1bet-sports","provider":"bahigo"}],"title":"Best odds, side by side"}'ctatext="Claim your best odds now"country="fr"language="fr"></nw-blocks>
Error: no snapshot for event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1snapshotKey=event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1
RBO tracking links (tlTarget="rbo")
Set tlTarget="rbo" and provide a legacyId for each brand. Every affiliate link in the widget (brand logo, odds cells, and the BET NOW button) is then built as /go/<legacyId>.html instead of the Vulcan /go/<cloakedLink> form.
Error: no snapshot for event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1snapshotKey=event:019e6dac-0a37-762f-8f21-13a8b6b28939:1x2:v1
Outright market (market: "outright")
The samebookmakerOddsComparison widget renders a tournament outright (e.g. World Cup Winner) when market is set to "outright" in the configuration JSON. Instead of fixed 1 / X / 2 columns, each brand row shows that bookmaker’s price for every outcome (one cell per selection – the competing teams or nations), served from the outright snapshot pre-aggregated by the odds-pipeline-worker.
Everything else is identical to the 1x2 market: brands, title / subtitle, ctakey / ctatext, tlTarget, and per-brand legacyId all behave exactly the same. Only two fields differ from the examples above – market is "outright" and internalEventId points at an outright event.
Note: Delasport does not offer outright markets, so these examples use Altenar- and Bahigo-backed brands. A configured brand with no outright price for the event is simply hidden, the same inactive-row behaviour as the 1x2 market.
Outright – full attributes (all options)
Expand me...
<nw-blocksid="bookmakeroddscomparison"configuration='{"internalEventId":"019ec25b-d1b5-7d11-9c62-e6981cd49886","market":"outright","brands":[{"cloakedLink":"rabona-sports","legacyId":"RabonaSport","provider":"altenar"},{"cloakedLink":"1bet-sports","legacyId":"1BetSport","provider":"bahigo"},{"cloakedLink":"legendplay-sports","legacyId":"LegendPlaySport","provider":"altenar"}],"title":"World Cup 2026 Winner","subtitle":"Outright odds across bookmakers"}'ctakey="bookmaker-odds-cta-bet-now"ctatext="Bet now"anchorid="bookmaker-odds-outright"tlTarget="vulcan"country="UK"language="en"></nw-blocks>
World Cup 2026 WinnerOutright odds across bookmakers
Set tlTarget="rbo" and provide a legacyId for each brand. Every affiliate link in the outright table – the brand-logo column headers, every odds cell, and the footer BET NOW buttons – is then built as /go/<legacyId>.html instead of the Vulcan /go/<cloakedLink> form.
Expand me...
<nw-blocksid="bookmakeroddscomparison"configuration='{"internalEventId":"019ec25b-d1b5-7d11-9c62-e6981cd49886","market":"outright","brands":[{"cloakedLink":"rabona-sports","legacyId":"RabonaSport","provider":"altenar"},{"cloakedLink":"1bet-sports","legacyId":"1BetSport","provider":"bahigo"},{"cloakedLink":"legendplay-sports","legacyId":"LegendPlaySport","provider":"altenar"}],"title":"World Cup 2026 Winner","subtitle":"RBO tracking strategy"}'ctakey="bookmaker-odds-cta-bet-now"ctatext="Bet now"tlTarget="rbo"country="UK"language="en"></nw-blocks>