В первой части мы обсуждали экосистему программатик рекламы. Получился довольно больший лонгрид, с быстрым обзором самых основных частей. Сегодня идем глубже и останавливаемся исключительно на самом протоколе OpenRTB. Важно, что большая часть статьи построена на спецификации OpenRTB 2.6. Эта версия удобна, потому что в одном документе показывает современную object model: structured user-agent через sua, DOOH-контекст, GPP-сигналы, video/audio pod-related поля и связь с supply-chain объектами. При этом наличие версии 2.6 в спецификации не означает, что каждая SSP, DSP или exchange поддерживает все поля именно так. В проде встречаются разные версии OpenRTB, частичная поддержка полей и договоренности на уровне интеграции.
Важно! В статье разбирались только поля, описанные в OpenRTB 2.6 или в связанной спецификации. Если поле встречается у конкретной платформы только внутри
ext, мы не выдаем его за стандарт OpenRTB. При этомextнельзя считать "мусорной корзиной": в реальных интеграциях там часто живут важные vendor-specific сигналы, но их нужно описывать как расширения конкретного участника, а не как универсальную норму.
Что же, теперь вперед.
2.1. Тип аукциона: at
2.2. Imp (impression): единица продажи
2.3. Медиаформат
2.4. Pmp и Deal: сделка внутри impression
2.5. Где происходит показ: Site, App, DOOH
2.6. Device: техническая среда
3.1. Поля Bid: цена, креатив, уведомления
3.2. Notification URLs и macros
3.3. No-bid и nbr
OpenRTB как грамматика сделки
OpenRTB - не рекламная платформа и не биржа. Это грамматика сообщения между supply-side системой, которая описывает рекламную возможность, и buy-side системой, которая может ответить ставкой. В конкретной цепочке это могут быть SSP, exchange, ad server, wrapper, mediation layer, DSP или bidder внутри рекламной сети.
В центре два корневых объекта:
BidRequest- описание рекламной возможности;BidResponse- ответ со ставкой, креативом и служебными идентификаторами.
Транспорт - отдельный слой. На практике OpenRTB часто передается server-to-server по HTTPS в JSON-представлении. Спецификация 2.6 в первую очередь описывает объектную модель: где лежит imp, что означает device.ua, как bid.impid связывается с imp.id, куда кладутся regs и где появляется schain.
Немного вспомним, прошлую статью схематически изобразив главных игроков рынка и запросы между ними:

