Skip to content
Developers · Embed

Events & JS API

The loader puts one object on your page, window.Ocheso. Use it to hear what players do, and to mount, theme and steer widgets from your own code. None of it is needed for a plain embed.

Events

Each event reaches you three ways: Ocheso.on for every widget, widget.on for one, and a bubbling DOM event ocheso:<name> whose detail also carries the widget.

EventDetailWhen
ready{}The frame has loaded and is showing.
resize{ height }The content changed height; the widget has already followed it.
join{ tournament, status }The player entered. status is approved, or pending when the organiser approves entries.
gameStart{ id, color }The signed-in player's game began.
gameEnd{ id, result, termination, color }Their game finished. result is white, black or draw; color is theirs.
identityRequired{ reason }Someone needs to sign in with your login: join, my-game, expired or login.
error{ code, message }blocked (no answer in 10 s), identity (your fetchToken failed) or proto (a loader too old).
JavaScript
// Every widget on the page:
Ocheso.on("join", (detail, widget) => {
  analytics.track("tournament_join", { tournament: detail.tournament });
});

// One widget:
const off = widget.on("gameEnd", (detail) => showResult(detail.result));
off(); // stop listening

// Or as DOM events, which bubble from the widget's element:
document.addEventListener("ocheso:identityRequired", (e) => {
  if (e.detail.reason === "login") openMyLoginModal();
});
Example events
  1. 19:02:11 ocheso:ready {}
  2. 19:02:11 ocheso:resize {"height":612}
  3. 19:02:40 ocheso:identityRequired {"reason":"join"}
  4. 19:03:05 ocheso:join {"tournament":"weekly-blitz","status":"approved"}
  5. 19:05:00 ocheso:gameStart {"id":"5f0c…","color":"white"}
  6. 19:11:42 ocheso:gameEnd {"id":"5f0c…","result":"white","termination":"checkmate","color":"white"}

window.Ocheso

MemberWhat it does
versionThe loader's version, e.g. "1.0.0".
ready(fn)Calls fn(Ocheso) once the page has loaded and every snippet is mounted.
mount(el, options)Turns an element (or a selector) into a widget and returns it; null if the options name nothing valid.
identify(fetchToken, options)Signs your users in. See Player sign-in.
logout()Forgets the player in every widget. Call it when your user signs out.
setTheme(theme | null)Themes every widget on the page; null goes back to the snippets' own.
on(event, fn)Listens to every widget. Returns a function that stops it.
scan(root?)Mounts snippets under root now, instead of waiting for the page to change.
widgets()The widgets on the page.

A widget

MemberWhat it does
el · iframeThe element it was mounted on, and the iframe inside it.
readyA promise that settles when the frame is up.
on(event, fn)Listens to this widget only.
setTheme(theme | null)Themes this widget, over the page's theme.
navigate(view, params?)Switches view, e.g. navigate("pairings", { round: 2 }).
unmount()Removes the frame and gives the element back as it was.

Mounting from code

mount takes the same settings as the data-attributes, camelCased: tournament, org, series, game, view, theme, lang, accent, radius, font, board, height, minHeight, lazy, title, limit, round, mobileFullscreen, sounds, compact, header.

JavaScript
const widget = Ocheso.mount("#tournament", {
  tournament: "weekly-blitz",
  view: "standings",
  theme: "dark",
  limit: 10,
});

await widget.ready;            // the frame is up and showing
widget.navigate("pairings", { round: 2 });
widget.setTheme({ accent: "#e4572e" });
widget.unmount();              // the element is left as it was

In a React component

TSX
"use client";
import { useEffect, useRef } from "react";

// For when a component should own its widget. Needs the loader (or the queue
// stub below) on the page. Plain markup plus the script works too: the loader
// mounts and unmounts elements as React renders them.
export function Standings({ slug }: { slug: string }) {
  const el = useRef<HTMLDivElement>(null);
  useEffect(() => {
    let widget: Ocheso.Widget | null = null;
    window.Ocheso?.ready((api) => {
      widget = el.current && api.mount(el.current, { tournament: slug, view: "standings" });
    });
    return () => widget?.unmount();
  }, [slug]);
  return <div ref={el} />;
}

Calling before the script loads

The loader is async, so your code may run first. Paste this queue stub above your own script and calls wait in line until the loader arrives; it replays them in order. A queued call returns nothing, so code that needs the widget back goes through Ocheso.ready.

HTML
<script>!function(w){var o=w.Ocheso=w.Ocheso||{q:[]};["ready","mount","identify","logout","setTheme","on","scan"].forEach(function(m){o[m]=o[m]||function(){o.q.push([m,arguments])}})}(window)</script>

TypeScript

Types for all of the above are published at /embed/v1.d.ts. Save it into your project (for example as types/ocheso.d.ts) and window.Ocheso, the options and every event detail are typed.

Single-page apps

  • Load the script once, in your app shell. A second copy notices the first and does nothing.
  • Snippets added or removed by your router are mounted and cleaned up by the loader. Frameworks that keep pages alive while hidden (keep-alive caches, Turbo's page cache) keep their widgets too: call widget.unmount() when you leave such a page.
  • Listeners added with Ocheso.on live as long as the page; keep the function it returns to remove them.
Never put a key or token in an option or attribute. The loader refuses anything shaped like one, and player tokens travel only through identify().