Iframe embed
The lowest-touch integration: point an iframe at the hosted player page on player-dev.oddin-video.gg and, optionally, control it over an origin-verified postMessage bridge. Playback runs isolated in its own browsing context — no build step, no dependency on your page's framework.
Before anything plays
The parent page's origin must be on your key's AllowedIframeParents allow-list, and on the DRM CORS allow-list. See Getting started.
Plain iframe — no JavaScript
<iframe
src="https://player-dev.oddin-video.gg/embed/?baseUrl=https%3A%2F%2Ffeed-dev.oddin-video.gg&matchUrn=od%3Amatch%3A1234&apiKey=pk_test_your_key"
allow="autoplay; encrypted-media; picture-in-picture; fullscreen"
allowfullscreen
referrerpolicy="no-referrer"
style="border: 0; width: 100%; aspect-ratio: 16 / 9"
></iframe>The page boots a fully managed player — branded controls, go-live pickup, DRM, autoplay muted — and needs three query parameters (URL-encode the values):
| Parameter | Example | Notes |
|---|---|---|
baseUrl | https://feed-dev.oddin-video.gg | Required. Havik API environment. |
matchUrn | od:match:1234 | Required. The match to play. |
apiKey | pk_test_… | Required. See the api-key and the URL. |
parentOrigin | https://your-site.example | Enables the postMessage bridge. Without it the bridge stays disabled (fails closed). |
muted | false | Starts muted unless explicitly false. |
Without parentOrigin you get a player, not a remote control — fine for a pure drop-in. allow="autoplay; encrypted-media …" is required: without encrypted-media DRM cannot start inside a cross-origin iframe.
SDK embed — mountEmbed recommended
mountEmbed builds the iframe for you — correct allow list, sandbox, referrer policy, URL encoding — and gives you a typed handle over the postMessage bridge:
import { mountEmbed } from '@oddin-gg/havik-player';
const embed = mountEmbed({
container: document.querySelector('#player')!,
src: 'https://player-dev.oddin-video.gg/embed/',
baseUrl: 'https://feed-dev.oddin-video.gg',
matchUrn: 'od:match:1234',
apiKey: 'pk_test_your_key', // dev/demo only — see below
onEvent: (msg) => {
if (msg.type === 'oddin:state') console.log('state:', msg.state);
if (msg.type === 'oddin:error') console.error(msg.code, msg.message);
},
});
embed.play();
embed.setMuted(false);
embed.load('od:match:5678'); // switch match in place
// embed.destroy();The handle mirrors the player API — play, pause, setMuted, setVolume, setQuality, setMaxBitrate, setAudioTrack, setTextTrack, seekToLive, enterPip/exitPip, retry, load, destroy — and on(cb) subscribes to every frame event. Track lists arrive as an oddin:tracks event; use them to build quality/caption menus. Full option and message tables: API reference → Mode C.
Both ends verify event.origin on every message, and the embed fails closed: with no trusted parentOrigin it neither accepts commands nor posts events. The api-key is never accepted over postMessage.
The api-key and the URL
The hosted page reads its config from the query string, which places the api-key in the iframe URL. The key is publishable by design — the origin allow-list is what protects it, and the page sets referrerpolicy="no-referrer" so the URL never leaks through Referer. For development and demos this is exactly right.
For production, decide by your threat model:
Hosted page + query key — acceptable when you're comfortable that the key is origin-locked anyway. The URL (and thus the key) is visible in the page source and browser devtools — which is equally true of a key shipped in your bundle.
Self-hosted embed page + injected key strictest — serve the page from your own origin and inject config server-side; the query string is then ignored entirely, so the key never appears in any URL and a tampered
?baseUrl=can't redirect it:html<script> window.HAVIK_EMBED_CONFIG = { baseUrl: 'https://feed-dev.oddin-video.gg', matchUrn: 'od:match:1234', apiKey: 'pk_live_…', // injected by your server parentOrigin: 'https://your-site.example', }; </script> <script src="https://cdn.jsdelivr.net/npm/@oddin-gg/havik-player@1.3.0/dist/havik-player.global.js"></script> <script> HavikPlayer.bootEmbed(); </script>A ready-to-host template lives in the repository at
embed/index.html. PointmountEmbed'ssrcat your page and omitapiKey. Pin the exact SDK version (and add Subresource Integrity) so the embed page can't skew ahead of your host SDK.
Sizing
The player fills the iframe. Give the iframe a real size — the classic responsive pattern is aspect-ratio: 16 / 9; width: 100%. For a fixed-height slot, the video letterboxes on #0e0f13 (themeable when self-hosting).
Limits of the hosted page
The hosted page runs the player with Oddin's default skin and copy. If you need your own theme, overlays, or analytics hooks inside the frame, either self-host the embed page (it's one HTML file) or step up to the managed player — same capabilities, your DOM.