Skip to content

The embed contract

An embed snippet is code sitting in someone else's CMS. We cannot see it, cannot migrate it and cannot fix it, so the only responsible thing is to say up front what we promise not to change, and to say it before there are enough embeds in the world for the question to become expensive.

The promise in one line

Within the /widgets/v1/ lane, attribute names, config keys, method names and event names are additive only. Nothing is removed or repurposed. Breaking changes ship at a new lane, never under an existing URL.

The rules

What is covered

The data-or-* attribute names and their accepted values; the shape of window.OddsRelay and the config object passed to mount(); the custom event names the widget dispatches on your page; and the URLs above. Anything not on that list is internal: class names inside the shadow root, the DOM structure, and the contents of the bundle are all free to change at any time.

What counts as a breaking change

Removing or renaming an attribute, a config key, a method or an event; narrowing the values an attribute accepts; or changing what an existing value does. Adding an attribute, adding an accepted value, adding a method or an event, and fixing a wrong number are not breaking.

Unknown values never throw

An attribute value the runtime does not recognise falls back to the default and the widget still renders. This is deliberate and it is part of the contract, not an implementation detail: it is what lets us add values without the embeds already on your pages breaking on the ones they do not know about.

How a breaking change ships

At a new major lane, /widgets/v2/, announced before it exists. The v1 lane keeps serving the v1 contract; we do not migrate anyone by changing the bytes under a URL they already published.

How long a version is supported

A major lane is served indefinitely once published. If we ever intend to stop, the notice period starts at twelve months, is announced by email to every account with an active widget key, and never starts before a v2 has been available for six months.

Which lane you are on

window.OddsRelay.version reports the exact bundle version running on the page, so you can check a pinned embed from your own console without contacting us.

What each URL promises

URLPromiseWho decides when it changes
/widgets/v1/oddsrelay-widgets.jsThe v1 contract, always. The bytes move forward with fixes and additions.We do. That is the point of it.
/widgets/v/<version>/oddsrelay-widgets.jsThese exact bytes, forever. Verifiable with a Subresource Integrity hash.You do. Nothing reaches this embed until you change the URL.
/widgets/oddsrelay-widgets.jsIdentical to v1, served permanently so pre-versioning embeds keep working.We do. Treat it as v1 under its original name.

What is deliberately not covered

Class names inside the shadow root, the DOM structure the widget renders, and anything you reach by inspecting the bundle are internal and will change without notice. If you find yourself needing to style something we have not exposed, ask. The right answer is for us to name it as part of the contract, not for you to depend on an implementation detail that will move under you.

The current bundle version is 0.3.0, reported at runtime on window.OddsRelay.version. Details of the serving lanes are on the overview page.