yandex-js-sdk

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Yandex Games JavaScript SDK

Yandex Games JavaScript SDK

Overview

概述

Yandex Games loads games inside a frame on
yandex.<tld>/games
. The host injects the
YaGames
global once the SDK script is loaded. Key capability areas:
  • Lifecycle & environment: init,
    LoadingAPI.ready()
    ,
    GameplayAPI.start/stop
    , pause/resume events, device info, language/TLD
  • Player & storage: authorization, profile data, per-player key/value cloud storage
  • Monetization: fullscreen interstitial, rewarded video, sticky banner ads, in-app purchases
  • Engagement: leaderboards, remote config flags, review prompt, add-to-home-screen shortcut, server time, clipboard write, cross-promotion via
    GamesAPI
The SDK does NOT expose social share, invite-friends, community-join, add-to-favorites, achievements, or stat counters.
Yandex Games 会在
yandex.<tld>/games
的 iframe 中加载游戏。SDK 脚本加载完成后,宿主页面会注入
YaGames
全局变量。主要能力领域包括:
  • 生命周期与运行环境:init、
    LoadingAPI.ready()
    、
    GameplayAPI.start/stop
    、暂停/恢复事件、设备信息、语言/TLD
  • 玩家与存储:授权、个人资料、按玩家存储的键值云存储
  • 商业变现:全屏插页广告、激励视频、常驻横幅广告、应用内购买
  • 用户互动:排行榜、远程配置标志、评价提示、添加到主屏幕快捷方式、服务器时间、剪贴板写入、通过
    GamesAPI
    进行交叉推广
SDK 不提供社交分享、邀请好友、加入社区、收藏、成就或统计计数器功能。

Installation

安装

html
<script src="https://yandex.ru/games/sdk/v2"></script>
If loaded dynamically, poll until
window.YaGames && window.YaGames.init
is defined before calling
init()
.
html
<script src="https://yandex.ru/games/sdk/v2"></script>
如果通过动态方式加载,应轮询检查
window.YaGames && window.YaGames.init
,确认已定义后再调用
init()
。

Quick Start / Integration Workflow

快速开始 / 集成工作流

Follow this sequence when wiring up the SDK for the first time. Verify each step before proceeding to the next.
javascript
async function bootstrap() {
    // 1. Ensure SDK script has loaded
    if (!window.YaGames?.init) {
        throw new Error('YaGames SDK not available — check that the script tag loaded');
    }

    // 2. Initialize — all subsequent SDK calls require ysdk
    const ysdk = await window.YaGames.init();

    // 3. Bind host-driven pause / resume before anything else
    ysdk.on('game_api_pause', () => {
        /* mute audio, pause gameplay */
    });
    ysdk.on('game_api_resume', () => {
        /* unmute, resume */
    });

    // 4. Signal that the loading screen is gone
    ysdk.features.LoadingAPI?.ready();

    // 5. Read environment (language, device type)
    const env = readEnvironment(ysdk);

    // 6. Fetch player — fall back to guest mode if not authorized
    let player = null;
    let storageCache = {};
    try {
        const info = await getPlayer(ysdk);
        player = info.raw;
        if (info.isAuthorized) {
            storageCache = await loadStorage(player);
        }
    } catch (err) {
        console.warn('Player init failed, continuing as guest:', err);
    }

    // 7. Start gameplay tracking
    onGameplayStarted(ysdk);

    return { ysdk, player, storageCache, env };
}
javascript
function readEnvironment(ysdk) {
    return {
        language: ysdk.environment.i18n.lang.toLowerCase(),
        tld: ysdk.environment.i18n.tld.toLowerCase(),
        deviceType: ysdk.deviceInfo.type // 'desktop' | 'mobile' | 'tablet' | 'tv'
    };
}
首次接入 SDK 时,请按照以下顺序操作。完成每一步的验证后,再继续下一步。
javascript
async function bootstrap() {
    // 1. Ensure SDK script has loaded
    if (!window.YaGames?.init) {
        throw new Error('YaGames SDK not available — check that the script tag loaded');
    }

    // 2. Initialize — all subsequent SDK calls require ysdk
    const ysdk = await window.YaGames.init();

    // 3. Bind host-driven pause / resume before anything else
    ysdk.on('game_api_pause', () => {
        /* mute audio, pause gameplay */
    });
    ysdk.on('game_api_resume', () => {
        /* unmute, resume */
    });

    // 4. Signal that the loading screen is gone
    ysdk.features.LoadingAPI?.ready();

    // 5. Read environment (language, device type)
    const env = readEnvironment(ysdk);

    // 6. Fetch player — fall back to guest mode if not authorized
    let player = null;
    let storageCache = {};
    try {
        const info = await getPlayer(ysdk);
        player = info.raw;
        if (info.isAuthorized) {
            storageCache = await loadStorage(player);
        }
    } catch (err) {
        console.warn('Player init failed, continuing as guest:', err);
    }

    // 7. Start gameplay tracking
    onGameplayStarted(ysdk);

    return { ysdk, player, storageCache, env };
}
javascript
function readEnvironment(ysdk) {
    return {
        language: ysdk.environment.i18n.lang.toLowerCase(),
        tld: ysdk.environment.i18n.tld.toLowerCase(),
        deviceType: ysdk.deviceInfo.type // 'desktop' | 'mobile' | 'tablet' | 'tv'
    };
}

