init
init(options): Promise<InitResult>. Call it once, before anything else. A second call returns the same
promise. It never rejects: a portal script that fails to load falls back to mock, and result.host says
so.
import { sdk } from '@filudi/game-sdk';
const result = await sdk.init({ gameId: 'gloop', version: '1.4.0' });console.log(result.host); // 'filudi' | 'crazygames' | 'poki' | 'playgama' | 'mock'console.log(result.player.nickname); // 'Guest-Fox'if (result.features.leaderboard) showBoardButton();import { sdk, type InitResult } from '@filudi/game-sdk';
const result: InitResult = await sdk.init({ gameId: 'gloop', version: '1.4.0' });const host: InitResult['host'] = result.host; // 'filudi' | 'crazygames' | 'poki' | 'playgama' | 'mock'if (result.features.leaderboard) showBoardButton();Options
Section titled “Options”await sdk.init({ gameId: 'gloop', // slug, same as in the console version: '1.4.0', // bundle version, sent with events debug: false, // console logging, same as ?filudi_debug=1 crazygames: { leaderboardKey: import.meta.env.VITE_CG_LEADERBOARD_KEY ?? '' },});interface InitOptions { gameId: string; // slug, same as in the console host?: HostName; // skip detection version?: string; // bundle version, sent with events locale?: string; // overrides the host's locale mock?: Partial<MockConfig>; // only read by the mock adapter timeoutMs?: number; // portal SDK script load, default 4000 handshakeTimeoutMs?: number; // wait for filudi:init, default 1500 debug?: boolean; // console logging, same as ?filudi_debug=1 events?: 'default' | 'always'; // 'always' sends track() batches from portals too eventsUrl?: string; // where portal batches go (POST .../v1/sdk/events), with 'always' crazygames?: { leaderboardKey?: string }; poki?: Record<string, never>;}gameId is the slug of the game in the console. On filudi.com the frame is opened for one game; when the
handshake names another slug than the one you passed, the SDK logs an error and uses the slug of the frame,
because the API would refuse the other one. version is the version string you upload; events carry it, so
pass the release version from your build.
The SDK ignores options for a host the game does not run on.
Result
Section titled “Result”const { host, player, locale, features, policy } = await sdk.init({ gameId: 'gloop' });// features.saves: 'remote' on filudi.com and portals with storage, 'local' elsewhere// features.leaderboard, features.rewarded, features.interstitial, features.account: booleans// policy.personalizedAds: false on kids sites or without consent// policy.ageBand: 'all' | 'kids' | 'teen' | 'adult'interface InitResult { host: HostName; player: Player; // { id, nickname, guest, host } locale: string; features: { saves: 'remote' | 'local'; leaderboard: boolean; rewarded: boolean; interstitial: boolean; account: boolean; }; policy: { personalizedAds: boolean; // false on kids sites or without consent ageBand: 'all' | 'kids' | 'teen' | 'adult'; };}Host detection
Section titled “Host detection”In this order: options.host; ?filudi_host=<name> on the page URL; a portal global or hostname
(CrazyGames.SDK or *.crazygames.com; PokiSDK or *.poki.com or *.poki-gdn.com; Playgama’s bridge);
the filudi handshake when the SDK runs inside an iframe (skipped on portal domains and at top level);
localhost, 127.0.0.1 or any unknown host gives mock.
On mock, two behaviours share the name. With options.mock or ?filudi_host=mock, the ESM build loads
the configurable mock. Without them, and always in the IIFE, the SDK runs standalone: ads unavailable,
saves in localStorage, no leaderboard.
The mock
Section titled “The mock”await sdk.init({ gameId: 'gloop', mock: { host: 'filudi', ads: 'no-fill', latencyMs: 300, player: { nickname: 'Guest-Fox' } },});interface MockConfig { host: HostName; // whose rules the mock follows (ad interval, features) latencyMs: number; // added to every async call ads: 'fill' | 'no-fill' | 'adblock' | 'error'; player: Partial<Player>; saveConflict: SaveRead<unknown> | null; // returned as the server copy on the next write leaderboard: LeaderboardEntry[]; // seed entries locale: string; eventsUrl: string | null; // where track() batches go; null drops them}Before init resolves
Section titled “Before init resolves”Async and void methods called while init() is pending wait for it. sdk.player.get(),
sdk.ads.available(), sdk.i18n.locale() and sdk.device() throw until it resolves. Every on() works at
any time and returns an unsubscribe function. Calling anything before init() was called at all throws.
Unavailable cases
Section titled “Unavailable cases”init() has none: it resolves on every host. When a portal script fails, takes longer than timeoutMs or
reports a disabled environment, the result says host: 'mock' and every other module answers as on the
mock.