Плейбук: реклама Ozon — данные, оценка окупаемости, решения
Перед интерпретацией отчёта, в том числе быстрого CPL/CPO, проверить журнал изменений и тестов: активные РК и изменения фото в отчётном окне и базе сравнения. Указать влияющие изменения, смешанные дни и ещё недозревшие результаты. Новое действие или решение владельца записывать туда с датой; результаты главных фото связывать с существующим CTR-учётом. Журнал не меняет формулы CLI.
Маршрут полного анализа актуализирован 06.09.2026 (§−1). Численные цели прибыли здесь не дублируются: источник — план-факт и решения владельца по ценам.
Срабатывает, когда пользователь спрашивает про рекламу Ozon: «куда уходит рекламный бюджет», «по каким запросам показываемся / сливаем», «разбей рекламу по типам кампаний», «ДРР по артикулам Ozon», «почему артикул X жрёт рекламу», «поисковые запросы по товару», «окупается ли реклама», «выключать или масштабировать», «почему просели заказы».
Начинать полный разбор с маршрута §−1; далее три справочных слоя:
- A. Данные (§0–§5) — где лежит, чем тянуть, грабли Performance API, что Ozon не даёт.
- B. Методика оценки (§6) — безубыточность и границы причинных выводов. Целевая прибыль из план-факта, общий CPL и формат полного разбора — §−1.
- C. Кейсы (§8+) — датированные разборы, только как иллюстрация.
Стек: mp-system (корень), .venv/bin/python, БД mp.db, shop 2 = Мой Ozon, shop 4 =
Siluetta Ozon. Performance API — app/ozon/performance.py (PerformanceClient). Расчёт
прибыли/ДРР — data/notes/ozon/profit-methodology.md. Зрелый выкуп и прогноз хвоста —
data/notes/ozon/orders-ad-cpo-playbook.md (не дублировать сюда).
−1. Полный анализ: единая точка входа
Для план-факта заказов и CPO через корзины Siluetta Ozon, без диагностики РК
и финансовой маржи, использовать отдельный короткий маршрут:
плейбук план-факта, report.cmd plan-fact.
Он читает production, возвращает вчера / 7 дней / предыдущую неделю и покрытие.
Полный маршрут ниже не требуется для такого ограниченного запроса.
Для короткого запроса CPL/CPO достаточно быстрого CLI ниже. Этот маршрут обязателен, когда просят проанализировать рекламу, сопоставить с маржой, показать общую картину, оценить оставленные РК или решить, что выключать / заменять / масштабировать.
Где брать план, факт и прошлые решения
Все пути в таблице — от корня Big-System-MP, если явно не указан соседний проект.
| Что нужно | Канонический источник | Что именно брать |
|---|---|---|
| Целевая прибыль и рекламный бюджет | План-факт: config/plan.yaml | items[].margin — прибыль ₽/продажу после рекламы; ads — реклама ₽/выкуп; cogs, logistics, price_cabinet, buyout_planned, season, liquidation, match |
| Обоснование целей и запреты на снижение цены | Плановые цены по артикулам | Решения владельца и дата их действия; при расхождении с YAML приоритет у этого документа |
| Общая корзина, конверсия, плановый CPL | Плейбук план-факта | Формулы и ограничения scripts/plan_fact.py; на сайте — /plan-fact |
| Фактическая прибыль и вклад | report.cmd profit, плейбук прибыли |
profit уже после расчётного налога; для периода вклад до рекламы = profit + ads |
| Реклама и размещения | report.cmd ads; ozon_ad_metrics_daily |
Расход, показы, клики, рекламные atbs; по РК — campaign_id, фактический offer_id, placement |
| Все корзины и заказы карточки | ozon_sku_traffic_daily, плейбук трафика |
total_hits_to_cart, ordered_units, pdp_views, hits_pdp_to_cart; не рекламные счётчики |
| Текущие оставленные кампании | Свежий ozon_campaigns из Performance |
state, campaign_id, title, payment_type, placement, fetched_at |
| Дозревший выкуп и возвраты | Плейбук выкупа | Когорта с отступом 15 дней, по размерам; для net-продаж дополнительно возвраты после вручения |
| Наличие рекламируемого размера | ozon_analytics_stock_snapshot |
Последний снимок магазина: available и число складов с available > 0; дата снимка обязательна |
| Прошлые анализы и рекомендации | Архив data/ads/ | Датированные отчёты; история решений, а не источник сегодняшнего факта |
Маржа в плане — не процент выручки. margin задаётся в рублях на проданную единицу.
Проценты 50/75/100 в обосновании — ROI относительно себестоимости. Своя цель есть у каждого
артикула; не переносить её по аналогии на цвет, соседнюю модель или ликвидационный хвост.
ads — бюджет на выкуп, не дневной лимит РК и не ставка за клик. Ноль — действительное
решение «реклама не заложена», а не отсутствие данных. Пол цены по решению владельца
сильнее арифметического порога безубыточности.
Сопоставление артикулов: использовать явный match плана и фактический offer_id;
размеры объединять только после сопоставления. Не применять слепо sku_alias: она может
склеивать разные товары (например, skirt-atlas-max-2 и skirt-milk). Себес факта — через
CostBook; плановый себес новой партии может отличаться от текущего. Разницу показать,
а не менять базу затрат или план в ходе анализа.
Порядок сбора без поиска по всему workspace
- Установить
shop_idи абсолютные даты. Без периода — 7 закрытых дней по Москве. Для сравнения брать равное предыдущее окно; для экономики — не менее месяца. - Из корня
Bot_TGснятьreport.cmd ads --shop "Ozon Siluetta"иreport.cmd profit --shop siluetta-ozon --period "за последние 30 дней". При заданном окне передать его явно; не заменять 2–5 сентября полной прошлой неделей. - Для недельной общей воронки из
Strategy-Operationsзапустить.venv\Scripts\python.exe scripts\plan_fact.py --period 7d --jsonбез--emit. План берётся изBig-System-MP/config/plan.yaml, факт — с серверного снимка. Для произвольного окна использовать те же источники и формулы, а не подменять даты ближайшим поддерживаемым периодом CLI. Данные WB из общего план-факта в Ozon-воронку не включать. - Если просят «сними через Hetzner», актуальные оставленные РК или свежие данные,
обновить
campaigns, затемad-statsза нужные даты (§0). Не запускать одновременно несколько выгрузок Performance. Из/home/mi/Bot_TG/mp-systemзапускать отmi(при SSH под root —sudo -u mi .venv/bin/python ...), чтобы не испортить права WAL. Это сбор аналитики; он не разрешает менять ставки, бюджеты, цены или состояние РК. - Нестандартную детализацию читать из production
/home/mi/Bot_TG/mp-system/mp.dbчерезsqlite3 -readonly. Штатный план-факт использует/root/mp-db-sync/mp-snapshot.db, обновляемый ежечасно. Назвать источник и задержку; после ingest не читать старый snapshot как будто он уже обновился. Локальныйmp.dbне использовать как незаметный fallback. Секреты и.envне выводить. - Сверить покрытие каждого дня по рекламе и общей аналитике карточки.
MAX(date)илиsuccessсборщика сами по себе не доказывают наличие корзин. Все расчёты одной строки строить на одинаковом наборе дней. Пропущенные дни не превращать в нули (§6.9). - Сначала собрать все корзины и все расходы по артикулу, затем детализацию по РК. Агрегировать источники отдельно, соединять по магазину и артикулу: прямой JOIN дневного трафика с несколькими РК задвоит корзины. По РК сохранять ID и реальный размер; название может содержать S, когда рекламируется M.
- Пройти диагностику ниже, сопоставить фактическую экономику с целью, сохранить отчёт.
Сегодня отдельно. Если реклама за сегодня уже есть, а дневные общие корзины ещё нет, показать общий CPL по закрытым дням и отдельный предварительный блок сегодняшней рекламы. Нельзя делить расход 2–5 сентября на корзины 2–4 сентября. Заказы из аналитики и постингов могут немного различаться: назвать источник, не подгонять числа вручную.
Как перейти от цели прибыли к цене корзины
Обозначения: m — целевая прибыль ₽/net-продажу из плана; A_plan — плановая реклама
₽/выкуп; V — фактический вклад до рекламы ₽/net-продажу; q — корзина→заказ;
b — доля выкупа. Все коэффициенты — доли, не проценты.
Плановый ориентир общего CPL = A_plan × q × b
Оценка CPS через корзины = общий CPL / (q × b)
V = (profit + ads) за финансовое окно / net-продажи того же окна
Реклама для целевой прибыли A_target = V − m
Общий CPL для целевой прибыли = (V − m) × q × b
Общий CPL безубыточности = V × q × b
Два разных сравнения: укладываемся ли в плановый рекламный бюджет, и оставляет ли
фактическая экономика целевую прибыль. Не называть их одним «допустимым CPL» без подписи.
Если V < m, даже нулевая реклама при такой экономике не даёт цель: проверять цену,
логистику, возвраты и затраты. Если V <= 0, реклама не единственная проблема. При
net-продажи <= 0 вклад на единицу не определён; прочерк, а не деление на ноль.
Вклад из общего financial CLI включает распределённые операции магазина; вклад §6.4
только по привязанным отправлениям имеет другую границу затрат. Явно назвать вариант.
Внешние затраты, не учтённые в profit/себесе, при строгой оценке вычесть отдельно,
не повторяя уже включённые расходы. Целевую маржу после решения владельца не выдавать
за обязательный план для более ранних дат — ретроспективное сравнение подписывать.
q в план-факте — orders_window / carts_window за скользящее окно. Своя статистика
используется при ≥50 корзинах и 0 < q <= 1, иначе медиана с пометкой. Неделя с <30
корзинами — малый объём. Общую конверсию считать как отношение сумм, не среднее процентов.
Отношение заказов к корзинам периода — показатель воронки, не трекинг конкретных корзин.
Штатный план-факт берёт выкуп по разрешившимся отправлениям последних 60 дней; при
недостатке использует плановый. Не называть этот выкуп зрелой когортой: отдельная
методика требует 60 дней, завершившихся за 15 дней до среза. Указать окно, источник,
fallback и возвраты после вручения. Подстановка только delivered без последующих
возвратов делает прогноз оптимистичнее net-продаж. Корзинный прогноз не заменяет проверку
по дозревшим продажам и финансам; неизвестные коэффициенты не выдавать за измеренные.
Диагностика: что именно изменилось
| Наблюдение | Рабочая гипотеза | Что проверить перед решением |
|---|---|---|
| Рекламный CPL вырос, клик→корзина прежняя | Подорожал клик / изменился состав трафика | CPC и доли расходов внутри той же РК, размещения и размеры |
| CPC прежний, клик→корзина снизилась | Изменились аудитория, предложение или карточка | Креатив, релевантность, цена, наличие; не объявлять причину доказанной |
| Корзины и их цена стабильны, корзина→заказ ниже | Ухудшение на следующем этапе воронки | Размеры, география и сроки доставки, цена, конкуренты; изменение качества рекламного трафика тоже не исключено |
| Заказы есть, net-продажи/прибыль ниже | Лаг, невыкуп, возвраты или затраты | Зрелость когорт, возвращённые продажи, комиссия, логистика, налог; не делить свежий расход на недозревшие продажи |
| Дорогая рекламная корзина, но общий CPL в плане | Рекламная атрибуция отражает лишь часть воронки | Общие корзины и заказы; инкрементальность этим не доказана |
| CPL укладывается в бюджет, но цель прибыли не достигнута | Плановые предположения по экономике не совпали с фактом | V − m, цена, себес, логистика и возвраты; одного CPL недостаточно |
| Расход вырос, общие корзины/заказы не выросли | Дополнительный расход пока не дал сопоставимого результата | Состав РК, даты переключений, сезон и лаг; причинный вывод требует теста |
| Кампании отключены, общий результат ещё плохой | В периоде остались расходы прежнего набора РК | Разделить историю периода и текущую конфигурацию; дождаться полного окна после изменения |
| Корзины исчезли у всех при живых заказах | Пропало покрытие аналитики | Подписка, даты и счётчики сбора (§6.9), не «обвал конверсии» |
Сначала сопоставить опережающие показатели, затем основные (§6.5). Сезонность учитывать по артикулу; ровная цена корзины не доказывает неизменность качества спроса. Исторические пороги ELS04 (§6.8) не универсальны для всех категорий.
Оставленные РК, замена размещения и единый формат ответа
Первая таблица — общая картина:
Артикул | Все корзины | Все заказы | Весь расход | Общий CPL
| Средняя корзина→заказ | Плановый CPL | CPL под целевую прибыль | Вывод
Назвать окно и число полных дней, источник заказов; добавить ИТОГО. Показать артикулы с корзинами без рекламы и расход без корзин. Если ширина мешает, экономические ориентиры вынести во вторую таблицу, но число всех корзин не убирать.
Затем детализация оставленных РК:
ID | Название | Реальный offer_id/размер | Размещение | Текущий статус
| Расход | Клики | Рекламные корзины | Клик→корзина | Рекламный CPL
RUNNING — статус на момент среза, не непрерывная работа весь период. В общем расходе
артикула оставить уже отключённые РК. Отдельно показать, какую сумму они потратили;
не делить только расход оставленных РК на все корзины прошлого периода. Отсутствие
строк CPO не является независимой сверкой отсутствия начислений finance.
Сравнивая «поиск» и «поиск + рекомендации», учитывать CPC и конверсию вместе: дорогой клик может компенсироваться более высокой конверсией. Разные размеры, даты, остатки и бюджеты не образуют чистый тест размещения. Формат сам по себе не делает РК лучше; новая кампания — гипотеза, а не гарантированное улучшение. Назначение РК (например, запуск) проверять отдельно от стоимости корзины.
Завершать ответ 2–3 приоритетами: что данные поддерживают, что только предполагается, какой результат изменит рекомендацию. Для теста — один изменяемый параметр, сопоставимый бюджет, контроль и окно (§6.6), с оговоркой по объёму выборки. Настройки менять только по явной команде пользователя, не по фразе «я бы выключил, что думаешь?».
Где сохранять анализ
Рабочий архив: Big-System-MP/data/ads/.
D:\YandexDisk\Bot_TG\Big-System-MP\data\ads\YYYY-MM-DD\
advertising_analysis_YYYY-MM-DD.md
Дата папки — день подготовки по Москве, даты анализируемых периодов — внутри документа. В каждом полном разборе сохранять: магазин; время/источник среза; покрытие и ограничения; периоды; ссылки на план и принятые цели; все корзины и расходы по артикулам; детализацию РК; динамику; диагностику; рекомендации и статус «предложено/выполнено»; исходный JSON или SQL без секретов. Прогноз отделять от финансового факта.
Повторный анализ за день не должен молча стирать предыдущий: дописать явно датированный
срез либо сохранить advertising_analysis_YYYY-MM-DD_HHMM.md. После повторного ingest
сохранять версии и помечать корректировки, а не склеивать старые корзины/расходы с новыми
без объяснения. Начатый архив: разбор 05.09.2026.
Датированные разборы не входят в комплект синхронизации плейбуков; ссылка на них на
Hetzner может вести к файлу, который хранится только локально.
Быстрый production-отчёт CPL/CPO
Для стандартного read-only запроса сначала использовать report.cmd ads, не ручной SQL:
.\report.cmd ads --shop "Ozon Siluetta"
.\report.cmd ads --shop "Ozon Siluetta" --sku "ELS004 Black" --date yesterday
.\report.cmd ads --shop "Ozon Siluetta" --period "за месяц"
Если период не указан, реклама берётся за последние 7 закрытых дней по Москве. Фильтр
--sku понимает регистр, пробелы и общие алиасы себестоимости (ELS004 Black совпадает с
карточкой ELS04-black). Старые JSON-поля не удаляются.
Дополнительные формулы:
CPL = рекламный расход / рекламные добавления в корзину
атрибутированные заказы = direct orders + model orders (halo)
сырой CPO = рекламный расход / атрибутированные заказы
ожидаемые выкупы = Σ(атрибутированные заказы offer_id × зрелый выкуп offer_id)
CAC ожидаемого выкупа = рекламный расход / ожидаемые выкупы
доступная маржа = 30-дневный вклад после себеса и УСН, но до рекламы / net-выкупы
Зрелый выкуп берётся по 60-дневной когорте, закончившейся 15 дней назад; сначала размер,
при выборке меньше 10 завершённых заказов — артикул. Если и по артикулу меньше 10, вердикт
недостаточно данных, без фолбэка на среднее магазина.
Оценка CAC ожидаемого выкупа относительно доступной маржи:
- до 70% включительно —
вменяемый CPO; - выше 70% и до 100% включительно —
пограничный CPO; - выше 100% —
дорогой/убыточный CPO; - расход есть, но корзин или атрибутированных заказов нет —
нет конверсий; - нет зрелого выкупа, себеса или 30-дневной экономики —
недостаточно данных.
Отчёт не вызывает Performance API. Неполное покрытие периода обозначается
complete=false; после успешного ответа не читать БД и плейбуки повторно.
🔴 Границы применимости этого отчёта. Все его метрики после CPL (сырой CPO,
CAC ожидаемого выкупа, вердикты «вменяемый / пограничный / дорогой») стоят на
атрибутированных заказах Ozon (orders + orders_model). Эта атрибуция не выдерживает
проверки на согласованность (§6.1), поэтому отчёт годится как быстрая диагностика ставки
и сравнение кампаний между собой, но не как вердикт об окупаемости артикула. Вердикт —
только по §6: знаменатель «все корзины / все заказы», метрика CPS против вклада.
CPL (расход / рекламные корзины) от атрибуции не зависит и остаётся валидным.
0. Перед стартом: данные свежие?
Реклама и кампании часто устаревшие — сперва доингест (Performance API асинхронный, тянется минутами):
.venv/bin/python scripts/ingest_ozon.py --shop-id 2 campaigns
.venv/bin/python scripts/ingest_ozon.py --shop-id 2 ad-stats --from YYYY-MM-DD --to YYYY-MM-DD
Кладётся в ozon_ad_metrics_daily (день × SKU × кампания: views/clicks/orders/money/placement)
и ozon_campaigns (тип/плейсмент кампаний).
⚠ Границы CPC-выгрузки (проверено 18.09.2026).
PerformanceClient.statistics_request превращает дату без времени в T00:00:00Z
для обеих границ. Поэтому --to 2026-09-18 не означает весь день 18.09 или «по сейчас»;
новый fetched_at не доказывает полноту суток. Для CPC передавать явные RFC3339:
начало первого дня YYYY-MM-DDT00:00:00+03:00, конец закрытого последнего дня
YYYY-MM-DDT23:59:59+03:00; для сегодня — фактическое текущее время с часовым поясом.
CLI передаёт такие строки без обрезки, а PerformanceClient сохраняет их. Запросы
по-прежнему выполнять последовательно, с проверкой фонового сборщика.
При ручном сравнении сохранить исходный CSV/ZIP и обе границы; сегодняшний день
показывать отдельно как неполный. Проверка на HZ020 M 18.09 дала существенно больше
сегодняшнего трафика при явном времени окончания. Период с неправильными границами
перевыгрузить; дневные строки в БД обновляются целиком, не складывать два среза.
Автоматический сборщик этим примечанием не исправлен; проверять его границы отдельно.
Для CPO этот случай не проверен — не переносить вывод без проверки его endpoint.
⚠ Креды Performance. Резолв: shops.perf_cred_path → файл Ozon_Cred.txt (Client ID /
Client Secret), резолвер app/web/shop_status.py::_resolve_ozon_perf. После Win→Linux
миграции в perf_cred_path остаётся мёртвый Windows-путь → «Performance creds не заполнены».
Фикс: UPDATE shops SET perf_cred_path='/home/mi/Bot_TG/mp-system/Ozon_Cred.txt' WHERE id=?.
1. Таксономия: типы кампаний и плейсменты
Тип кампании (ozon_campaigns.adv_object_type / payment_type):
| adv_object_type | payment_type | Что |
|---|---|---|
| SKU | CPC | Оплата за клик (товарная) |
| SEARCH_PROMO | CPO | Оплата за заказ (% с заказа, ДРР-cap) |
| BANNER | CPM | Баннер |
| VIDEO_BANNER | — | Видеобаннер |
| REF_VK / REF_BLOGGER | — | Внешний трафик (VK / блогеры) |
Плейсмент (placement, для CPC):
| placement | По-русски | Фразы? |
|---|---|---|
| PLACEMENT_TOP_PROMOTION | Поиск (топ выдачи) | да (отчёт по фразам только тут) |
| PLACEMENT_SEARCH_AND_CATEGORY | Поиск и рекомендации | частично (только поиск-часть; рекомендации склеены) |
| PLACEMENT_PDP | Карточка товара | нет (только ручные кампании) |
| PLACEMENT_OVERTOP | Поиск и главная (спецразмещение) | — |
| PLACEMENT_TAKEOVER | Первые 4 плитки (спецразмещение) | — |
| None (в ad_metrics) | — | это CPO-операции (за заказ) |
Нет плейсмента «только рекомендации». Рекомендации всегда в связке с поиском (
SEARCH_AND_CATEGORY). Без фраз умеют:PDP(карточка, только ручные) и CPO.
Чего Ozon не даёт вообще (не искать, время не тратить)
- Разбивки «поиск vs рекомендации» внутри кампании.
views/clicksуSEARCH_AND_CATEGORY— одно число на оба размещения. В деньгах сплит доступен только в CPO-режиме «все товары» (all_sku_promo, §4). - Кликов по товару в аналитике карточки. В ответе аналитики (~60 метрик) поля
clicksнет ни в каком виде. Ближайшее по смыслу —pdpViews(просмотр карточки). - Честной атрибуции заказа к рекламе. См. §6.1.
- Минус-слов. Продавец их не ставит; вывод по фразам — только для решения вкл/выкл или ставки.
Сравнение типов РК: «Поиск» против «Поиск и Полки»
Siluetta Ozon (shop 4), все товары, 01.06–28.08.2026:
| Тип РК | Расход | CPC | Клик→корзина | Цена корзины |
|---|---|---|---|---|
SEARCH_AND_CATEGORY (Поиск и Полки) |
345 531 | 1.83 ₽ | 3.10% | 59 ₽ |
TOP_PROMOTION (Поиск / Вывод в топ) |
60 109 | 5.19 ₽ | 3.81% | 136 ₽ |
Помесячно соотношение не плавает (июнь 52/117, июль 64/143, август 58/145 ₽ за корзину). «Поиск» даёт клик качественнее — конверсия в корзину выше на ~23%, — но клик в 2.8× дороже, и качества не хватает, чтобы это отбить: корзина выходит в 2.3× дороже.
⚠ Не резать TOP_PROMOTION автоматически по цене корзины: у неё бывает другая задача
(вывод новинки в топ, удержание позиции). Сначала проверить назначение кампании.
2. Разрез расхода по типам РК (главный запрос)
SELECT placement, payment_type, campaign_id, campaign_title,
ROUND(SUM(money)) AS spend, SUM(clicks) AS clicks, SUM(orders) AS orders
FROM ozon_ad_metrics_daily
WHERE shop_id = :shop AND date BETWEEN :since AND :to
GROUP BY campaign_id ORDER BY SUM(money) DESC;
Чтение: placement=NULL → CPO (за заказ); TOP_PROMOTION → поиск-CPC; SEARCH_AND_CATEGORY
→ поиск+рекомендации-CPC. Свод по типу: GROUP BY placement (или payment_type).
Связка с прибылью: агрегировать SUM(money) per color_key(offer_id) из
ozon_ad_metrics_daily. Исторический образец _oneshot_ozon_unit_shop2.py на 16.08.2026
сохранился только в незакоммиченной рабочей копии Hetzner и не является зависимостью
плейбука. Сверка с finance:
SUM(amount) WHERE operation_type_name IN ('Оплата за клик','Продвижение с оплатой за заказ')
должна совпасть с Performance в пределах 0.1%.
3. Отчёт по поисковым запросам
Только для CPC-кампаний с placement = PLACEMENT_TOP_PROMOTION. Метод на стадии тестирования.
POST /api/client/statistics/phrases/json, тело:
{ "campaigns": ["<id>", ...], "dateFrom": "YYYY-MM-DD", "dateTo": "YYYY-MM-DD", "groupBy": "NO_GROUP_BY" }
Асинхронно → UUID → client.wait_statistics(uuid) → client.statistics_report_bytes(uuid)
(JSON-вариант возвращает dict). Дата не раньше 2025-02-01.
Структура: { "<campaign_id>": { title, report: { rows: [...] } } }, строка =
{sku, title, search_phrase, views, clicks, ctr}.
⚠ Только показы/клики/CTR — НЕТ денег и заказов по фразе. Расход на фразу можно лишь
оценить: клики × средний CPC (CPC = расход_кампании / Σ кликов). Конверсию «фраза→заказ»
API не отдаёт. CTR низкий = плохая релевантность показа.
⚠ Минус-слова продавец на Ozon сам НЕ ставит. Вывод по фразам — для решения вкл/выкл кампании или ставки, не для ручной минусовки.
Алгоритм исторического _oneshot_ozon_phrases_shop2.py: взять TOP_PROMOTION-кампании с
расходом в окне, запросить отчёт, агрегировать фразы по кликам и оценить расход через
средний CPC. На 16.08.2026 этот one-shot есть только в незакоммиченной рабочей копии
Hetzner; воспроизводимый контракт — endpoint и SQL ниже, а не наличие файла.
Кандидаты кампаний:
SELECT DISTINCT campaign_id FROM ozon_ad_metrics_daily
WHERE shop_id=:shop AND date BETWEEN :since AND :to AND placement='PLACEMENT_TOP_PROMOTION' AND money>0;
4. Прочие отчёты Performance (что ещё доступно)
| Нужно | Endpoint | Метод | Отдаёт |
|---|---|---|---|
| Дневная стата по кампаниям | /api/client/statistics/daily |
GET | расход/клики по дням |
| Расход по кампаниям | /api/client/statistics/expense |
GET | быстрый свод трат |
| CPO заказы | /api/client/statistic/orders/generate/json |
POST {from,to} |
заказы CPO (исп. в ingest_cpo_orders) |
| CPO товары (выбранные) | /api/client/statistic/products/generate/json |
POST {from,to} |
per-SKU: orders, ДРР, расход CPO + CPC-доля |
| CPO товары (все, сплит поиск/реком) | /api/client/statistics/all_sku_promo/products/generate/json |
GET timeBounds.from/to |
продажи/заказы из поиска vs из рекомендаций |
| Конкурентные ставки | /api/client/campaign/{id}/products/bids/competitive |
— | ставки конкурентов |
⚠ Сплит «поиск vs рекомендации» (в деньгах/заказах) есть ТОЛЬКО в режиме «все товары»
(all_sku_promo). Если CPO настроен как «выбранные товары» — этот отчёт даёт 404
«кампания не найдена», сплит недоступен (нужно переключить продвижение в кабинете на «все товары»).
⚠ CPO «выбранные товары» расход = CPO (за заказ, ДРР-cap) + CPC (за клик) в одном
инструменте (поля MoneySpent/DRR и MoneySpentFromCPC/ordersFromCPC).
5. Механика Performance API
- Авторизация: OAuth2
client_credentials→ Bearer (TTL ~30 мин), уже вPerformanceClient. - Тяжёлые отчёты асинхронные: submit →
UUID→wait_statistics(uuid, max_wait_sec=600)→statistics_report_bytes(uuid)./json-вариант пути → dict сразу; обычный → CSV/ZIP. - Метод иногда GET, иногда POST — если 405, поменять метод; если параметры через query
(
timeBounds.from) — это GET. Есть rate-limit (раздел «Лимиты» в доке). - Зеркало доки:
Dev-API-Ozon/html/latest/performance/index.md.
NOT_STARTED — норма, не баг
wait_statistics поллит статус UUID. Типичный сценарий: UUID создан → NOT_STARTED 2–5 мин
→ IN_PROGRESS ~30c → OK. 240 секунд — мало, использовать max_wait_sec=600. Реализовано в
pipeline.py: step("ad-stats", ..., max_wait_sec=600).
Лимит 1 одновременная выгрузка на аккаунт → 429 «максимум 1» при попытке создать второй
UUID. Надо дождаться завершения первого, потом повторить. PerformanceClient.request() ретраит
429 3 раза с паузой 30с — если очередь не освобождается за 90с, кидает исключение.
Колонки CSV переименованы Ozon (~2025)
POST /api/client/statistics возвращает ZIP/CSV с заголовками, которые изменились. Актуальные
имена (июнь 2026, verified):
| Старое | Актуальное |
|---|---|
Заказы |
Продано товаров |
В корзину |
Добавления в корзину |
Продажи, ₽ |
Продажи в продвижении, ₽ |
Сумма заказов, ₽ |
Заказано на сумму, ₽ |
Заказы модели |
Продано товаров модели |
Продажи с заказов модели, ₽ |
Продажи в продвижении с заказов модели, ₽ |
Парсер app/ozon/ingest._parse_ad_stats_csv сначала ищет известные точные варианты через
_idx("старое", "новое"), затем использует смысловой fallback по заголовкам:
- количество заказов: содержит
заказ/продано/заказано, но не содержитмодельи денежные маркеры; - сумма заказов: приоритетно
Заказано на сумму, ₽; затем старые поля продаж/сумм. Fallback содержит₽/руб/выруч/сумм/продажи, но не содержитмодельирасход; - количество/сумма модели: те же правила, но обязательно содержит
модель.
Это нужно, потому что Ozon меняет CSV-заголовки без смены endpoint. Если i_orders is None —
в лог уйдёт WARNING "колонка 'Заказы'/'Продано товаров' не найдена".
Диагностика: поднять уровень ozon_ingest до DEBUG и смотреть строку CSV campaign=X headers: [...].
Симптом: все записи
ozon_ad_metrics_daily.orders = 0при ненулевомmoney. Значит колонка renamed и парсер её не нашёл — добавить новое имя в_idx(...).
ingest_campaigns и ARCHIVED-кампании
GET /api/client/campaign возвращает только живые кампании. Архивированные из ответа исчезают,
но в ozon_campaigns остаются со старым статусом (RUNNING/STOPPED/INACTIVE). В результате
ingest_ad_stats посылает statistics_request с невалидными campaign_id → Ozon принимает, UUID
выдаёт, но отчёт НИКОГДА не стартует (NOT_STARTED бесконечно).
Фикс (реализован в ingest_campaigns): после upsert свежих данных кампании, не попавшие в
ответ API, помечаются CAMPAIGN_STATE_ARCHIVED, и ingest_ad_stats их пропускает.
6. Методика оценки: на чём делается вывод
Установлено 28.08.2026 на разборе ELS004 Black (Siluetta Ozon, 05.07–22.08). Заменяет прежний раздел «CPA с поправкой на выкуп», который стоял на атрибуции Ozon.
6.1. Атрибуция Ozon не годится как основа вердикта
Что означают поля ozon_ad_metrics_daily (парсер app/ozon/ingest._parse_ad_stats_csv):
| Поле | Колонка CSV | Смысл |
|---|---|---|
orders |
«Продано товаров» (ex-«Заказы») | заказы самого рекламируемого SKU |
orders_model |
«Продано товаров модели» | заказы других SKU той же модели (гало) |
orders_money |
«Заказано на сумму, ₽» | другая стадия/модель атрибуции |
orders_model_money |
«Продажи в продвижении с заказов модели, ₽» | продажи по гало |
Официальное определение Ozon: «Продано товаров — количество заказов, которые совершили
покупатели, увидев и заказав товары с продвигаемых позиций»
(knowledge-base-mp/ozon/ads/extracted-text/08-promotion-analytics.txt). Несмотря на слово
«Продано», стадия — заказ, а не выкуп.
🔴 orders_money — не денежная пара к orders. Парсер намеренно ставит «Заказано на
сумму» первой. Проверка: ELS004 Black, 14–20.08 — orders_money = 609 390 ₽ ≈ 111 единиц
при orders + orders_model = 38; в отдельные недели orders_money превышает всю валовую
выручку артикула. Считать ДРР = money / orders_money и CPA = money / orders
на одной строке отчёта нельзя — это разные базы.
🔴 Проверка на согласованность, которую атрибуция не проходит. Если принять её за истину, то для ELS004 Black получается: рекламная корзина конвертится в заказ на 19%, органическая — на 50–66%, и цифра скачет 29% → 66% неделя к неделе. Корзина не знает, из какого плейсмента пришёл покупатель — такой разрыв нефизичен. Вывод: раскладывать заказы на «рекламные» и «органические» по данным Ozon нельзя.
⚠ Гало задваивается: если на одну карточку работают кампании на M и на S, заказ размера S по
клику в кампании M попадёт в orders_model кампании M, и наоборот. Суммировать гало по
кампаниям одной модели — с оговоркой.
6.2. Органика не контрольная группа
Инкрементальность «реклама против органического baseline» для наших карточек не считается: органический трафик не независим от рекламы — включили РК, органика появилась; выключили, через неделю пропала.
Подтверждение на ELS004 Black, 11 недель 05.06–20.08:
- корреляция недельный расход ↔ все заказы r = 0.94; клики РК ↔ все заказы r = 0.97;
- разгон июня: расход 1.6 → 14.5 тыс ₽, заказы 26 → 110 — движение одной пары, а не «реклама плюс независимая органика»;
- обратный эпизод 29.07–06.08: показы в поиске рухнули с ~5 000 до ~1 000 в день на девять
дней, а
totalViewsне просел — дыру закрыла реклама. Именно на этой неделе лучший CPS.
⚠ r = 0.94 — это корреляция, а бюджет двигали не случайно. Отделить вклад рекламы от сезона наблюдением нельзя в принципе; нужен эксперимент (§6.6).
6.3. Знаменатель — всё
Из 6.1 и 6.2 следует единственный корректный знаменатель: все корзины и все заказы товара, без попытки выделить рекламную долю.
Общий CPL артикула = весь расход / ВСЕ корзины карточки # сравнение с планом
Рекламный CPL РК = расход РК / рекламные корзины (atbs) # диагностика кампании
CPO = расход / ВСЕ заказы товара
CPS (стоимость продажи) = расход / продажи после возвратов # факт после дозревания
ДРР = расход / выручка продаж после возвратов
Продажи после возвратов = отправления в статусе delivered минус те, по которым есть
финансовая операция «Получение возврата, отмены, невыкупа от покупателя». На Ozon FBO нет
отдельного статуса returned: отмена и невыкуп при доставке схлопнуты в cancelled, а
возврат после выкупа виден только в ozon_finance_operations. По ELS004 Black за 01.07–27.08
это 27 шт из 263 выкупленных = 10% сверх невыкупа.
⚠ Когорта должна дозреть. Пока в неделе много отправлений вне delivered/cancelled,
продажи и CPS ещё уедут — такую неделю помечать, а не сравнивать. Правило зрелости —
orders-ad-cpo-playbook.md.
6.4. Порог: вклад до рекламы
Единственный абсолютный эталон. Считается по факту ozon_finance_operations, привязанным к
отправлениям артикула, за окно ≥1 месяца:
нетто с Ozon = «Доставка покупателю»
− «Получение возврата, отмены, невыкупа от покупателя»
− «Доставка и обработка возврата, отмены, невыкупа»
− «Оплата эквайринга» − упаковка партнёрами и материалы
нетто на единицу = нетто с Ozon / (проданные единицы − возвращённые)
вклад до рекламы = нетто на единицу − себес (CostBook) − УСН 6% от покупательской цены
Отмены и невыкупы уже внутри: их стоимость размазана на те единицы, что доехали.
Пример, ELS004 Black, 01.07–27.08.2026: нетто 713 320 ₽ на 321 нетто-проданную единицу = 2 222 ₽/шт; − себес 850 − УСН 183 = вклад 1 189 ₽.
Безубыточность в выбранной границе затрат: CPS < вклад до рекламы оставляет
положительный результат после рекламы. Отношение вклад / CPS — запас до нуля.
Цель прибыли: CPS <= вклад до рекламы − margin из config/plan.yaml (§−1).
Положительный результат ещё не означает достижения цели. Эти сравнения оценивают
общую экономику артикула с рекламой, не доказывают её отдельный причинный вклад.
⚠ Что в этот вклад не входит: общемагазинные операции Ozon, не привязанные к отправлению (сбор первых отзывов, досрочная выплата, кросс-докинг, подписка Premium, страхование — по shop 4 это ≈106 ₽ на проданную единицу), и всё вне Ozon (ФФ, доставка до склада, ФОТ). Для строгой оценки вычитать; на вердикт по ELS004 Black это не влияло (запас 1.8× → 1.7×).
6.5. Две группы метрик: опережающие и основные
Разделять всегда — они ломаются в разных местах и лечатся разным.
| Группа | Метрики | Про что |
|---|---|---|
| Опережающие | показы РК, клики, CTR, CPC, клик→корзина, все корзины и общий CPL; отдельно рекламный CPL | стоимость и объём интереса; диагностика аукциона и креатива |
| Основные | все заказы, корзина→заказ, продажи после возвратов, CPS, ДРР | доходит ли приведённый интерес до денег |
Диагностическое правило. Опережающие ровные, а основные едут вниз — сначала проверить следующий этап воронки: наличие размера в кластере покупателя, срок доставки, цену, конкурентов, затем выкуп и возвраты. Это приоритет проверки, не доказательство, что реклама ни при чём: качество приведённого спроса могло измениться при прежней цене корзины. Само по себе повышение ставки не следует из такой просадки. Таблица гипотез — §−1.
Безубыточный общий CPL = вклад до рекламы × конверсия всех корзин→net-продажа.
Порог под цель прибыли = (вклад до рекламы − margin) × та же конверсия (§−1).
Это опережающие оценки; коэффициенты, их окна и допущения по возвратам назвать явно.
Рекламный CPL с этими общими порогами не сравнивать.
6.6. Что данными не решается — только эксперимент
Наблюдением нельзя получить: вклад рекламы отдельно от сезона; эластичность по цене; правильное деление бюджета между цветами/размерами.
Схема (одна на все такие вопросы). Плечо — одна пара цвет/размер, контроль — соседний цвет той же модели, окно — две недели, метрики — все корзины, корзина→заказ и CPS обоих плеч. Ставится сдвиг ровно одного параметра: бюджет ±30–50% либо цена кабинета ±10–15%.
🔴 Тест ставится на товаре в фазе роста, а не на уходящем сезоне. Контроль снимает тренд, но падающие объёмы убивают чувствительность. Ориентиры по чувствительности (80% мощности, 5% уровень, две недели на плечо, конверсия корзина→заказ ~30%):
| Объём на плечо | Ловится разница в заказах | Ловится разница в конверсии |
|---|---|---|
| 240 заказов / 900 корзин | ~26% относительных | ~6 п.п. |
| 480 заказов / 1 800 корзин | ~18% | ~4 п.п. |
| 100 заказов / 400 корзин | ~40% | ~9 п.п. |
ELS004 Black в июле–августе 2026 давал ~120 заказов и ~460 корзин в неделю на цвет — то есть на границе, где тест ещё имел смысл. К концу сезона объёмы падают, и окно закрывается.
Практический вывод: тест закладывается в план запуска нового товара, а не изобретается
задним числом. Статус запусков — ../Strategy-Operations/products/<товар>/launch.yaml
(скилл launch-operations); там же держать окно теста, плечо и контроль.
6.6a. Цена как фактор: проверено, зависимости не найдено
Разбор ELS004 Black M, Siluetta Ozon, 05.07–22.08.2026, 41 день с полными данными
(ozon_buyer_price_daily + воронка + постинги).
Корреляции цены покупателя со всей воронкой около нуля и со знаком «дороже → чуть больше корзин»: корзины +0.18, заказы +0.16, корзина→заказ +0.10. Внутри уровней остатков (главный конфаундер снят) — +0.08 / +0.05 / +0.19. Терцили по цене плоские: корзин в день 24.9 / 27.1 / 27.9, конверсия 29 / 33 / 28%.
⚠ Корреляция цены кабинета с корзинами (−0.59) — артефакт времени, а не эффект: 5 690 стояла почти весь июль, 5 100/5 490 — в августе. Уровней всего четыре и они не пересекаются во времени. Не читать как эластичность.
Квази-эксперимент 13.08 (цену black подняли 5 100 → 5 490, у brown и grafit не трогали):
| Товар | 29.07–05.08 | 06–12.08 | 13–18.08 | Цену меняли |
|---|---|---|---|---|
| black-M | 37% | 26% | 20% | −10%, затем +7.6% |
| black-S | 30% | 34% | 30% | −10%, затем +7.6% |
| brown-M | 27% | 35% | 32% | нет |
| grafit-M | 33% | 34% | 35% | нет |
Направление не воспроизводится: на снижении цены black-M ухудшился, а black-S улучшился; grafit при неизменной цене не просел вовсе. Второй эпизод — 14–15.07, самая низкая цена покупателя за период (−15%): заказы 6 и 9 при 10 накануне и 7 назавтра, конверсия 24 и 31% против 43 и 37%. Скидка подъёма не дала.
Почему цену покупателя нельзя брать за рычаг. За период цена кабинета имела размах 11.6%
(5 100–5 690), а цена покупателя — 34.1% (2 408–3 229), при corr(кабинет, покупатель) = +0.13.
При неизменной цене кабинета 5 690 витринная цена гуляла на 30.9% (σ = 6.6%), день к дню
в среднем на 3.6%, максимум на 14.7%. Доля покупателя от кабинета — 43–59%. Ozon двигает
витрину своей скидкой сильнее и почти независимо от нас.
⚠ Это не доказательство отсутствия эластичности: свою цену за 41 день подвинули всего на 11.6%, на фоне падающего сезона и рушащейся географии остатков. Такой дизайн не поймал бы и эффект средней силы. Мерить эластичность — только намеренным тестом по §6.6, на растущем товаре.
Что из этого следует для разбора: версию «просели заказы, потому что подняли цену» проверять этими данными можно и обычно она закрывается. Заявлять «цена не влияет» вообще — нельзя.
6.7. Дефицит рекламируемого размера бьёт по всей карточке
Карточка одна: реклама размера M генерирует показы и корзины всех размеров. Поэтому проверять остатки надо по тому размеру, на который льют бюджет, и не в штуках, а в числе складов с остатком — товар может быть «в наличии» суммарно, но отсутствовать в кластере покупателя, и тогда корзина не превращается в заказ из-за срока доставки.
Кейс ELS004 Black, август 2026 (M — 2/3 бюджета):
| Размер | Неделя | Расход | Корзины | Заказы | Корз.→заказ | Складов | Остаток |
|---|---|---|---|---|---|---|---|
| M | 26.07 | 12 020 | 145 | 52 | 36% | 22 | 121 |
| M | 09.08 | 11 617 | 230 | 50 | 22% | 14 | 56 |
| M | 16.08 | 12 523 | 195 | 47 | 24% | 6–8 | 24–33 |
| S | 16.08 | 4 279 | 170 | 53 | 31% | 13 | 37 |
| L | 16.08 | 0 | 96 | 16 | 17% | 2 | 2 |
Цена корзины при этом держалась 50–70 ₽ без тренда — реклама отработала честно. L показывает второй эффект: реклама выключена с 26.07, а корзины идут (74–111/нед) — их приносит карточка целиком; заказы упирались в остаток 1–6 шт.
Следствия: рекламировать размер с околонулевым остатком — слив; чинить надо поставку по
географии (ozon/supply-playbook.md), а не ставку.
6.8. Пороги мониторинга
| Метрика | Порог | Что означает |
|---|---|---|
| CTR | < 5.5% две недели подряд | проверить аудиторию, размещение, фото и ставку |
| Общий CPL | выше порога под целевую маржу | цель прибыли под риском; пересчитать по §−1 |
| Общий CPL | > 80% общего безубыточного CPL | небольшой запас до нуля, даже если цель прибыли уже нарушена |
| Корзина→заказ | < 28% | приоритет проверки следующего этапа; причину ещё нужно установить |
| Складов с остатком по рекламируемому размеру | < 10 | проверить географию наличия и доставку |
Источники цен для проверки версии «дело в цене» — ozon_buyer_price_daily
(ozon/buyer-price-playbook.md). ⚠ Покрытие дырявое: по shop 4 за 05.07–22.08 есть 41 день
из 49 (нет 25–28.07 и 19–26.08); по shop 2 прогоны с 23.08.2026 висят в статусе running с
rows_count = 0. Считать только по дням, где снимок есть.
Пороги калиброваны на ELS004 Black (комбинезон, средний чек ~5 400 ₽ цены продавца). Для другой категории пересчитывать, а не переносить.
6.9. Зависимость от подписки Premium
Блок опережающих метрик по карточке (все корзины, все показы, конверсия корзина→заказ) идёт
из ozon_sku_traffic_daily и доступен только при активной платной аналитике. Исторический
сбой shop 4: 22–31.08.2026 без тарифа Ozon отдавал лишь 8 метрик вместо ~60 (revenue,
orderedUnits, soldRevenue и динамика), корзины были нулевыми при живых заказах.
По плейбуку план-факта подписку продлили и пропуск добрали 01.09; срез 05.09 подтвердил
корзины за все дни 29.08–04.09. Не считать подписку сейчас отключённой по старой записи.
При новом сбое проверять реальные ненулевые корзины по датам, а не только статус
success и последнюю строку. Общий CPL считать по одинаковому покрытию расхода и корзин.
Без покрытия он неизвестен; отдельно доступны рекламный CPL и финансовый CPS после
дозревания. Добор прошлых дат описан в плейбуке план-факта.
7. Чек-лист разбора рекламы Ozon
Данные
- ☐ Свежесть кампаний и ad-stats проверена; при запросе свежего среза данные обновлены за окно?
- ☐ В
ozon_ad_metrics_dailyесть расход за окно? Если заказы массово нулевые при живом расходе, проверен парсер (§5); ноль у отдельной РК не объявлен ошибкой сбора? - ☐ Свод расхода по
placement/campaign_idснят — видно, где деньги (CPO vs поиск vs поиск+реком)? - ☐ Реклама сверена с finance (0.1%)?
- ☐ Дни с неполными данными исключены, а не занулены? (пропуски снимков аналитики, отключённый тариф §6.9, оборванный день по расходу). Все метрики считаются на одном наборе дней, и число дней указано в выводе.
Оценка (§6)
- ☐ Недели полные и выровнены по дню недели; недозревшие когорты помечены?
- ☐ Знаменатель — ВСЕ корзины и ВСЕ заказы; разложения на «рекламные/органические» нет?
- ☐ Продажи считаются после возвратов (
deliveredминус финансовые возвраты), а не поdelivered? - ☐ Вклад до рекламы пересчитан по свежему finance-окну, а не взят из старого разбора?
- ☐ Безубыточность отделена от цели
CPS <= вклад − marginиз план-факта; атрибутированный CPO/CPA не выдан за доказательство окупаемости? - ☐ Опережающие и основные метрики разведены; гипотеза о следующем этапе воронки не выдана за доказанную причину или исключение влияния рекламы?
- ☐ Проверены остатки рекламируемого размера в разрезе числа складов (§6.7)?
- ☐ Версия «дело в цене» проверена по
ozon_buyer_price_daily— и цена кабинета, и цена покупателя, только на днях со снимком (§6.6a)?
Вывод пользователю
- ☐ Названо, какие решения данные поддерживают, а какие требуют эксперимента (§6.6)?
- ☐ Если предлагается тест — товар в фазе роста и объёмов хватает на чувствительность, а не «поставим на уходящем сезоне»?
- ☐ Если копаем поиск — фразы тянем только по
TOP_PROMOTION; помним: CTR ≠ конверсия, минус-слов на Ozon нет? - ☐ Взяты
marginиadsнужного артикула из плана, проверены дата решения и пол цены? - ☐ Первая таблица содержит число всех корзин, все заказы и весь расход артикула; общий и рекламный CPL явно различаются?
- ☐ Коэффициенты конверсии/выкупа, окна, fallback и малые выборки обозначены; скользящий выкуп не назван полностью зрелым?
- ☐ При анализе оставленных РК проверен текущий статус, сохранён расход отключённых; не приписаны все прежние корзины только оставшимся РК?
- ☐ Сегодняшний расход отделён, если общих корзин за сегодня ещё нет; повторные выгрузки и изменения данных не склеены молча?
- ☐ Сравнение размещений учитывает размер, CPC, конверсию, бюджет и наличие; замена на новую РК сформулирована как гипотеза?
- ☐ Полный разбор сохранён в
data/ads/YYYY-MM-DD/advertising_analysis_YYYY-MM-DD.md(либо отдельный срез с HHMM), ссылки на план и исходные данные приложены? - ☐ Рекомендации отделены от исполненных действий; настройки не менялись без команды?
8. Реальный кейс (HZ030-Brown, Мой Ozon, июнь 2026)
Артикул убыточен по юните; реклама 25 263 ₽ = 60% бюджета магазина. Разложение: CPO (ДРР 10%, управляемо) ≈ 8.5к + CPC внутри CPO ≈ 8.6к + CPC «Поиск» 6.4к + CPC «поиск+полки» 1.7к. ~16.7к из 25.3к = CPC на общих фразах («комбинезон женский летний», «Каталог» — CTR 1.7–2.7%) с неуправляемым ДРР — вот это утечка, а не CPO-10%. Решение: по убыточным SKU оставлять CPO (ДРР-cap), а поисковый CPC резать. См. [[ads-playbook]] §3 (фразы), §2 (разрез по типам).
9. Реальный кейс (ELS004 Black, Siluetta Ozon, июль–август 2026)
Разбор, на котором построен §6. Окно 05.07–22.08, недели полные, только дни с полными данными (39 из 42 — пропуски снимков 25–27.07 и 20.08).
Опережающие держатся ровно: цена корзины 50–70 ₽, клик→корзина 3.7–4.1% без тренда, CPC ~2.3 ₽. Реклама отработала предсказуемо весь период.
Основные поехали:
| Неделя | Расход | Корз. всего | Заказы | Корз.→заказ | CPO | Продажи | CPS | ДРР |
|---|---|---|---|---|---|---|---|---|
| 05.07–11.07 | 13 529 | 322 | 98 | 30% | 138 | 23 | 588 | 10.3% |
| 19.07–25.07 | 13 016 | 323 | 105 | 33% | 124 | 37 | 352 | 6.2% |
| 02.08–08.08 | 16 910 | 519 | 171 | 33% | 99 | 50 | 338 | 6.4% |
| 09.08–15.08 ⚠ | 16 753 | 502 | 129 | 26% | 130 | 43 | 390 | 7.5% |
| 16.08–22.08 ⚠ | 16 802 | 461 | 116 | 25% | 145 | 29 | 579 | 10.7% |
Итого за зрелое окно: расход 90 798 ₽, корзины 1 516 РК из 2 402 всего (доля РК 63%), заказы 731, продажи после возвратов 222 шт на 1 207 365 ₽. CPS 408 ₽ при вкладе 1 189 ₽ — запас 2.9×. Безубыточная цена корзины 110 ₽ против факта 60 ₽.
Диагноз: опережающие ровные, основные вниз → смотреть ниже воронки. Нашлось в §6.7: у размера M (2/3 бюджета) число складов с остатком упало 22 → 6, и конверсия корзина→заказ там просела 36% → 22%. Цена покупателя в тот же период снизилась (3 093 → 2 702 ₽), то есть версия «подняли цену» отпадает.
Принятые решения: рекламу не трогать (запас 2.9× и r=0.94 расход↔заказы); приоритет — поставка M по географии; L включать только после пополнения (с 26.07 по 27.08 расход на него был 0 при живых 74–111 корзинах в неделю и остатке 1–6 шт).