GameDev Guide
Глава 1114 мин чтенияПроверено: 5 сентября 2026 г.

Реклама внутри игры — interstitial, rewarded video и sticky-баннер

Подключим три рекламных формата SDK Яндекс Игр, обработаем стартовую рекламу платформы через game_api_pause и напишем модуль, который ставит звук и геймплей на паузу так, как требует пункт 4.7.

Содержание главы

У рекламы в Яндекс Играх неприятная асимметрия: кода — пятнадцать строк, требований — целый раздел. Пункт 4.4 отвечает за момент показа, 4.7 — за паузу звука и геймплея, 1.16 запрещает самодельные блоки, похожие на рекламные. Плюс одна деталь, которую пропускает почти каждое руководство: платформа показывает полноэкранную рекламу на старте вашей игры сама, без единой строчки вашего кода, — и обработать её всё равно придётся вам. Разберём все форматы, напишем модуль и пройдёмся по требованиям, на которых чаще всего спотыкаются.

Четыре рекламных сущности

Что этоКак вызываетсяКто решает, когда показать
Полноэкранный блок (interstitial)ysdk.adv.showFullscreenAdv()Игра вызывает, но частоту ограничивает платформа
Rewarded videoysdk.adv.showRewardedVideo()Игрок сам нажимает кнопку; частота не ограничена
Sticky-баннерshowBannerAdv() / hideBannerAdv()По умолчанию платформа; API включается в Консоли
Стартовая полноэкранная рекламаНикак — её нет в вашем кодеПлатформа, автоматически, на старте всех игр

Полноэкранный блок и блок с вознаграждением создаются автоматически при подключении монетизации в Консоли — руками их заводить не нужно. Ещё один факт из документации, полезный при отладке: реклама показывается только в онлайн-режиме. Играете без интернета — блоков не будет, и это не баг в вашем коде.

Полноэкранная реклама

Документированная форма вызова — объект с полем callbacks:

ysdk.adv.showFullscreenAdv({
  callbacks: {
    onOpen: () => console.log('Реклама открыта.'),
    onClose: (wasShown) => console.log(wasShown ? 'Показана и закрыта.' : 'Не показана.'),
    onError: (error) => console.error('Ошибка вызова.', error),
  },
});

Метод ничего не возвращает — весь результат приходит в колбэки. Ключевой из них onClose: по документации он вызывается при закрытии рекламы, после ошибки, а также если реклама не открылась из-за слишком частого вызова. То есть onClose — это единственная точка, которая срабатывает гарантированно, а wasShown === false — единственный доступный вам сигнал «показа не было».

Важно

Игра должна продолжаться одинаково при wasShown === true и wasShown === false. Если следующий уровень запускается только внутри «успешной» ветки, у части игроков игра просто зависнет на чёрном экране — это отказ по пункту 1.14 (игра не запускается / зависает).

Чтобы не размазывать логику по колбэкам, оберните вызов в промис. Обратите внимание на защиту от двойного разрешения: после onError документация обещает ещё и onClose.

// ads.js
export function showInterstitial(ysdk) {
  return new Promise((resolve) => {
    let settled = false;
    const finish = (wasShown) => {
      if (settled) return;
      settled = true;
      resolve(wasShown);
    };

    ysdk.adv.showFullscreenAdv({
      callbacks: {
        onClose: (wasShown) => finish(Boolean(wasShown)),
        onError: (error) => {
          console.error('[adv] fullscreen error', error);
          finish(false);
        },
      },
    });
  });
}

Использование — всегда после действия игрока, никогда не в середине геймплея:

async function onNextLevelClick() {
  await showInterstitial(ysdk); // Результат нужен только для аналитики.
  startLevel(currentLevel + 1); // Запускаем уровень в любом случае.
}

Кто управляет частотой показов

Здесь придётся разойтись с большей частью русскоязычных туториалов. В них обычно фигурирует «минимальный интервал 60 секунд», который предлагается отслеживать самому — через Date.now() и собственный таймер.

В актуальной документации никакого числового интервала нет. Проверено в сентябре 2026 года: на странице о рекламе сказано ровно две вещи — частота вызова rewarded video не ограничена, а частота вызова полноэкранного блока управляется платформой Яндекс Игры. В требованиях к расположению рекламы добавлено, что при слишком частом вызове в консоли браузера появится предупреждение.

Практический вывод: не стройте собственный тротлинг как источник истины. Правильная схема — вызывать полноэкранный блок в тех точках, где это уместно по пункту 4.4, и корректно обрабатывать wasShown === false. Платформа сама не покажет лишнего. Если вы всё же добавляете свой интервал (например, чтобы не дёргать SDK на каждом коротком уровне), относитесь к нему как к продуктовому решению, а не как к требованию платформы.

Частая ошибка

