ibiza
CPM · CTR …
/

Кеширование рекламы: предзагрузка, кеш ставок и bid.exp

≈ 8 мин чтения · обновлено

Кеширование рекламы — это хранение объявления, ставки или креатива между запросом и показом, чтобы реклама появлялась мгновенно. Оно поднимает видимость и доход, но у каждой ставки есть срок годности: показ после него покупатель может не учесть. Правило простое: кешировать креативы и статику, предзагружать полноэкранные форматы в пределах bid.exp, а трекеры и уведомления не кешировать никогда.

Четыре разных кеша в рекламе

Под словом «кеш» в рекламе прячутся четыре разные вещи с разными рисками.

Что хранится Где Зачем Главный риск
Загруженное объявление (ответ аукциона + креатив) SDK в приложении Показать interstitial или rewarded без ожидания Ставка устарела к моменту показа
Ставки прошлых аукционов Обертка header bidding в браузере Не терять хорошую ставку, которая не была показана Показ по ставке с истекшим TTL
VAST-разметка видео Сервер кеша (например, Prebid Cache) Дать плееру URL вместо длинного XML Ключ кеша истек раньше показа
Креативы и статика Браузер, CDN, HTTP-кеш SDK Быстрая отрисовка Закешировали то, что должно быть уникальным

Первые три — про деньги и сроки, последний — про скорость. Ошибки в них разные, поэтому разберем по очереди.

Предзагрузка в SDK: interstitial и rewarded

Полноэкранная реклама почти всегда загружается заранее. Если запрашивать interstitial в момент паузы в игре, пользователь будет ждать аукцион, загрузку креатива и отрисовку — и часть просто уйдет. Поэтому рекламные SDK разделяют два шага:

// Шаг 1: заранее, например, в начале уровня
interstitial.load(placementKey, listener)

// Шаг 2: в естественной паузе
if (interstitial.isReady) interstitial.show()

Правила, которые стоит соблюдать:

  • Показ считается при показе, а не при загрузке. Пиксели показа и уведомление о биллинге burl должны срабатывать, когда объявление отрисовано на экране. Если SDK шлет их при загрузке, отчеты будут расходиться с покупателем.
  • Одно загруженное объявление — один показ. После show() нужна новая загрузка, а не повтор того же креатива.
  • Держать не больше, чем покажете. Загрузить пять объявлений «про запас» — значит пять раз выиграть аукцион и, скорее всего, не показать четыре из них до истечения срока.
  • Следить за возрастом. Если объявление пролежало дольше срока годности, его выбрасывают и загружают заново.

Для rewarded video все то же самое, плюс видеофайл нужно скачать до показа, иначе награда «за просмотр» превращается в просмотр индикатора загрузки.

Срок годности ставки: imp.exp и bid.exp

OpenRTB дает для этого два поля, оба есть и в версии 2.5, и в 2.6:

  • imp.exp в запросе — сколько секунд, по оценке биржи, может пройти между аукционом и показом;
  • bid.exp в ответе — сколько секунд покупатель готов ждать между аукционом и показом.
{
  "id": "resp-1",
  "seatbid": [{
    "bid": [{
      "id": "b-1",
      "impid": "1",
      "price": 210.0,
      "exp": 1800,
      "burl": "https://dsp.example/bill?a=${AUCTION_ID}&p=${AUCTION_PRICE}"
    }]
  }],
  "cur": "RUB"
}

Почему это важно покупателю: по уведомлению о показе DSP списывает бюджет, считает частоту и регулирует темп открутки. Если уведомление приходит через час после аукциона, бюджет на этот час уже распределен по другим показам, а частотное ограничение могло быть пройдено. Поэтому в заметках к OpenRTB IAB советует покупателям отслеживать время между аукционом и уведомлением о показе и разбираться с биржей, если задержки систематические.

Ориентиры из тех же заметок IAB к OpenRTB (раздел «Impression Expiration») — именно ориентиры, не правило:

Тип показа Разумная задержка
Веб на десктопе и в мобильном браузере 1 минута
Баннер в приложении, который может кешироваться 5 минут
Нативная реклама в приложении 10 минут
Полноэкранная реклама и видео 30 минут и больше

Важная оговорка спецификации: истекший bid.exp не означает автоматически, что показ не оплатят, — это вопрос договора между биржей и покупателем. Но если покупатель отбрасывает запоздавшие уведомления, у паблишера показ есть, а у покупателя его нет. Так рождается расхождение, разобранное в статье про сверку показов и биллинга.

Пример: сколько стоит устаревший кеш

Иллюстративный пример. Игра предзагружает interstitial в начале уровня, ставка пришла с exp = 1800 секунд. Средний уровень длится 12 минут — показ укладывается. Но 15% игроков проходят уровень дольше 30 минут или сворачивают игру. Если SDK показывает им старое объявление, 15% показов рискуют остаться без учета у покупателя. Если SDK проверяет возраст и запрашивает новое объявление, эти показы проходят новый аукцион и учитываются. Цена решения — лишний запрос и короткая задержка у малой доли пользователей.

Кеш ставок в header bidding

В вебе ставки хранятся в обертке header bidding. В Prebid.js за это отвечает настройка useBidCache. С версии 2.0 она выключена по умолчанию; если включить, ставка, которая не была показана в прошлом аукционе, может участвовать в следующем — но только для того же рекламного места, на той же странице и до истечения своего TTL. Перезагрузка страницы кеш очищает.

pbjs.setConfig({
  useBidCache: true,
  // не переиспользовать видеоставки: их VAST мог истечь в кеше раньше
  bidCacheFilterFunction: bid => bid.mediaType !== 'video',
  ttlBuffer: 5 // секунд запаса до истечения TTL ставки
});

Срок жизни каждой ставки задает адаптер партнера. По документации Prebid ядро по умолчанию вычитает из него секунду запаса (ttlBuffer), так что ставка с TTL 30 секунд считается истекшей через 29. Не путайте это с minBidCacheTTL: он управляет тем, сколько ставки лежат в памяти для аналитики, а не тем, сколько их можно показывать.

Когда кеш ставок полезен: при рефреше рекламы и ленивой загрузке, когда одно место запрашивает рекламу несколько раз за визит. Когда вреден: если ставки живут долго, а покупатель ждет быстрый показ, — тогда выигрывает старая цена, а уведомление приходит с опозданием.

Кеш VAST для видео

VAST-ответ видеоставки — XML на десятки килобайт. Передавать его через ключи таргетинга рекламного сервера неудобно, поэтому Prebid отправляет XML на сервер кеша (cache.url в настройках — Prebid Cache или совместимый сервис) и получает ключ videoCacheKey. Плеер затем загружает VAST по URL с этим ключом.

Здесь два срока: TTL ставки и TTL записи в кеше. Если запись живет меньше, чем ставка, плеер получит пустой ответ на вполне «живую» ставку. Срок хранения в кеше должен быть не меньше срока ставки плюс время, нужное плееру на запуск.

HTTP и CDN: скорость, которая превращается в деньги

Креатив, который грузится полторы секунды, успевают пролистать. Цепочка простая: медленная загрузка — ниже видимость — ниже ставки покупателей на это место. Что кешировать агрессивно:

  • изображения, шрифты, скрипты рендеринга с хешем версии в имени файла — Cache-Control: public, max-age=31536000, immutable;
  • медиафайлы видео на CDN рядом с пользователем;
  • в SDK — шаблоны отрисовки нативной рекламы, чтобы не тянуть их на каждый показ.

Что держать коротким или не кешировать: HTML-разметку объявления с подставленными макросами, конфигурацию рекламных мест, которую меняют из админки, и любые ответы аукциона.

Что кешировать нельзя