Player / Authorization

玩家 / 授权

javascript
async function getPlayer(ysdk, { useSignedData = false } = {}) {
    const player = await ysdk.getPlayer({ signed: useSignedData });

    return {
        raw: player,
        id: player.getUniqueID(),
        name: player.getName() || null,
        photos: ['small', 'medium', 'large'].map((size) => player.getPhoto(size)).filter(Boolean),
        isAuthorized: player.isAuthorized(),
        payingStatus: player.getPayingStatus(),
        signature: useSignedData ? player.signature : null
    };
}

async function authorizePlayer(ysdk, options) {
    const current = await getPlayer(ysdk, options);
    if (current.isAuthorized) {
        return current;
    }

    await ysdk.auth.openAuthDialog();
    return getPlayer(ysdk, options);
}
javascript
async function getPlayer(ysdk, { useSignedData = false } = {}) {
    const player = await ysdk.getPlayer({ signed: useSignedData });

    return {
        raw: player,
        id: player.getUniqueID(),
        name: player.getName() || null,
        photos: ['small', 'medium', 'large'].map((size) => player.getPhoto(size)).filter(Boolean),
        isAuthorized: player.isAuthorized(),
        payingStatus: player.getPayingStatus(),
        signature: useSignedData ? player.signature : null
    };
}

async function authorizePlayer(ysdk, options) {
    const current = await getPlayer(ysdk, options);
    if (current.isAuthorized) {
        return current;
    }

    await ysdk.auth.openAuthDialog();
    return getPlayer(ysdk, options);
}

Storage

存储

Every call writes the full document — there is no per-key API. Cache the latest snapshot client-side and merge before each save. Fall back to
localStorage
for guests.
javascript
async function loadStorage(player) {
    return player.getData();
}

async function setStorage(player, cache, key, value) {
    const data = { ...(cache || {}) };
    if (Array.isArray(key)) {
        for (let i = 0; i < key.length; i++) {
            data[key[i]] = value[i];
        }
    } else {
        data[key] = value;
    }
    await player.setData(data);
    return data;
}

async function deleteStorage(player, cache, key) {
    const data = { ...(cache || {}) };
    if (Array.isArray(key)) {
        for (let i = 0; i < key.length; i++) {
            delete data[key[i]];
        }
    } else {
        delete data[key];
    }
    await player.setData(data);
    return data;
}

function getCached(cache, key) {
    if (Array.isArray(key)) {
        return key.map((k) => (typeof cache?.[k] === 'undefined' ? null : cache[k]));
    }
    return typeof cache?.[key] === 'undefined' ? null : cache[key];
}
每次调用都会写入完整文档,没有按单个 key 操作的 API。应在客户端缓存最新快照,并在每次保存前进行合并。访客用户应回退到
localStorage
。
javascript
async function loadStorage(player) {
    return player.getData();
}

async function setStorage(player, cache, key, value) {
    const data = { ...(cache || {}) };
    if (Array.isArray(key)) {
        for (let i = 0; i < key.length; i++) {
            data[key[i]] = value[i];
        }
    } else {
        data[key] = value;
    }
    await player.setData(data);
    return data;
}