Верхний уровень: BidRequest
BidRequest - корневой объект запроса. Его удобно читать не как
длинный список полей, а как набор смысловых блоков.
Блок | Поля и смысл |
|---|---|
Идентификация |
|
Что продается |
|
Где показывается |
|
Техническая среда |
|
Пользователь |
|
Ограничения |
|
Время, валюта и тип аукциона |
|
Происхождение |
|
Расширения |
|
Компактный пример:
{ "id": "req-001", "tmax": 120, "at": 1, "cur": ["USD"], "imp": [ { "id": "1", "banner": { "format": [{ "w": 300, "h": 250 }] }, "bidfloor": 0.80, "bidfloorcur": "USD", "secure": 1 } ], "site": { "domain": "example.com", "page": "https://example.com/article" }, "device": { "ua": "Mozilla/5.0 ...", "ip": "203.0.113.1", "language": "en" }, "user": { "buyeruid": "buyer-user-123", "ext": { "consent": "CONSENT_STRING_EXAMPLE" } }, "regs": { "gdpr": 1 } }
Это не шаблон для копирования. Это карта вложенности, от которой мы пойдем к самим объектам.
CONSENT_STRING_EXAMPLEвextздесь именно placeholder: реальную consent string и место ее передачи нужно брать из privacy-фреймворка и интеграционной документации.
Далее рассмотрим наиболее важные объекты в модели.
Тип аукциона: at
OpenRTB 2.6 содержит request-level поле at. По спецификации OpenRTB 2.6 оно не описывает весь алгоритм аукциона, но передает базовый auction type:
first-price auction;
second-price plus auction.
Это важный мост к следующей части: at говорит DSP, как интерпретировать ставку на уровне протокола, но не раскрывает dynamic floors, bid shading, правила округления, комиссии, приоритет ad server или post-auction проверки. Поэтому at нельзя читать как полную формулу списания. Упростим, at конкретно говорит DSP по какому аукциону будет действовать SSP, но не раскрывает какие-либо детали расчета.
Imp (impression): единица продажи
imp - массив объектов Imp. Каждый Imp описывает одну рекламную возможность. Технически DSP возвращает ставку на конкретный Imp; модель ценности при этом может учитывать сайт, приложение, пользователя, контент, креатив, кампанию, deal, частоту и другие сигналы.
Ключевые группы полей Imp:
Группа | Примеры |
|---|---|
Идентификатор |
|
Медиаформат |
|
Цена и условия |
|
Private marketplace |
|
Технические признаки |
|
Самая важная связка:
BidRequest.imp[0].id = "1" BidResponse.seatbid[0].bid[0].impid = "1"
Так DSP говорит: "моя ставка относится именно к этому impression".
Когда imp несколько
imp - массив, поэтому один request может описывать несколько рекламных возможностей. DSP не обязана отвечать на каждую из них: она может вернуть ставку только на один impid, несколько ставок на разныеimpid или no-bid.
BidRequest.imp[0].id = "banner-1" BidRequest.imp[1].id = "video-1" BidResponse.seatbid[0].bid[0].impid = "video-1"
Такой ответ означает: buyer участвует только в аукционе за video-1.
Если в SeatBid используется group, он указывает, должны ли ставки в этой группе рассматриваться вместе. Детальные правила, можно ли выиграть несколько impressions из одного request, нужно проверять по OpenRTB 2.6 и конкретной интеграции.
Медиаформат
Banner
Объект Banner обычно воспринимают как «укажи размер и всё». Но он несёт четыре совершенно разных смысловых нагрузки одновременно.

Теперь по каждой зоне подробнее.
Геометрия. Типичная ошибка — передавать только
wиhкак скаляры. Это работает, но лишает издателя гибкости.format[]— это массив:[{"w":300,"h":250},{"w":728,"h":90}]. SSP может подобрать подходящий размер сам, а байер не обязан держать под каждый размер отдельныйimp.Ограничения.
btypeиbattr— это блок-листы на стороне издателя, которые байер обязан уважать.btypeговорит «не присылай флеш-баннеры» или «не присылай всплывающие окна» (числовые enum по IAB).battrточнее: «без автозапуска звука», «без анимации длиннее 30 секунд» — всё это атрибуты креатива.mimesограничивает допустимые форматы файлов.Окружение.
pos— это IAB-enum позиции на странице: above the fold, below the fold, header, footer, sidebar и т.д. Влияет на CPM — above the fold исторически дороже.topframeсообщает, находится ли рекламный слот в корневомwindowили внутриiframe: важно для верификационных скриптов, которые пытаются прочитатьwindow.top.expdirнужен для expandable-форматов — баннер может раскрываться влево, вправо, вниз и т.д.API и идентификация.
api— список поддерживаемых фреймворков: MRAID 1/2 для мобильных rich media, ORMMA, VPAID. Без этого поля байер не знает, можно ли использовать интерактивные форматы.idнужен только если в одномimpнесколькоBanner-объектов — иначе ссылаться на конкретный баннер в ответе невозможно.
Video
Video — самый богатый объект из четырёх форматов. Баннер описывает что показать, видео описывает ещё когда, как и в каком окружении.

Несколько нюансов, которые не влезают в ячейки. placement и plcmt — это два разных поля с пересекающейся семантикой: первое из OpenRTB 2.x, второе добавлено в 2.6 как более точная классификация. Для CTV и SSAI важно смотреть на версию спеки и конкретные требования площадки. startdelay = 0 значит pre-roll, -1 — generic mid-roll, -2 — generic post-roll. protocols — это список VAST-версий, которые принимает слот; байер обязан прислать крeatив в одном из перечисленных форматов.
Audio и Native
Audio структурно близок к Video, но без геометрии и placement-классификации. Поды работают так же: maxseq, poddur, rqddurs.

