Skip to content

Portals

One bundle runs on filudi.com and on the three portals. At init() the SDK detects the host from the portal’s global or hostname, loads the portal’s own script when the page does not have it, and maps every call. Nothing portal-specific ships in your bundle. Each portal has its own listing process, outside Filudi; this page covers what your game does once it runs there.

filudi.comCrazyGamesPokiPlaygama
DetectionThe handshake in a frameCrazyGames.SDK or *.crazygames.comPokiSDK or *.poki.com, *.poki-gdn.comwindow.bridge
AdsNone yetRewarded and midgamerewardedBreak, commercialBreakRewarded and interstitial
SavesThe APIData module, else localStoragelocalStoragebridge.storage
ScoresSigned, to your boardsuser.submitScore with your keyNonebridge.leaderboards
top() and me()WorkunavailableunavailableWork with in_game boards
PlayerGuest or accountThe portal’s user, else a random idGuestThe portal’s player
LocaleThe site’suser.systemInfo.localenavigator.languagebridge.platform.language
EventsThe APIDropped unless events: 'always'SameSame
Extrassdk.host.crazygamessdk.host.pokisdk.host.playgama

The SDK loads https://sdk.crazygames.com/crazygames-sdk-v3.js when the page does not have it, and falls back to the mock when the script fails, takes longer than timeoutMs or reports the disabled environment. ready() is game.loadingStop, the gameplay brackets are gameplayStart and gameplayStop, happyTime() is happytime. Ads go through ad.requestAd('rewarded' | 'midgame'); ad.hasAdblock turns available() off. The portal paces interstitials, so the SDK adds no interval there.

Saves go to the data module under one key, filudi:save, holding { v, d }; with the module off they stay in localStorage. Scores reach the portal board only with the key from the CrazyGames developer portal, encrypted with AES-GCM; keep it in a build variable.

CrazyGames options

await sdk.init({
gameId: 'gloop',
version: '1.4.0',
crazygames: { leaderboardKey: import.meta.env.VITE_CG_LEADERBOARD_KEY ?? '' },
});
sdk.host.crazygames?.onMuteChange((muted) => audio.mute(muted));
fullscreenButton.hidden = result.host === 'crazygames'; // the portal draws its own

The portal’s mute setting, invite links and game context are host extras. device() reads user.systemInfo.device.type.

The SDK loads https://game-cdn.poki.com/scripts/v2/poki-sdk.js when the page has no window.PokiSDK, then calls PokiSDK.init(). A script that fails, takes longer than timeoutMs, or an init() that rejects (Poki does when an ad blocker is on) puts the game on the mock with ads off. ready() is gameLoadingFinished. Interstitials are commercialBreak, always completed: Poki says nothing about a skip. Rewarded ads are rewardedBreak: completed on true, skipped on false.

Poki keeps no save, leaderboard or player: saves stay in localStorage, boards answer unavailable, the player is a guest. shareableURL(params) and getURLParam(key) are the host extras.

Poki share link

const link = (await sdk.host.poki?.shareableURL({ seed: today })) ?? location.href;
const seed = sdk.host.poki?.getURLParam('seed') ?? new URLSearchParams(location.search).get('seed');

The adapter runs when the page has Playgama Bridge (window.bridge) and calls bridge.initialize() if the page has not, within timeoutMs. Ads are advertisement.showRewarded() and showInterstitial(), read through the state events: opened fires start, rewarded then closed is completed, closed alone is skipped, failed is no-fill.

Saves go to bridge.storage under filudi:save as { v, d }. Scores go to bridge.leaderboards.setScore unless the board type is not_available, and top() reads getEntries when the type is in_game. visibility_state_changed fires pause and resume; the locale is bridge.platform.language; device() reads bridge.device.type (a TV falls back to the SDK’s own guess). The audio setting is sdk.host.playgama?.onAudioChange(fn), with enabled the opposite of muted.

Playgama audio

sdk.host.playgama?.onAudioChange((enabled) => audio.mute(!enabled));

The playground installs each portal’s global in the frame before your bundle runs, with the shapes the adapters read, and lets you set the ad outcome, the environment, the data module, the leaderboard type, the player and the locale. What it cannot do: show a real ad, decrypt a real CrazyGames key (it checks the encryption against the key you paste), or stand for a portal’s review. Run the game on each host there before every release, as the release checklist says.

A game runs on filudi.com by default. The console’s distribution switch opens it to approved third-party portals on the Filudi catalog once it has a live version; the console shows which sites list it. That is a different thing from CrazyGames, Poki and Playgama: those portals host your bundle themselves and you submit it to them.