async function deleteStorage(player, cache, key) {
    const data = { ...(cache || {}) };
    if (Array.isArray(key)) {
        for (let i = 0; i < key.length; i++) {
            delete data[key[i]];
        }
    } else {
        delete data[key];
    }
    await player.setData(data);
    return data;
}

function getCached(cache, key) {
    if (Array.isArray(key)) {
        return key.map((k) => (typeof cache?.[k] === 'undefined' ? null : cache[k]));
    }
    return typeof cache?.[key] === 'undefined' ? null : cache[key];
}

Advertisement

广告

Fullscreen interstitial

全屏插页广告

onClose(wasShown)
fires on both normal close and SDK-skipped ads. Treat
wasShown === false
as a failure.
javascript
function showInterstitial(ysdk, handlers = {}) {
    ysdk.adv.showFullscreenAdv({
        callbacks: {
            onOpen: () => handlers.onOpen?.(),
            onClose: (wasShown) => handlers.onClose?.(wasShown),
            onError: (err) => handlers.onError?.(err)
        }
    });
}
onClose(wasShown)
会在正常关闭和 SDK 跳过广告时触发。应将
wasShown === false
视为失败。
javascript
function showInterstitial(ysdk, handlers = {}) {
    ysdk.adv.showFullscreenAdv({
        callbacks: {
            onOpen: () => handlers.onOpen?.(),
            onClose: (wasShown) => handlers.onClose?.(wasShown),
            onError: (err) => handlers.onError?.(err)
        }
    });
}

Rewarded video

激励视频

Grant the reward inside
onRewarded
.
onClose
fires after the ad UI is dismissed.
javascript
function showRewarded(ysdk, handlers = {}) {
    ysdk.adv.showRewardedVideo({
        callbacks: {
            onOpen: () => handlers.onOpen?.(),
            onRewarded: () => handlers.onRewarded?.(),
            onClose: () => handlers.onClose?.(),
            onError: (err) => handlers.onError?.(err)
        }
    });
}
应在
onRewarded
中发放奖励。
onClose
会在广告界面关闭后触发。
javascript
function showRewarded(ysdk, handlers = {}) {
    ysdk.adv.showRewardedVideo({
        callbacks: {
            onOpen: () => handlers.onOpen?.(),
            onRewarded: () => handlers.onRewarded?.(),
            onClose: () => handlers.onClose?.(),
            onError: (err) => handlers.onError?.(err)
        }
    });
}

Sticky banner

常驻横幅广告

javascript
async function getBannerStatus(ysdk) {
    return ysdk.adv.getBannerAdvStatus(); // { stickyAdvIsShowing: boolean, reason?: string }
}

async function showBanner(ysdk) {
    const data = await ysdk.adv.showBannerAdv();
    return data.stickyAdvIsShowing === true;
}

async function hideBanner(ysdk) {
    const data = await ysdk.adv.hideBannerAdv();
    return data.stickyAdvIsShowing === false;
}
javascript
async function getBannerStatus(ysdk) {
    return ysdk.adv.getBannerAdvStatus(); // { stickyAdvIsShowing: boolean, reason?: string }
}

async function showBanner(ysdk) {
    const data = await ysdk.adv.showBannerAdv();
    return data.stickyAdvIsShowing === true;
}

async function hideBanner(ysdk) {
    const data = await ysdk.adv.hideBannerAdv();
    return data.stickyAdvIsShowing === false;
}

Payments / IAP

支付 / IAP

Obtain the payments object once after init. Pass
signed: true
for backend signature validation.
javascript
async function initPayments(ysdk, { signed = true } = {}) {
    return ysdk.getPayments({ signed });
}
初始化后获取一次 payments 对象。传入
signed: true
以进行后端签名验证。
javascript
async function initPayments(ysdk, { signed = true } = {}) {
    return ysdk.getPayments({ signed });
}

Catalog

商品目录

javascript
async function getCatalog(payments) {
    const products = await payments.getCatalog();
    return products.map((p) => ({
        id: p.id,
        title: p.title,
        description: p.description,
        imageURI: p.imageURI,
        price: p.price,
        priceValue: p.priceValue,
        priceCurrencyCode: p.priceCurrencyCode,
        priceCurrencyImage: p.getPriceCurrencyImage?.('medium')
    }));
}
javascript
async function getCatalog(payments) {
    const products = await payments.getCatalog();
    return products.map((p) => ({
        id: p.id,
        title: p.title,
        description: p.description,
        imageURI: p.imageURI,
        price: p.price,
        priceValue: p.priceValue,
        priceCurrencyCode: p.priceCurrencyCode,
        priceCurrencyImage: p.getPriceCurrencyImage?.('medium')
    }));
}