Native устроен принципиально иначе: сам объект в OpenRTB — это тонкая обёртка. Всё содержательное находится в отдельной Native Ad Specification, на которую request служит мостом.

На стороне bid response симметрично: nativeResponse тоже читается через Native Ad Spec, а не как произвольный JSON. assets[] в ответе должны отвечать assets[] из запроса по id.
Pmp и Deal: сделка внутри impression
Private marketplace в OpenRTB живет внутри Imp:
"imp": [ { "id": "1", "banner": { "w": 300, "h": 250 }, "pmp": { "private_auction": 1, "deals": [ { "id": "deal-777", "bidfloor": 2.50, "bidfloorcur": "USD", "at": 1, } ] } } ]
Объект Pmpсодержит два поля:
private_auction- флаг, 0 - открытый аукцион, 1 - только invited buyers поdeals[].id. Безdealidв ответе — бид отклоняется exchange'ем.deals- массив объектовDeal. Одинimpможет нести несколько сделок одновременно: например, preferred deal для одного байера и PMP-аукцион для другого.
Давайте поподробнее о Deal:
bidfloor+bidfloorcur— специфический floor для этой сделки, независимо отimp.bidfloor. Если оба заданы, SSP обычно применяет максимум из двух, но конкретное поведение закрепляется в интеграционных правилах — в спеке это не нормировано жёстко.at— тип аукциона именно для этой сделкиwseat— whitelist seat-ов, которым разрешено биддить по этой сделке. Если пустой, ограничений нет.wadomain— whitelist доменов рекламодателей. Не все exchange реализуют проверку на своей стороне — иногда это ответственность DSP.ext— стандартное место для нестандартных полей. Часто используется для передачи audience segment ID, приоритета сделки или флагов SSAI.
Где происходит показ: Site, App, DOOH
OpenRTB 2.6 разделяет среды показа.
Site
Site используется для web-инвентаря. Важные группы:
идентификация:
id,name,domain;страница:
page,ref,search;категории:
cat,sectioncat,pagecat;связи:
publisher,content;прочее:
keywords,mobile,privacypolicy,ext.
App
App используется для in-app инвентаря. В нем важны id, name, bundle, domain, storeurl, cat, publisher, content, keywords, ext. Главное отличие: приложение идентифицируется не только доменом, а bundle/store-контекстом.
DOOH
OpenRTB 2.6 включает DOOH для digital out-of-home. Это важно именно для версии 2.6: inventory context шире, чем site и app. В DOOH нет привычного браузерного пользователя, поэтому иначе устроен контекст места и аудитории. Например, экран в торговом центре описывается не как web-страница с cookie, а через место, экран, контент/паблишера и оценку аудитории. OpenRTB 2.6 также содержит связанные DOOH-объекты вроде Venue, Publisher, Content Producer; для DOOH особенно важно не переносить web-логику one-to-one impression без проверки спецификации и интеграции.
Device: техническая среда
Device описывает не человека, а техническую среду. Среди полей OpenRTB 2.6: ua, sua, geo, dnt, lmt, ip, ipv6, devicetype, make, model, os, osv, h, w, ppi, pxratio, js,language, carrier, connectiontype, ifa, ext.
Особенно важен sua - structured user-agent. Классический ua - строка, которую разные системы могут парсить по-разному. sua дает структурированный способ передавать user-agent-информацию. При этом legacy ua все еще встречается очень часто; поддержка sua зависит от
участников цепочки.
Типичная ошибка: воспринимать Device как набор данных для fingerprinting. В OpenRTB это объект описания среды; какие поля можно передавать и использовать, решается не только спецификацией, но и privacy-правилами, платформенными ограничениями и договорами.
User: идентификаторы и данные
User описывает пользователя в той мере, в какой это доступно и разрешено. В OpenRTB 2.6 среди полей: id, buyeruid, yob, gender,keywords, customdata, geo, data, eids, ext.
Поля вроде yob и gender существуют в спецификации, но это не означает, что они часто, надежно или правомерно передаются в современной privacy-среде. Важное различие:
id- exchange-specific user ID;buyeruid- buyer-specific user ID, если он известен отправителю;eids- external identifiers.
В первой части мы говорили о cookie syncing и identity как процессе. Здесь фиксируем только результат: где в OpenRTB может лежать идентификатор, если его разрешено и возможно передать.
Regs: regulatory signals
Regs предназначен для сигналов регулирования. В OpenRTB 2.6 описаны:
coppa— флаг, что запрос от ребёнка (закон США о детской приватности).gdpr— флаг, что запрос из Европы и подпадает под GDPR.us_privacy— строка для законов штатов США (CCPA и подобные).gppиgpp_sid— это глобальная штука, которая объединяет разные законы в одном месте. GPP — сама строка,gpp_sid— ID секций (какие законы вообще затронуты).ext— Расширения.
Regs - только container для regulatory signals. Consent string для GDPR/TCF обычно передается не самим regs.gdpr, а через расширения вродеuser.ext.consent; GPP используеть regs.gpp и regs.gpp_sid. Enforcement logic остается на стороне участников цепочки и их договоров.
Важно: Regs не дает юридического разрешения использовать данные. Он передает downstream-системам сигналы, которые они должны интерпретировать по своим правилам, договорам и применимому праву.
Прозрачность supply chain
Один schain не закрывает всю тему прозрачности, подробнее о chain. В связке с ним обычно проверяют несколько официальных механизмов IAB Tech Lab:
ads.txt - список авторизованных продавцов web-инвентаря;
app-ads.txt - аналогичная идея для app-инвентаря;
sellers.json - сведения о продавцах в рекламной системе;
SupplyChain Object - цепочка участников, переданная внутри конкретного bid request.
Практический смысл: DSP может сверять, кто продает inventory, авторизован ли продавец и как выглядит путь supply. Но эти механизмы не являются математическим доказательством качества трафика; они дают проверяемую структуру для аудита.
Source и schain: происхождение запроса
Source описывает источник request. Среди полей: fd, tid, pchain, schain, ext. schain - SupplyChain Object. Он описан отдельной спецификацией IAB Tech Lab
Пример:
"source": { "tid": "transaction-123", "schain": { "ver": "1.0", "complete": 1, "nodes": [ { "asi": "ssp.example", "sid": "publisher-42", "rid": "req-001", "hp": 1 } ] } }
Ключевые поля nodes:
asi- advertising system identifier;sid- seller/reseller ID within that system;rid- request ID, если передается;hp- участвует ли узел в payment flow (что это);name,domain- дополнительные сведения, если переданы.
schain не доказывает честность трафика. Он дает структуру, по которой
DSP и другие участники могут проверять путь supply.
На этом закончим рассмотрения BidRequest и перейдем к модели ответа.
BidResponse, SeatBid, Bid
Часть про ответ DSP будет существенно короче, так как модель ответа содержит существенно меньше полей.
Если DSP участвует, она возвращает BidResponse. В OpenRTB 2.6 верхний уровень ответа включает id, seatbid, bidid, cur, customdata, nbr, ext.

