Arena 3D#
A match rendered as a 3D broadcast, driven by the same pitch-level event
stream that feeds the WebSocket action frames. The ball follows the real
on-pitch action, shots arc to goal, and a goal triggers the celebration.
Two modes: live while the match is being played, and replay for a finished one.
It is included with the WebSocket addon at no extra cost. There is nothing separate to buy and nothing to activate — if your addon is active, it is on your dashboard.
Your embed key#
The dashboard issues one key per account, alongside a list of the domains allowed to load the widget. Both live on the Arena 3D block of /dashboard/.
- Up to 3 domains. Subdomains are covered automatically, so
example.comalso allowsapp.example.com. sports.bzzoiro.comalways works, with or without a domain listed — leave the list empty if you only want to watch, not embed.- Regenerating the key invalidates the old one immediately. Anything still embedding it stops rendering.
The key is not an API token and the two are not interchangeable: it authorises one widget on one set of domains, and it carries no read access to the API.
Embedding#
<iframe src="https://arena.bzzoiro.com/embed/live/{event_id}/?key=YOUR_EMBED_KEY"
width="100%" height="520" frameborder="0" allowfullscreen></iframe>
Swap live for replay on a finished match. {event_id} is the same id the
REST API uses, so an event from GET /api/v2/events/live/ drops straight in.
The response carries a Content-Security-Policy: frame-ancestors header built
from your own domain list, so a key lifted from your page still will not render
anywhere else.
URL parameters#
The widget starts with everything switched on. Append parameters to the embed URL to change what it draws before the first frame — useful when the widget sits in a small panel, or beside a scoreboard your own page already renders.
<iframe src="https://arena.bzzoiro.com/embed/live/{event_id}/?key=YOUR_EMBED_KEY&off=ticker,ads&dim=2"
width="100%" height="520" frameborder="0" allowfullscreen></iframe>
| Parameter | Values | Effect |
|---|---|---|
off |
comma-separated layer names | Start with these layers hidden |
on |
comma-separated layer names | Start with these layers shown |
dim |
2, 3 |
Flat 2D pitch or the 3D scene |
quality |
low, med, high |
How hard the 3D renderer pushes the GPU |
cam |
follow, fixed |
3D camera. Ignored in 2D, which is already a fixed centre shot |
Layers#
| Name | What it is |
|---|---|
scoreboard |
Score, clock and the competition line above the pitch |
names |
Floating tag naming the player on the ball |
commentary |
Running text line along the bottom |
ticker |
Event feed |
stats |
Stat cards — expected goals, shots, possession, territory |
pressure |
Pressure map shaded onto the pitch |
trail |
Ball trail |
ads |
Pitchside boards |
controls |
Playback bar — scrubber, play, speed, 2D/3D |
muted |
Crowd sound |
Names that are not on this list are ignored, so a typo silently does nothing rather than breaking the widget.
Layers are resolved before the first paint, so one switched off with off is
never drawn and then removed — there is no flash of a panel that disappears.
The URL is the last word. A viewer who toggles a layer from the panel keeps their choice for that session, but the next load applies the URL again, so an embed always starts in the state you asked for.
Hiding controls leaves a small gear in the corner that opens the panel again.
That is deliberate: the widget never traps a viewer in a state they cannot
leave.
Which matches have it#
The same ones that carry full per-action WebSocket coverage. From
GET /api/v2/events/live/:
websocket_plus: true— the match has pitch-level coverage, so Arena 3D renders itwebsocket_plus: false— score and stats only; there is nothing to draw
Requesting a match without coverage returns an empty pitch rather than an error, so check the flag before you build a link to it.
Responses#
| Status | Meaning |
|---|---|
200 |
Rendered |
402 |
The WebSocket addon on this account is not active |
403 |
The page's domain is not on the key's allowlist, or the key does not exist |
A 403 with a key you believe is correct is almost always the referrer: the
widget identifies the embedding page by Origin, falling back to Referer.
A page served with Referrer-Policy: no-referrer sends neither, and the
request cannot be attributed to any domain. Opening the embed URL directly in
the address bar fails the same way, and for the same reason — that is not an
embed, and no domain can be checked.