Purchase

购买

javascript
async function purchase(payments, productId, payload) {
    const result = await payments.purchase({ id: productId, developerPayload: payload });
    if (!result?.purchaseData?.purchaseToken) {
        throw new Error(
            `Purchase succeeded but returned no purchaseToken for product ${productId}`
        );
    }
    return { id: productId, ...result.purchaseData };
}
javascript
async function purchase(payments, productId, payload) {
    const result = await payments.purchase({ id: productId, developerPayload: payload });
    if (!result?.purchaseData?.purchaseToken) {
        throw new Error(
            `Purchase succeeded but returned no purchaseToken for product ${productId}`
        );
    }
    return { id: productId, ...result.purchaseData };
}

Owned purchases

已购买的商品

javascript
async function getPurchases(payments) {
    const list = await payments.getPurchases();
    return list.map((purchase) => ({ id: purchase.productID, ...purchase.purchaseData }));
}
javascript
async function getPurchases(payments) {
    const list = await payments.getPurchases();
    return list.map((purchase) => ({ id: purchase.productID, ...purchase.purchaseData }));
}

Consume

消耗

Verify the item was granted before consuming. A failed consume leaves the token intact for retry.
javascript
async function consumePurchase(payments, purchaseToken) {
    if (!purchaseToken) {
        throw new Error('consumePurchase: purchaseToken is required');
    }
    await payments.consumePurchase(purchaseToken);
}
消耗前请确认物品已发放。消耗失败时,token 会保持有效,以便重试。
javascript
async function consumePurchase(payments, purchaseToken) {
    if (!purchaseToken) {
        throw new Error('consumePurchase: purchaseToken is required');
    }
    await payments.consumePurchase(purchaseToken);
}

Leaderboards

排行榜

Boards are configured in the developer console and referenced by string id. Setting a score requires an authorized player.
javascript
async function setLeaderboardScore(ysdk, leaderboardId, score) {
    const lb = await ysdk.getLeaderboards();
    await lb.setLeaderboardScore(leaderboardId, score);
}

async function getLeaderboardEntries(ysdk, leaderboardId, { isPlayerAuthorized = false } = {}) {
    const lb = await ysdk.getLeaderboards();

    const options = { quantityTop: 20 };
    if (isPlayerAuthorized) {
        options.includeUser = true;
        options.quantityAround = 3;
    }

    const result = await lb.getLeaderboardEntries(leaderboardId, options);
    if (!result || result.entries.length === 0) {
        return [];
    }

    return result.entries.map((e) => ({
        id: e.player.uniqueID,
        name: e.player.publicName,
        score: e.score,
        rank: e.rank,
        photo: e.player.getAvatarSrc('large')
    }));
}
排行榜在开发者控制台中配置,并通过字符串 id 引用。设置分数需要玩家已授权。
javascript
async function setLeaderboardScore(ysdk, leaderboardId, score) {
    const lb = await ysdk.getLeaderboards();
    await lb.setLeaderboardScore(leaderboardId, score);
}

async function getLeaderboardEntries(ysdk, leaderboardId, { isPlayerAuthorized = false } = {}) {
    const lb = await ysdk.getLeaderboards();

    const options = { quantityTop: 20 };
    if (isPlayerAuthorized) {
        options.includeUser = true;
        options.quantityAround = 3;
    }

    const result = await lb.getLeaderboardEntries(leaderboardId, options);
    if (!result || result.entries.length === 0) {
        return [];
    }

    return result.entries.map((e) => ({
        id: e.player.uniqueID,
        name: e.player.publicName,
        score: e.score,
        rank: e.rank,
        photo: e.player.getAvatarSrc('large')
    }));
}

Remote config

远程配置

ysdk.getFlags(options)
returns a flat
{ key: stringValue }
map.
javascript
async function getRemoteConfig(ysdk, options = {}) {
    const params = { clientFeatures: [], ...options };
    return ysdk.getFlags(params);
}
ysdk.getFlags(options)
返回扁平的
{ key: stringValue }
映射。
javascript
async function getRemoteConfig(ysdk, options = {}) {
    const params = { clientFeatures: [], ...options };
    return ysdk.getFlags(params);
}