Пример:
{ "id": "req-001", "seatbid": [ { "seat": "buyer-seat-1", "bid": [ { "id": "bid-123", "impid": "1", "price": 1.25, "adm": "<!-- creative markup -->", "crid": "creative-456", "cid": "campaign-789", "adomain": ["advertiser.example"], "w": 300, "h": 250, "nurl": "https://dsp.example/win?...", "burl": "https://dsp.example/billing?...", "lurl": "https://dsp.example/loss?..." } ] } ], "cur": "USD" }
Три уровня:
BidResponseотвечает на request черезid;SeatBidгруппирует ставки по buyer seat;Bidописывает конкретную ставку на конкретныйImp.
SeatBid.group управляет пакетной логикой: при group: 1 выигрыш одной ставки аннулирует остальные в группе — это нужно когда байер хочет купить ровно один слот из нескольких предложенных. Детали применения group нужно проверять в интеграционных правилах конкретного exchange.
Поля Bid: цена, креатив, уведомления
Ключевые группы полей Bid:
Группа | Поля |
|---|---|
Связь и цена |
|
Креатив |
|
Формат |
|
Классификация |
|
Уведомления |
|
Прочее |
|
adomain особенно важен для проверки рекламодателя и политик площадки. crid нужен для creative review и логирования. adm может быть HTML, VAST XML, native response или другой markup в зависимости от media object. nurl, burl, lurl связывают аукцион с событиями после ответа: победа, биллинг, проигрыш. Их фактическое срабатывание, macro substitution и шифрование цены задаются спецификацией и интеграционными правилами exchange; win notice не всегда равен billing event.
Поле mtype явно указывает тип markup: 1 — banner, 2 — video, 3 — audio, 4 — native. Без него exchange определяет тип по содержимому adm — это ненадёжно. crid позволяет exchange кешировать результаты creative review: при повторном появлении того же crid полная проверка adm не нужна.
Notification URLs и macros
Поля nurl, burl и lurl могут содержать URL с macros. После аукциона exchange может подставить в них значения вроде clearing price, auction ID или loss reason, если такие macros поддерживаются конкретной интеграцией и описаны в спецификации/документации.
nurl — победа в аукционе. Слот мог не отрендериться, пользователь закрыть страницу — показа ещё нет. burl — подтверждённый факт показа, именно он служит основой для финансовой сверки. lurl опционален, но полезен для DSP-аналитики: macro ${AUCTION_LOSS_REASON} передаёт причину проигрыша — перебит ценой, заблокирован badv, не прошёл battr и т.д. Поддержка конкретных macros и формат пинга закрепляются в интеграционных правилах exchange.

