SDK Event Order Checker for Poki, CrazyGames and YouTube Playables
Paste a log of your game's SDK calls and check it against the order rules Poki, CrazyGames and YouTube Playables publish. Runs in your browser.
The recorder (debug builds only)
Load it after the portal SDK’s <script> tag and before your game code, callinstallSdkRecorder(), play through a level, then run copySdkLog() in the console and paste the result above. It wraps the documented SDK calls and logs each one with a timestamp. Remove it before you submit.
// SDK event recorder for the SDK Event Order Checker (debug builds only; remove before submitting).
// Load it AFTER the portal SDK's <script> tag and BEFORE your game code. It wraps the documented SDK
// calls of Poki, CrazyGames v3 and YouTube Playables, prints one line per call, and keeps the lines in
// window.__sdkLog. Copy them with copySdkLog() and paste them into the checker.
export function installSdkRecorder(win = window) {
const t0 = performance.now();
/** @type {string[]} */
const log = (win.__sdkLog = []);
const rec = (/** @type {string} */ sdk, /** @type {string} */ name) => {
const line = `[sdk-log] +${Math.round(performance.now() - t0)}ms ${sdk} ${name}`;
log.push(line);
console.log(line);
};
// Records the player's first input, so the checker can tell "on load" from "on first input".
const firstInput = () => rec('input', 'first-input');
win.addEventListener('pointerdown', firstInput, { once: true, capture: true });
win.addEventListener('keydown', firstInput, { once: true, capture: true });
/** Wraps obj[method]; logs the call, and `name:done` (+ result) when a returned promise settles. */
const wrap = (/** @type {any} */ obj, /** @type {string} */ method, /** @type {string} */ sdk, /** @type {string} */ name = method, withResult = false) => {
if (!obj || typeof obj[method] !== 'function') return;
const original = obj[method];
obj[method] = function (/** @type {any[]} */ ...args) {
rec(sdk, name);
const out = original.apply(this, args);
if (out && typeof out.then === 'function') {
out.then(
(/** @type {unknown} */ v) => rec(sdk, withResult ? `${name}:done:${Boolean(v)}` : `${name}:done`),
() => rec(sdk, `${name}:error`),
);
}
return out;
};
};
const poki = win.PokiSDK;
if (poki) {
for (const m of ['init', 'gameLoadingFinished', 'gameplayStart', 'gameplayStop']) wrap(poki, m, 'poki');
wrap(poki, 'commercialBreak', 'poki');
wrap(poki, 'rewardedBreak', 'poki', 'rewardedBreak', true);
}
const cg = win.CrazyGames && win.CrazyGames.SDK;
if (cg) {
wrap(cg, 'init', 'crazygames');
for (const m of ['loadingStart', 'loadingStop', 'gameplayStart', 'gameplayStop']) wrap(cg.game, m, 'crazygames');
if (cg.ad && typeof cg.ad.requestAd === 'function') {
const requestAd = cg.ad.requestAd;
cg.ad.requestAd = function (/** @type {string} */ type, /** @type {any} */ callbacks = {}) {
rec('crazygames', `requestAd:${type}`);
const cb = (/** @type {string} */ k) => (/** @type {any[]} */ ...a) => {
rec('crazygames', k);
return callbacks[k]?.(...a);
};
return requestAd.call(this, type, { ...callbacks, adStarted: cb('adStarted'), adFinished: cb('adFinished'), adError: cb('adError') });
};
}
}
const yt = win.ytgame;
if (yt) {
for (const m of ['firstFrameReady', 'gameReady', 'loadData', 'saveData']) wrap(yt.game, m, 'playables');
wrap(yt.ads, 'requestInterstitialAd', 'playables');
wrap(yt.ads, 'requestRewardedAd', 'playables', 'requestRewardedAd', true);
}
win.copySdkLog = () => log.join('\n');
return log;
}Why the order of SDK calls matters
Portal SDKs measure your game through a handful of calls: when loading finished, when gameplay started and stopped, when an ad break happened. The portals use those calls for their dashboards and for ad timing, and some of them review the order explicitly. Poki’s requirements list the common mistakes: the same event fired twice in a row, gameplayStart() on page load instead of the first input, SDK events during an ad, and commercialBreak() used when leaving gameplay rather than when heading back into it. YouTube Playables certifies the order of its ready signals and cloud saves (integration requirements).
These mistakes are easy to make and hard to see, because the game looks fine while the event stream is wrong. This tool reads a log of the calls and checks it against the published rules.
How to use it
- Add the recorder to a debug build: load it after the portal SDK’s script tag and before your game code, and call
installSdkRecorder(). It wraps the SDK methods and prints lines such as[sdk-log] +1215ms poki gameplayStart, plus one line for the player’s first tap or key press. - Play through a typical session: start, finish a level, lose, continue with a reward, quit to the menu.
- Run
copySdkLog()in the browser console, paste the result above, pick the SDK, and press Check the log.
Without the recorder, you can paste or type event names one per line (gameplayStart, commercialBreak, commercialBreak:done). The “first input” rule then shows as a note, because only the recorder logs input.
What it checks
The full list, generated from the checker’s code, is below the tool. In short:
- Poki: no repeated
gameplayStart/gameplayStop;gameLoadingFinishedbefore the firstgameplayStart; the firstgameplayStartafter the first input; breaks only aftergameplayStop; no SDK events while a break plays; a commercial break leads back into gameplay. Sources: Poki’s requirements and order of events. - CrazyGames SDK v3:
init()first; if you use the optional loading events, aloadingStart/loadingStoppair before gameplay; agameplayStartexists (it ends CrazyGames’ initial-download measurement); ads requested only aftergameplayStop; every ad request ends withadFinishedoradError; no gameplay events while an ad plays. Sources: the game module and ad requirements. - YouTube Playables:
firstFrameReady()beforegameReady(),gameReady()called once, andloadData()completed before the firstsaveData().
What it cannot know
A log shows order, not context. The checker cannot tell whether a loading screen was still visible when you called gameReady(), whether your game actually paused and muted during an ad, or whether an ad was placed at a natural break. It reads one session, so code paths you did not play are not checked. CrazyGames does not forbid repeated gameplay events outright, so those are warnings rather than problems. Treat a clean log as one piece of evidence, then test in each portal’s own QA tool.
The SDK guides show the call order in context, with tested example code for each portal.
The rules it checks
Generated from the checker’s code. Each rule links to the official page it comes from.
Poki SDK
- gameplayStart / gameplayStop never fire twice in a row (Poki: Requirements (technical standards))
- gameLoadingFinished() comes before the first gameplayStart() (Poki: SDK overview and events (order of events))
- The first gameplayStart() follows the player’s first input (Poki: Requirements (technical standards))
- Breaks start only after gameplayStop() (Poki: SDK overview and events (order of events))
- No SDK events while a break is playing (Poki: Requirements (technical standards))
- commercialBreak() leads back into gameplay (Poki: Requirements (technical standards))
CrazyGames SDK v3
- SDK.init() runs before any other SDK call (CrazyGames: SDK introduction)
- loadingStart() / loadingStop() pair before gameplay (CrazyGames: Game module)
- gameplayStart() is reported (CrazyGames: Game module)
- Ads are requested at breaks, after gameplayStop() (CrazyGames: Advertisement requirements)
- Every ad request ends with adFinished or adError (CrazyGames: Video ads)
- No gameplay events while an ad is playing (CrazyGames: Advertisement requirements)
- No repeated gameplayStart() / gameplayStop() (CrazyGames: Game module)
YouTube Playables SDK
- firstFrameReady() is called, before gameReady() (YouTube Playables SDK reference)
- gameReady() is called once the game is interactive (YouTube Playables: Integration requirements)
- loadData() completes before the first saveData() (YouTube Playables: Integration requirements)
Questions
- Where does the log come from?
- From the recorder shown on this page, which wraps the documented SDK calls in a debug build and prints one line per call. You can also type or paste event names, one per line.
- Does a clean result mean my integration will pass review?
- No. The checker only sees the order of calls in one play session. Reviewers also check timing, ad placement, audio and gameplay, which a log cannot show. Use it to catch ordering mistakes before you upload.
- Is my log sent anywhere?
- No. The log is checked by JavaScript in this page and is not uploaded or stored.