Показ рекламы по таймеру, оторванному от действий игрока, приведён в документации как «Пример неправильного вызова»:

setInterval(() => ysdk.adv.showFullscreenAdv(), 180000)

Рекламная сеть Яндекса считает случайные клики по блокам признаком рекламного фрода. Реклама, вылезающая посреди активного взаимодействия, гарантированно их порождает.

Rewarded video

Отличие одно, но принципиальное: награду выдаёт onRewarded, а не onClose.

export function showRewarded(ysdk) {
  return new Promise((resolve) => {
    let rewarded = false;
    let settled = false;
    const finish = () => {
      if (settled) return;
      settled = true;
      resolve(rewarded);
    };

    ysdk.adv.showRewardedVideo({
      callbacks: {
        onRewarded: () => { rewarded = true; },
        onClose: () => finish(),
        onError: (error) => {
          console.error('[adv] rewarded error', error);
          finish();
        },
      },
    });
  });
}
async function onExtraLifeClick() {
  const rewarded = await showRewarded(ysdk);
  if (rewarded) {
    grantExtraLife();
  } else {
    showToast('Реклама недоступна, попробуйте позже');
  }
}

onRewarded вызывается, когда просмотр засчитан, — именно в этот момент награда честно заработана. Если выдавать её в onClose, награду получит и тот, кто закрыл ролик на первой секунде.

Требования к кнопке тоже конкретные:

  • 4.5 — просмотр только по желанию игрока, например по нажатию специальной кнопки;
  • 4.5.1 — из текста или кнопки однозначно понятно, что сейчас будет реклама за вознаграждение и что именно игрок получит. «Получить 100 монет за просмотр рекламы» — да; иконка подарка без подписи — нет;
  • 4.5.2 — награда должна быть дополнительным бонусом (бустеры, дополнительные попытки, пропуск уровня) и не должна определять саму возможность продолжить игру.

Sticky-баннер

По умолчанию баннер появляется при запуске игры и висит всю сессию — от вас ничего не требуется, только настройка расположения в Консоли на вкладке Реклама (для мобильных — позиция в портретной и альбомной ориентации, для десктопа — включение показа справа).

Управлять им из кода можно, только если в той же вкладке включена опция Использовать API для показа sticky-баннера. Без неё методы вызовутся, но эффекта не будет.

const { stickyAdvIsShowing, reason } = await ysdk.adv.getBannerAdvStatus();

if (!stickyAdvIsShowing && !reason) {
  await ysdk.adv.showBannerAdv();
}

// Перед катсценой или на полноэкранном экране результатов:
await ysdk.adv.hideBannerAdv();

Все три метода возвращают промис с полем stickyAdvIsShowing, а getBannerAdvStatus() и showBannerAdv() — ещё и опциональное reason:

reasonЧто означает
ADV_IS_NOT_CONNECTEDБаннеры не подключены
UNKNOWNОшибка показа рекламы на стороне Яндекса

Полезное следствие: reason === 'ADV_IS_NOT_CONNECTED' в черновике — это обычно не ошибка кода, а незавершённая настройка монетизации.

Стартовая реклама платформы — то, что ломает игры

Платформа автоматически показывает полноэкранную рекламу на старте всех игр. У неё нет колбэков: вы не узнаете о ней ни из showFullscreenAdv, ни из какого-либо промиса. Единственный способ её отследить — события game_api_pause и game_api_resume.

Что это значит на практике: если ваша игра запускает музыку и игровой цикл сразу после загрузки, игрок услышит вашу музыку поверх рекламного ролика и вернётся в игру, где уже потерял тридцать секунд. Это нарушение пункта 4.7 и одна из причин отказа в собственном списке Яндекса.

Эти же события приходят при показе interstitial и rewarded, при открытии окна покупок, при переключении вкладок браузера и при сворачивании окна. То есть одна подписка закрывает сразу несколько требований — 1.3 (звук останавливается при потере фокуса) и 4.7.

// pause.js
let gameStarted = false;
let isPaused = false;

function handlePause() {
  isPaused = true;
  audioCtx.suspend();          // Web Audio API.
  cancelAnimationFrame(rafId); // Останавливаем игровой цикл.
}

function handleResume() {
  isPaused = false;
  audioCtx.resume();
  if (!gameStarted) {
    startGame();               // Стартовая реклама закончилась — только теперь запускаемся.
  } else {
    rafId = requestAnimationFrame(tick);
  }
}

export function initPause(ysdk) {
  ysdk.on('game_api_pause', handlePause);
  ysdk.on('game_api_resume', handleResume);

  // Если пауза уже пришла (идёт стартовая реклама) — ждём resume.
  if (!isPaused) startGame();
}

function startGame() {
  gameStarted = true;
  rafId = requestAnimationFrame(tick);
}