Server time

服务器时间

javascript
function getServerTime(ysdk) {
    // Returns Unix timestamp in milliseconds
    return ysdk.serverTime();
}
javascript
function getServerTime(ysdk) {
    // Returns Unix timestamp in milliseconds
    return ysdk.serverTime();
}

Social

社交

Review prompt

评价提示

javascript
async function requestReview(ysdk) {
    const can = await ysdk.feedback.canReview();
    if (!can.value) {
        throw new Error(can.reason || 'review not available');
    }
    const { feedbackSent } = await ysdk.feedback.requestReview();
    return feedbackSent;
}
javascript
async function requestReview(ysdk) {
    const can = await ysdk.feedback.canReview();
    if (!can.value) {
        throw new Error(can.reason || 'review not available');
    }
    const { feedbackSent } = await ysdk.feedback.requestReview();
    return feedbackSent;
}

Add to home screen (shortcut)

添加到主屏幕(快捷方式)

javascript
async function canAddToHomeScreen(ysdk) {
    const prompt = await ysdk.shortcut.canShowPrompt();
    return prompt.canShow === true;
}

async function addToHomeScreen(ysdk) {
    const result = await ysdk.shortcut.showPrompt();
    return result.outcome === 'accepted';
}
javascript
async function canAddToHomeScreen(ysdk) {
    const prompt = await ysdk.shortcut.canShowPrompt();
    return prompt.canShow === true;
}

async function addToHomeScreen(ysdk) {
    const result = await ysdk.shortcut.showPrompt();
    return result.outcome === 'accepted';
}

Clipboard

剪贴板

javascript
async function clipboardWrite(ysdk, text) {
    await ysdk.clipboard.writeText(text);
}
javascript
async function clipboardWrite(ysdk, text) {
    await ysdk.clipboard.writeText(text);
}

Gameplay lifecycle, pause and audio

游戏生命周期、暂停与音频

Bracket every active gameplay session with
GameplayAPI.start()
/
GameplayAPI.stop()
to drive ad pacing and analytics.
javascript
function onGameplayStarted(ysdk) {
    ysdk.features.GameplayAPI?.start();
}

function onGameplayStopped(ysdk) {
    ysdk.features.GameplayAPI?.stop();
}
javascript
function bindPauseHandlers(ysdk, { onPause, onResume }) {
    ysdk.on('game_api_pause', () => onPause?.());
    ysdk.on('game_api_resume', () => onResume?.());
}
Visibility/focus changes not announced by Yandex should still be handled with
document.visibilitychange
,
window.blur
, and
window.focus
alongside these SDK callbacks.
使用
GameplayAPI.start()
/
GameplayAPI.stop()
包裹每次活跃的游戏会话,以控制广告节奏并支持分析。
javascript
function onGameplayStarted(ysdk) {
    ysdk.features.GameplayAPI?.start();
}

function onGameplayStopped(ysdk) {
    ysdk.features.GameplayAPI?.stop();
}
javascript
function bindPauseHandlers(ysdk, { onPause, onResume }) {
    ysdk.on('game_api_pause', () => onPause?.());
    ysdk.on('game_api_resume', () => onResume?.());
}
除了这些 SDK 回调,还应通过
document.visibilitychange
、
window.blur
和
window.focus
处理 Yandex 未通知的可见性或焦点变化。

Catalog of other Yandex Games (optional)

其他 Yandex Games 的目录(可选)

features.GamesAPI
is gated on availability per game; check for the namespace before calling it.
javascript
async function getAllGames(ysdk) {
    const { games } = await ysdk.features.GamesAPI.getAllGames();
    return games;
}

async function getGameById(ysdk, gameId) {
    const { game, isAvailable } = await ysdk.features.GamesAPI.getGameByID(gameId);
    return { ...game, isAvailable };
}
features.GamesAPI
是否可用取决于具体游戏;调用前请检查该命名空间。
javascript
async function getAllGames(ysdk) {
    const { games } = await ysdk.features.GamesAPI.getAllGames();
    return games;
}

async function getGameById(ysdk, gameId) {
    const { game, isAvailable } = await ysdk.features.GamesAPI.getGameByID(gameId);
    return { ...game, isAvailable };
}