Практический вывод: Bid.price - это ставка в ответе DSP, а фактическая цена закрытия может прийти позже через win/billing notification. Поэтому нельзя читать bid response как полный финансовый лог сделки.
No-bid и nbr
Если DSP не делает ставку, это тоже часть протокола. BidResponse.nbr предназначен для no-bid reason.
Важно не переобещать: в реальных интеграциях no-bid может быть пустым ответом, HTTP 204, HTTP-ответом без ставки или объектом с nbr. Но если причина передается в OpenRTB-ответе, стандартное место для нее -nbr. Значения берутся из enum no-bid reason в спецификации OpenRTB 2.6.
Что OpenRTB покрывает и не покрывает
OpenRTB покрывает | OpenRTB не покрывает |
|---|---|
Структуру | Как DSP обучает ML-модель. |
Описание | Как рекламодатель задает стратегию. |
Контекст | Как SSP выбирает routing. |
| Точный алгоритм аукциона, хотя |
| Как происходят атрибуция, коммерческие комиссии и финансовая сверка. |
OpenRTB - язык торгового сообщения. Он не гарантирует, что выигранная ставка превратится в показ: пользователь мог уйти, слот мог не отрендериться, креатив мог не пройти политику, ad server мог выбрать другой источник спроса. Аукцион, bid shading, clearing price и оптимизация ставок - следующая часть.
Итог
OpenRTB-запрос можно читать так:
Вот рекламная возможность:
Imp. Вот среда:Site,AppилиDOOH. Вот устройство:Device. Вот пользовательские и regulatory-сигналы:User,Regs. Вот происхождение запроса:Source. Если хочешь участвовать, ответь черезBidResponse.
OpenRTB-ответ можно читать так:
Я ставлю
priceнаimpid. Вот креатив, advertiser domain, campaign ID, creative ID и URL для уведомлений.
На этом OpenRTB заканчивается и начинается аукционная математика: кто победит, почему проиграют остальные и почему списанная цена не всегда равна ставке.
Для более подробного ознакомления
OpenRTB 2.6: https://github.com/InteractiveAdvertisingBureau/openrtb2.x/blob/main/2.6.md
Репозиторий OpenRTB 2.x: https://github.com/InteractiveAdvertisingBureau/openrtb2.x
SupplyChain Object: https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/supplychainobject.md
ads.txt: https://iabtechlab.com/ads-txt/
app-ads.txt: https://iabtechlab.com/app-ads-txt/
sellers.json: https://iabtechlab.com/sellers-json/