Отписаться при необходимости можно теми же именами: ysdk.off('game_api_pause', handlePause).

Совет

События согласованы с разметкой геймплея: при game_api_pause платформа сама вызывает GameplayAPI.stop(), при game_api_resumeGameplayAPI.start(). Дублировать эти вызовы вокруг рекламы не нужно. Причём если игра уже была остановлена вашим GameplayAPI.stop() (например, игрок открыл меню), то после game_api_resume метод start() не вызовется — состояние вашей разметки не сломается.

Собственную рекламу на старте (то есть свой вызов showFullscreenAdv сразу после загрузки) показывать можно, но только после срабатывания Game Ready — это прямая сноска в требованиях к расположению рекламы.

Когда показывать: пункт 4.4 в одной таблице

Вне игрового процесса — после запуска игры и после любого неигрового действия: выбор уровня, кнопки «Новый уровень», «Магазин», «Коллекция». Внутри игрового процесса всё зависит от механики и длины уровня:

Тип игрыУровни короче 5 минутУровни длиннее 5 минут
Условно-пошаговые (тесты, викторины, пазлы, merge)Сразу после действия игрока, без предупрежденияТак же
В реальном времениВнутри уровня нельзя — только после неигрового действияМожно в любой момент, но с паузой и предупреждением

Предупреждение — это заметная плашка с обратным отсчётом («Реклама через: 2, 1») длительностью 2 секунды, одна на один показ. Во время предупреждения и самой рекламы игра должна быть на паузе; анимацию «замораживать» не обязательно, главное — недоступность игровых действий.

Про задержку: максимальная допустимая задержка между действием игрока и началом рекламы — 0,33 секунды (330 мс). При этом модерация считает нарушением только явную задержку больше 2 секунд, а пограничные случаи проходят проверку. Ориентируйтесь на 0,33 с как на цель — то есть вызывайте рекламу в обработчике клика, а не после анимации перехода на 1,5 секунды.

Чего делать нельзя

ПунктЗапрет
4.1Реклама только через SDK Яндекс Игр; никаких сторонних рекламодателей, статичных баннеров и текстовых вставок
4.6.2Кастомные RTB-баннеры запрещены; дополнительными блоками считаются только sticky-баннеры
1.16Нельзя модифицировать блоки и имитировать их — свой «полноэкранный блок» или RV со своими кнопками
4.7Звук и геймплей обязаны ставиться на паузу на время interstitial и rewarded
4.3Ориентация рекламных блоков соответствует ориентации игры
4.2Внутренний прогресс сохраняется после перехода по рекламе и возврата обратно

Отдельно: если в игре продаётся отключение рекламы, после покупки её действительно не должно быть — включая sticky-баннер.

Осторожно

«Звук в игре не ставится на паузу во время показа рекламы» — пункт из официальной таблицы частых причин отказа. Проверяется он за десять секунд: модератор открывает игру в наушниках. Один общий модуль паузы, подписанный на game_api_pause, снимает этот риск целиком.

Как проверить перед отправкой

Реклама не работает в локальном запуске «просто из папки» — нужна реальная платформа. Документация предлагает два способа: prod-окружение (локальный запуск с проксированием на боевой SDK) и режим черновика в Консоли. В обоих случаях показывается настоящая реклама.

Минимальный прогон:

  • Открыть игру и ничего не трогать: дождаться стартовой рекламы платформы. Музыки поверх ролика быть не должно, после закрытия игра начинается с начала.
  • Вызвать interstitial дважды подряд — второй раз, скорее всего, придёт wasShown === false. Игра должна продолжиться так же, как при true.
  • Нажать кнопку rewarded и закрыть ролик досрочно — награды быть не должно.
  • Посмотреть ролик до конца — награда выдана ровно один раз.
  • Переключить вкладку браузера во время игры — звук замолкает, цикл останавливается.
  • Перейти по рекламному объявлению и вернуться — прогресс на месте (пункт 4.2).
  • Проверить консоль: предупреждений о слишком частом вызове быть не должно.

Что дальше

Реклама — половина монетизации, и та половина, где вы не управляете почти ничем: ни ценой показа, ни частотой. Вторая половина — внутриигровые покупки: там вы задаёте каталог, цену и логику выдачи товара, но и требований к корректности больше — от обязательного консумирования до запрета хардкодить название и иконку валюты. Ими и займёмся в следующей главе.

Источники

Официальная документация платформы — единственный источник истины по её требованиям.

Нужно подробнее?

Полное обучение разбирает те же темы глубже: уроки с примерами, готовые структуры проектов, развёрнутые чек-листы и файл инструкций для Claude Code — он входит в стоимость. Бесплатные главы при этом остаются открытыми и продолжают дополняться.

Что входит в полное обучение