Articles on: Developers & API
This article is also available in:

Widget lifecycle and error handling

This article is for developers who embed a Drimify experience with the HTML integration code (widget) and need to react to what happens inside it: show a loader, detect errors, or track which screen the participant is on.


For setup and the full list of callbacks, see Advanced integration of the HTML integration code (widget) via the API.


Event order when the widget loads


When you call widget.load(), events always arrive in this order:


  1. onReady fires once, as soon as the experience has loaded its configuration (texts, theme, layout). This happens before the first screen is requested.
  2. onRouteChange fires each time a screen is displayed, starting with the first one.


What this means in practice:


  • onReady doesn't mean the first screen is visible. The first onRouteChange marks that.
  • onError can still fire after onReady, for example if the first screen fails to load.
  • If the experience can't start at all, onReady never fires. You receive onError instead (see below).


Use onReady for "the experience has started". Use the first onRouteChange for "the participant can see content".


Screen names (onRouteChange)


Every onRouteChange event has this shape:


{
type: "routechange",
data: {
screen: "screen_<name>-<APP_ID>[-<suffix>]",
errorCode: "ERR_xx" // only on some unavailability screens
}
}


Examples of regular screens:


  • screen_start-12345
  • screen_end-12345
  • Loyalty Hub: screen_loyalty-hub-<tab>-12345, screen_loyalty-hub-reward-12345-<reward_id>


Match screens by their prefix (for example event.data.screen.startsWith('screen_end-')) rather than the full value: the suffix can change.


Screens that mean the participant can't play


These screens are delivered as a normal onRouteChange, not as an error. The experience is working, but it shows the participant a message instead of the game.


Screen name starts with

Meaning

errorCode

screen_outofdate-

The experience isn't available at this time

ERR_02 not started yet, ERR_03 ended, ERR_18 between two activation periods, ERR_19 outside the opening hours

screen_nomoreviews-

The participation quota has been reached

ERR_04

screen_noquestions-

The experience has no question to display

ERR_16

screen_langnotavailable-

The game isn't available in the selected language

—

screen_alreadyplayed-<id>-ip / -session

The participant has already played (limit per IP address or per session)

—

screen_restriction-<id>-session

Access control: this session_uid isn't on the authorised list

—

screen_restriction-<id>-session_unique

Access control: this session_uid has already been used

—

screen_restriction-<id>-country / -ip / -query_string

Blocked by country, IP address or URL parameter

—

screen_restriction-<id>-jwt

JWT authentication failed

—

screen_form-error-

A form or login was refused (blocked email domain, restricted list, already used, invalid format)

—

screen_loyalty-hub-redirect-

Loyalty Hub: the participant is sent back to the hub (entry refused, or the normal return after a play)

—


Errors (onError)


onError is used when the experience can't start or can't recover. It fires once. The error code is in event.data.message.


Code

Meaning

ERR_04

The participation quota was already reached when the page loaded

ERR_05

Security error: the reserved preview parameter was used

ERR_07

The experience isn't published

ERR_08

The experience needs a premium option that isn't included in the plan

ERR_09

A session_uid is required but wasn't provided

ERR_10

The session_uid isn't allowed (not on the access list)

ERR_13

The SSO (SAML or OAuth) login failed

ERR_14

The experience isn't available in the requested language

ERR_15

The link doesn't exist (unknown or deleted experience)

ERR_17

The SSO configuration is invalid

ERR_21

A Combo™ or Dynamic Path™ has no game assigned


onError can also fire without an ERR_xx code, for example when a screen fails to load because of a network error after the experience has started.


widget.onError = function (event) {
var code = event.data && event.data.message;
switch (code) {
case 'ERR_09':
case 'ERR_10':
// session_uid missing or refused
break;
case 'ERR_13':
case 'ERR_17':
// SSO problem
break;
default:
// any other fatal error
break;
}
};

widget.onRouteChange = function (event) {
if (!event.data) {
return;
}
if (event.data.errorCode) {
// ERR_02, ERR_03, ERR_04, ERR_16, ERR_18 or ERR_19
}
if (event.data.screen.startsWith('screen_restriction-')) {
// access refused
}
};


Session unique ID (session_uid)


  • A session_uid has no expiry date. An unknown session_uid is treated as a new participant, not as an error.
  • If access control is based on session_uid:
    • a value that isn't on the list gives ERR_10 through onError, or the screen_restriction-<id>-session screen;
    • a value that has already been used gives the screen_restriction-<id>-session_unique screen through onRouteChange.
  • If participation is limited to once per session: a reused session_uid gives the screen_alreadyplayed-<id>-session screen through onRouteChange.
  • When SSO is enabled, the participant is identified by their SSO account and any session_uid passed in the URL is ignored.


There is no "session expired" callback. Rely on the screens and codes above.


Loading state and timeout


We don't publish guaranteed load times: they depend on the experience, its media, and the participant's device and network. To build a loading state:


  1. Start a timer when you call widget.load().
  2. Treat the first onRouteChange as "the experience is visible" and onError as a definitive failure. Either one clears the timer.
  3. Keep a timeout as a safety net. It covers the case where neither event arrives, for example when the frame itself can't load (network failure, content blocked by the browser). Measure typical load times in your own environment and set the value from those, with a generous margin for slow mobile connections.


var timer = setTimeout(showFallback, TIMEOUT_MS);

widget.onRouteChange = function (event) {
clearTimeout(timer);
hideLoader();
};

widget.onError = function (event) {
clearTimeout(timer);
showError(event.data && event.data.message);
};

widget.load();

Updated on: 27/10/2026

Was this article helpful?

Share your feedback

Cancel

Thank you!