Объект Почему Как защитить
Пиксель показа, кликовый трекер Повторный показ не дойдет до сервера и не будет учтен Cache-Control: no-store, уникальный параметр в URL
nurl, burl, lurl Это уведомления о конкретном аукционе Вызывать один раз на событие, без кеша
URL с уникальными макросами (${AUCTION_ID}, метка времени, случайное число) Кеш подставит значение чужого аукциона Подстановку делать при показе, не при загрузке
Ответ аукциона Цена и креатив действительны для одного показа no-store на ответах биржи и SDK-шлюза

Сервер трекинга должен отвечать так, чтобы ни браузер, ни прокси не сохранили ответ:

HTTP/1.1 200 OK
Content-Type: image/gif
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0

Cache-busting — защита со стороны URL: в адрес пикселя добавляют случайное число или метку времени (в VAST для этого есть макрос [CACHEBUSTING], у рекламных серверов — свои аналоги), чтобы каждый вызов выглядел для кеша новым адресом. Это страховка на случай промежуточных прокси, которые игнорируют заголовки.

Важно. Кешировать можно креатив, но не событие. Пока это правило соблюдается, кеширование почти всегда дает плюс в скорости и видимости.

Как выбрать срок жизни кеша и что мерить

Срок, сколько SDK держит загруженное объявление, выбирают от ставки, а не от удобства разработчика:

  1. Если в ответе есть bid.exp, срок кеша не длиннее него минус запас на отрисовку.
  2. Если bid.exp нет, берут ориентиры IAB для своего формата или договоренность с биржей.
  3. По истечении срока объявление выбрасывают и в фоне загружают новое, не дожидаясь момента показа.
  4. Следующее объявление загружают сразу после показа предыдущего, если пауза в приложении будет скоро.

Чтобы видеть, работает ли схема, полезны четыре метрики:

Метрика Что показывает
Возраст объявления в момент показа (медиана и p95) Укладывается ли показ в срок ставки
Доля выброшенных по сроку Не загружаете ли вы рекламу слишком рано
Доля показов «без готовой рекламы» Не слишком ли поздно стартует загрузка
Расхождение показов с покупателем Срабатывают ли трекеры при показе

Типичные ошибки кеширования

  • Пиксели при загрузке, а не при показе. У паблишера показов больше, чем у покупателя, на долю непоказанных предзагрузок.
  • Нет проверки возраста. Полноэкранное объявление показывают через сутки после аукциона.
  • Одна загрузка — два показа. Повторный показ того же объявления без нового аукциона.
  • Кеш VAST короче TTL ставки. Выигранная ставка без видео.
  • CDN кеширует трекер. Пропадают показы у части пользователей за корпоративными прокси.

Предзагрузка и кеш в Ibiza

Android SDK биржи Ibiza разделяет загрузку и показ полноэкранной рекламы: load() выполняет аукцион заранее, show() показывает объявление один раз, а пиксели показа, nurl, burl и уведомление биржи срабатывают при показе, а не при загрузке. Ответы аукциона биржа отдает с Cache-Control: no-store, пиксель трекинга DSP — с no-cache, no-store, must-revalidate. Уведомление биржи о показе подписано и несет время аукциона: слишком старые уведомления не засчитываются, событие относится к часу аукциона, а не доставки, и повторы склеиваются по ID запроса. Подробнее об уведомлениях — в документации «Подключение SSP».

Частые вопросы

Сколько можно держать загруженную рекламу до показа?

Ориентир дает сама ставка: поле bid.exp в OpenRTB — сколько секунд покупатель готов ждать между аукционом и показом. Если его нет, IAB в заметках к OpenRTB приводит примерные окна: минута для веба, 5–10 минут для баннеров и нативной рекламы в приложении, 30 минут и больше для полноэкранных форматов.

Что будет, если показать рекламу после истечения bid.exp?

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

Включать ли useBidCache в Prebid.js?

По умолчанию он выключен с версии 2.0. Включать стоит осознанно: кешированная ставка может перебить новые только в пределах того же рекламного места и той же страницы и только до истечения своего TTL.

Можно ли кешировать трекинг-пиксели?

Нет. Пиксель показа, nurl и burl должны срабатывать на каждый показ: закешированный браузером или прокси пиксель не дойдет до сервера, и показ не будет учтен.