crazy-games-js-sdk
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCrazyGames JavaScript SDK
CrazyGames JavaScript SDK
Integration Checklist
集成检查清单
Follow this order when integrating the SDK into a game:
- Load SDK — add the CDN tag before your game bootstraps
<script> - Init — call and await resolution before touching any SDK module
SDK.init() - Lifecycle hooks — wire and
loadingStart/Stopthroughout the game loopgameplayStart/Stop - Ads — add interstitial and/or rewarded ad calls at natural break points
- Optional: Auth & Storage — add sign-in and persistent key/value storage if needed
- Optional: Payments — Xsolla Pay Station integration (separate concern; skip if not applicable)
将 SDK 集成到游戏时,请按以下顺序操作:
- 加载 SDK — 在游戏 bootstrap 之前添加 CDN 标签
<script> - 初始化 — 调用 并等待 Promise 完成,然后再使用任何 SDK 模块
SDK.init() - 生命周期钩子 — 在整个游戏循环中接入 和
loadingStart/StopgameplayStart/Stop - 广告 — 在自然发生的游戏断点添加插页式和/或激励广告调用
- 可选:身份验证与存储 — 根据需要添加登录和持久化键/值存储
- 可选:支付 — 集成 Xsolla Pay Station(独立事项;如果不适用则跳过)
Installation
安装
Load the SDK from the official CDN before bootstrapping the game.
html
<script src="https://sdk.crazygames.com/crazygames-sdk-v3.js"></script>If you load it dynamically, wait until is defined before calling it. If the script is blocked (e.g. by CSP), the global will be undefined — add to your directive.
window.CrazyGames.SDK.initwindow.CrazyGamessdk.crazygames.comscript-src通过官方 CDN 加载 SDK,并确保在游戏 bootstrap 之前完成加载。
html
<script src="https://sdk.crazygames.com/crazygames-sdk-v3.js"></script>如果动态加载脚本,请等待 完成定义后再调用。如果脚本被阻止(例如被 CSP 阻止), 全局变量将为 undefined——请将 添加到 指令中。
window.CrazyGames.SDK.initwindow.CrazyGamessdk.crazygames.comscript-srcInitialization
初始化
Call once. It resolves when the SDK is ready. Only after resolution are , , , , , and safe to use.
SDK.init()SDK.userSDK.dataSDK.adSDK.bannerSDK.gameSDK.analyticsjavascript
async function initCrazyGames() {
if (!window.CrazyGames?.SDK) {
throw new Error('CrazyGames SDK script not loaded');
}
const sdk = window.CrazyGames.SDK;
try {
await sdk.init();
} catch (err) {
throw new Error(`CrazyGames SDK init failed: ${err.message}`);
}
const isUserAccountAvailable = sdk.user.isUserAccountAvailable;
if (isUserAccountAvailable) {
const language = sdk.user.systemInfo.countryCode.toLowerCase();
const deviceType = sdk.user.systemInfo.device.type.toLowerCase(); // 'desktop' | 'mobile' | 'tablet'
console.log('lang/device', language, deviceType);
}
return sdk;
}调用一次 。SDK 就绪后,该调用会 resolve。只有在 resolve 之后,才能安全使用 、、、、 和 。
SDK.init()SDK.userSDK.dataSDK.adSDK.bannerSDK.gameSDK.analyticsjavascript
async function initCrazyGames() {
if (!window.CrazyGames?.SDK) {
throw new Error('CrazyGames SDK script not loaded');
}
const sdk = window.CrazyGames.SDK;
try {
await sdk.init();
} catch (err) {
throw new Error(`CrazyGames SDK init failed: ${err.message}`);
}
const isUserAccountAvailable = sdk.user.isUserAccountAvailable;
if (isUserAccountAvailable) {
const language = sdk.user.systemInfo.countryCode.toLowerCase();
const deviceType = sdk.user.systemInfo.device.type.toLowerCase(); // 'desktop' | 'mobile' | 'tablet'
console.log('lang/device', language, deviceType);
}
return sdk;
}Verification
验证
After calling , confirm the SDK is working before proceeding:
initCrazyGames()- Console check — no error should appear;
CrazyGames SDK init failedshould return a boolean without throwing.sdk.user.isUserAccountAvailable - Lifecycle hooks — open the CrazyGames sandbox URL for your game and verify that /
loadingStart/loadingStop/gameplayStartcalls appear in the CrazyGames developer dashboard event log.gameplayStop - Ad callbacks — use the CrazyGames sandbox environment (append to the URL) to trigger test ads and confirm
?crazygames_sandbox=1andadStartedfire correctly.adFinished - Adblock — call while running with an ad blocker enabled and confirm it resolves
sdk.ad.hasAdblock().true
调用 后,继续操作前请确认 SDK 正常工作:
initCrazyGames()- 控制台检查 — 不应出现 错误;
CrazyGames SDK init failed应返回布尔值且不抛出异常。sdk.user.isUserAccountAvailable - 生命周期钩子 — 打开游戏的 CrazyGames sandbox URL,并验证 /
loadingStart/loadingStop/gameplayStart调用出现在 CrazyGames 开发者控制台的事件日志中。gameplayStop - 广告回调 — 使用 CrazyGames sandbox 环境(在 URL 后附加 )触发测试广告,并确认
?crazygames_sandbox=1和adStarted正确触发。adFinished - 广告拦截 — 启用广告拦截器后运行游戏,调用 ,并确认其 resolve 为
sdk.ad.hasAdblock()。true
Player / Authorization
玩家 / 授权
Use to ask the player to sign in, then to read profile data, and optionally for a signed JWT to verify on your backend.
showAuthPrompt()getUser()getUserToken()javascript
async function authorizePlayer(sdk, { useUserToken = false } = {}) {
if (!sdk.user.isUserAccountAvailable) {
// Guest session — no auth possible on this domain
return null;
}
await sdk.user.showAuthPrompt();
const user = await sdk.user.getUser();
if (!user) {
return null;
}
const profile = {
name: user.username || null,
photo: user.profilePictureUrl || null,
extra: user
};
if (useUserToken) {
profile.extra.jwt = await sdk.user.getUserToken();
}
return profile;
}使用 提示玩家登录,然后使用 读取个人资料,并可选使用 获取已签名的 JWT,以便在后端进行验证。
showAuthPrompt()getUser()getUserToken()javascript
async function authorizePlayer(sdk, { useUserToken = false } = {}) {
if (!sdk.user.isUserAccountAvailable) {
// Guest session — no auth possible on this domain
return null;
}
await sdk.user.showAuthPrompt();
const user = await sdk.user.getUser();
if (!user) {
return null;
}
const profile = {
name: user.username || null,
photo: user.profilePictureUrl || null,
extra: user
};
if (useUserToken) {
profile.extra.jwt = await sdk.user.getUserToken();
}
return profile;
}Storage
存储
CrazyGames provides synchronous key/value storage via . Values are strings; serialize JSON yourself.
SDK.datajavascript
function storageSet(sdk, key, value) {
const data = typeof value === 'string' ? value : JSON.stringify(value);
sdk.data.setItem(key, data);
}
function storageGet(sdk, key, tryParseJson = true) {
const raw = sdk.data.getItem(key);
if (!tryParseJson || raw == null) {
return raw;
}
try {
return JSON.parse(raw);
} catch (_) {
return raw;
}
}
function storageRemove(sdk, key) {
sdk.data.removeItem(key);
}
// Batch helpers — just iterate, the SDK has no native multi-key API
function storageSetMany(sdk, keys, values) {
for (let i = 0; i < keys.length; i++) {
storageSet(sdk, keys[i], values[i]);
}
}CrazyGames 通过 提供同步键/值存储。值为字符串;请自行序列化 JSON。
SDK.datajavascript
function storageSet(sdk, key, value) {
const data = typeof value === 'string' ? value : JSON.stringify(value);
sdk.data.setItem(key, data);
}
function storageGet(sdk, key, tryParseJson = true) {
const raw = sdk.data.getItem(key);
if (!tryParseJson || raw == null) {
return raw;
}
try {
return JSON.parse(raw);
} catch (_) {
return raw;
}
}
function storageRemove(sdk, key) {
sdk.data.removeItem(key);
}
// Batch helpers — just iterate, the SDK has no native multi-key API
function storageSetMany(sdk, keys, values) {
for (let i = 0; i < keys.length; i++) {
storageSet(sdk, keys[i], values[i]);
}
}Advertisement
广告
Interstitial ad (midgame
)
midgame插页式广告 (midgame
)
midgameCall . The callbacks fire synchronously as the ad lifecycle progresses.
SDK.ad.requestAd('midgame', callbacks)javascript
function showInterstitial(sdk) {
sdk.ad.requestAd('midgame', {
adStarted: () => {
// Mute audio and pause the game here
},
adFinished: () => {
// Resume audio and gameplay here
},
adError: (error) => {
console.warn('interstitial failed', error);
}
});
}调用 。回调会在广告生命周期推进时同步触发。
SDK.ad.requestAd('midgame', callbacks)javascript
function showInterstitial(sdk) {
sdk.ad.requestAd('midgame', {
adStarted: () => {
// Mute audio and pause the game here
},
adFinished: () => {
// Resume audio and gameplay here
},
adError: (error) => {
console.warn('interstitial failed', error);
}
});
}Rewarded ad
激励广告
Same API, pass as the type. means the user watched to completion and should receive the reward.
'rewarded'adFinishedjavascript
function showRewarded(sdk, onReward) {
sdk.ad.requestAd('rewarded', {
adStarted: () => {
// Pause the game
},
adFinished: () => {
onReward();
},
adError: (error) => {
console.warn('rewarded failed', error);
}
});
}使用相同的 API,将 作为类型传入。 表示用户已完整观看广告,此时应发放奖励。
'rewarded'adFinishedjavascript
function showRewarded(sdk, onReward) {
sdk.ad.requestAd('rewarded', {
adStarted: () => {
// Pause the game
},
adFinished: () => {
onReward();
},
adError: (error) => {
console.warn('rewarded failed', error);
}
});
}Adblock detection
广告拦截检测
javascript
async function isAdblockActive(sdk) {
return sdk.ad.hasAdblock();
}javascript
async function isAdblockActive(sdk) {
return sdk.ad.hasAdblock();
}Responsive banners
响应式横幅广告
Banners are bound to existing DOM containers by id. CrazyGames renders into them and picks an appropriate size.
javascript
async function showBanner(sdk, containerId) {
// The container must already be in the DOM and visible
try {
await sdk.banner.requestResponsiveBanner([containerId]);
} catch (e) {
console.warn('banner failed', e);
}
}
async function showAdvancedBanners(sdk, containerIds) {
// Request several banners in parallel
await Promise.all(containerIds.map((id) => sdk.banner.requestResponsiveBanner(id)));
}
function hideBanners(sdk) {
sdk.banner.clearAllBanners();
}横幅广告通过 id 绑定到已有的 DOM 容器。CrazyGames 会将广告渲染到这些容器中,并选择合适的尺寸。
javascript
async function showBanner(sdk, containerId) {
// The container must already be in the DOM and visible
try {
await sdk.banner.requestResponsiveBanner([containerId]);
} catch (e) {
console.warn('banner failed', e);
}
}
async function showAdvancedBanners(sdk, containerIds) {
// Request several banners in parallel
await Promise.all(containerIds.map((id) => sdk.banner.requestResponsiveBanner(id)));
}
function hideBanners(sdk) {
sdk.banner.clearAllBanners();
}Lifecycle / gameplay events
生命周期 / 游戏事件
CrazyGames REQUIRES the host game to call gameplay and loading hooks at the right moments — they drive ad pacing, in-game UI dimming, and analytics.
Map generic game lifecycle events to SDK calls as follows:
| Game event | SDK call |
|---|---|
| |
| |
| |
| |
| |
There are no separate / / callbacks on the CrazyGames SDK — drive your audio and pause state from the ad callbacks ( / ) and the standard event.
audiopausevisibilityadStartedadFinisheddocument.visibilitychangeCrazyGames 要求宿主游戏在正确的时间调用 gameplay 和 loading 钩子——这些钩子用于控制广告节奏、游戏内 UI 变暗和 analytics。
将通用游戏生命周期事件映射到 SDK 调用,如下所示:
| 游戏事件 | SDK 调用 |
|---|---|
| |
| |
| |
| |
| |
CrazyGames SDK 没有独立的 / / 回调——应通过广告回调( / )和标准的 事件来驱动音频与暂停状态。
audiopausevisibilityadStartedadFinisheddocument.visibilitychangePayments (optional, via Xsolla Pay Station)
支付(可选,通过 Xsolla Pay Station)
Skip this section entirely if you do not have an Xsolla project ID. CrazyGames itself does not sell IAPs; this integration uses CrazyGames-issued Xsolla user tokens with the Xsolla Pay Station widget and Xsolla Store API.
Key constants:
javascript
const XSOLLA_PAYSTATION_EMBED_URL =
'https://cdn.xsolla.net/payments-bucket-prod/embed/1.5.0/widget.min.js';
const XSOLLA_SDK_URL = 'https://store.xsolla.com/api/v2/project';Obtain the Xsolla user token via . Use it as a token for all Xsolla Store API requests (catalog, purchase, inventory, consume).
sdk.user.getXsollaUserToken()BearerCatalog —
GET /{projectId}/items?limit=50Purchase flow:
- → returns
POST /{projectId}/payment/item/{sku}{ token, order_id } - Load dynamically if not already present
XSOLLA_PAYSTATION_EMBED_URL - then
XPayStationWidget.init({ access_token: token, sandbox: isSandbox }).open() - Listen for ; when
XPayStationWidget.eventTypes.STATUSmatchespaymentInfo.status, fetch/done|charged|success/iand callGET /{projectId}/order/{orderId}to record the purchasesdk.analytics.trackOrder('xsolla', order) - Listen for the event to handle cancellation
'close'
Inventory —
GET /{projectId}/user/inventory/itemsConsume — with
POST /{projectId}/user/inventory/item/consume{ sku, quantity }All fetch calls must include . Throw on non-OK responses. Use during development.
Authorization: Bearer <xsollaToken>isSandbox: true如果尚未拥有 Xsolla project ID,请完全跳过此节。 CrazyGames 本身不销售 IAP;此集成使用 CrazyGames 签发的 Xsolla user token,并结合 Xsolla Pay Station widget 和 Xsolla Store API。
关键常量:
javascript
const XSOLLA_PAYSTATION_EMBED_URL =
'https://cdn.xsolla.net/payments-bucket-prod/embed/1.5.0/widget.min.js';
const XSOLLA_SDK_URL = 'https://store.xsolla.com/api/v2/project';通过 获取 Xsolla user token。将其作为所有 Xsolla Store API 请求(catalog、purchase、inventory、consume)的 token 使用。
sdk.user.getXsollaUserToken()Bearer目录 —
GET /{projectId}/items?limit=50购买流程
- → 返回
POST /{projectId}/payment/item/{sku}{ token, order_id } - 如果尚未加载,则动态加载
XSOLLA_PAYSTATION_EMBED_URL - 执行 ,然后执行
XPayStationWidget.init({ access_token: token, sandbox: isSandbox }).open() - 监听 ;当
XPayStationWidget.eventTypes.STATUS匹配paymentInfo.status时,获取/done|charged|success/i,并调用GET /{projectId}/order/{orderId}记录购买sdk.analytics.trackOrder('xsolla', order) - 监听 事件以处理取消操作
'close'
库存 —
GET /{projectId}/user/inventory/items消耗 — ,请求内容为
POST /{projectId}/user/inventory/item/consume{ sku, quantity }所有 fetch 调用都必须包含 。对于非 OK 响应,请抛出异常。开发期间使用 。
Authorization: Bearer <xsollaToken>isSandbox: true