Troubleshooting
Check these first
- Studio's install status. Seen on yoursite.com means the widget loaded there; an amber Seen on an origin not on the list names the exact address to allow.
- The browser console on your page. Messages that mention
Content Security Policy,frame-ancestorsorPermissions policypoint straight at one of the sections here. Ocheso.versionin the console:"1.0.0"means the loader is there;undefinedmeans it never loaded.
Only the fallback link shows
After 10 seconds without an answer from the frame, the widget shows the link you put inside it and fires an error event with code blocked. Usual causes, in order:
Your site's Content Security Policy
If your site sends a CSP, it must allow Ocheso's script and frame. No 'unsafe-inline' is needed: the loader sets its styles through the DOM, which CSP allows.
Content-Security-Policy:
script-src 'self' https://www.ocheso.com;
frame-src 'self' https://www.ocheso.com;
connect-src 'self' https://www.ocheso.com;connect-srcis for install detection: when a frame can't load, the loader tells Ocheso which page it is on, so Studio can show the address to allow. Without it the console logs a refused connection and Studio never sees that page.
Pasting the queue stub? It is the one inline script; allow it by hash rather than with 'unsafe-inline':
script-src 'self' https://www.ocheso.com 'sha256-Q0bulL06WoILlL/6vSB3egdYOqjJlZfcGogqJX0q+yo=';An ad or tracker blocker
Rare, but some lists block third-party frames. The link still works, which is why the snippet keeps it. Try the page in a private window without extensions to tell.
A page that sends Cross-Origin-Embedder-Policy
Pages with Cross-Origin-Embedder-Policy: require-corp (often set for SharedArrayBuffer, by some game engines and editors) can only show frames that opt in to the same policy, and Ocheso's widget pages don't. Put the widget on a page without that header, or link to the hosted page.
"Refused to frame", or the widget is read-only
When your organisation lists allowed domains, a widget on any other address is refused by the browser (Refused to frame … frame-ancestors in the console) or, if it does load, stays read-only with a link to join on the hosted page. The fix is always the list in Studio → Developers → Allowed domains. Each entry is one exact origin:
| Your page is on | Add |
|---|---|
| https://yoursite.com | https://yoursite.com |
| https://www.yoursite.com | https://www.yoursite.com (a different origin from the one above) |
| https://staging.yoursite.com | https://staging.yoursite.com, or https://*.yoursite.com for every subdomain |
| https://yoursite.com:8443 | https://yoursite.com:8443 (a port is part of the origin) |
| http://localhost:3000 | http://localhost:3000 (http only for localhost and 127.0.0.1) |
https://*.yoursite.com covers subdomains, never yoursite.com itself. Most sites need the bare domain and www both.Site builders that wrap your code
Some builders run pasted HTML inside a frame of their own, on another domain (Wix's Embed HTML element and Google Sites' Embed both do). The widget then sees the builder's domain rather than yours, and can't grow past the box the builder gives it.
- Use the iframe snippet and set the box's height in the builder; or use the builder's own iframe element.
- If you keep allowed domains, Studio's install status shows the builder's address once the widget has loaded there: allow that address too.
- Or skip the code: link to the hosted page from your menu.
WordPress's Custom HTML block puts the snippet straight into your page and needs none of this.
Games don't go full screen on phones
The widget asks for real full screen first, and covers your page instead when that's refused, so games stay playable either way. If your site sends a Permissions-Policy that limits fullscreento itself, the frame's request is refused; allow Ocheso:
# Allows Ocheso's frame to go full screen on phones (yours keeps it too):
Permissions-Policy: fullscreen=(self "https://www.ocheso.com")If the widget sits inside an element with a CSS transform, filter or contain, the cover is drawn within that element instead of over the page; the real full screen isn't affected.
Sign-in problems
"Session expired", or players asked to sign in again
- Your endpoint must hand out a fresh player token each time it's called, with
Cache-Control: no-store. A cached token runs out after 10 minutes, or signs the wrong person in. When one is refused, the widget asks again with reasonexpiredand the loader fetches a new one. - Sessions last 12 hours for your users and 7 days for Ocheso accounts; after that, one more sign-in.
- On iPhones and iPads, Safari clears what a site has stored after about 7 days without a visit to it. Players who return after a break sign in again: a code for accounts, nothing at all with your login.
No Google button
Google sign-in shows only when it's switched on for Ocheso and the widget isn't in an app: Google refuses sign-in inside webviews. In apps, players use the email code or your login (Mobile apps).
Your login does nothing
- The tournament's sign-in must be Your platform's login or Both; with Ocheso accounts the widget never asks your page.
Ocheso.identify()must run on the page (before the loader, with the queue stub, or after it, either works). Anerrorevent with codeidentitycarries what your fetchToken threw.- The page's domain must be in your allowed list, or the widget stays read-only.
No sounds
Browsers don't play sound a page starts by itself, so move and clock sounds begin after the player's first tap or click inside the widget. data-sounds="false" turns them off for good.
Single-page apps: widgets left behind, or doubled
- Left behind.The loader removes a widget when its element leaves the page. Routers that hide pages instead of removing them (keep-alive caches, Turbo's page cache) keep the widget alive: call
widget.unmount()on leaving, or remount withOcheso.mount(). - Two loaders. Loading
v1.jstwice is harmless: the second copy sees the first and stops. But if one is a pinned file and the otherv1.js, whichever loaded first is the one you get; checkOcheso.version. - Page won't scroll after a game.The cover locks your page's scroll while it's up, and gives it back when it closes or the widget is removed. A page your router keeps alive while hidden keeps the lock too:
widget.unmount()releases it.
Still stuck?
Send us a messagewith the page's address and what the console says. Never send a secret key: we never need it.