Мастер отчётов в Директе отдаёт один срез за запрос. Хочешь сравнить расход по площадкам — строишь один отчёт; нужна понедельная динамика стоимости лида — строишь второй; смотришь, какая кампания просела — третий. Между несколькими клиентскими логинами добавьте ещё перелогины. Картина всего аккаунта в этой схеме существует только в голове аналитика, и каждое утро её приходится пересобирать заново.

Мне это мешало достаточно, чтобы потратить вечер и вытащить данные напрямую из Reports API в Google-таблицу: один лист — весь аккаунт по неделям, рядом разрезы по площадкам и по каждой кампании, плюс подневное скользящее окно. Обновляется само через Apps Script. Ниже разберу, как это устроено под капотом, где у конструкции стенки (их хватает) и почему свои боевые дашборды я в итоге всё равно унёс в DataLens. Таблица — пустой шаблон, отдаю по ссылке в конце, можно скопировать и распотрошить.

Адресат — те, кто сам копается в Директе и аналитике. Написали такой инструмент — будет с чем сверить решения; только думаете — сэкономите вечер на граблях.

Почему не Мастер отчётов и почему не DataLens сразу

Мастер отчётов — нормальный инструмент под свою задачу: разовый срез с группировкой и фильтром. Проблема в модели. Он построен вокруг одного отчёта за раз, а контроль аккаунта требует держать рядом несколько разрезов: общий тренд, Поиск против Сетей, динамика по кампаниям. Я каждый раз строил три-четыре отчёта и склеивал их глазами. Дорого по вниманию, и легко пропустить аномалию, которой нет в текущем срезе.

Логичная альтернатива — DataLens. Пять лет до агентства я работал в Яндексе и привык, что любой показатель живёт на дашборде: сразу, в динамике, в нужной нарезке. Перенести этот подход на клиентские кабинеты хотелось с самого начала.

Но честная инфраструктура под DataLens складывается из нескольких частей: хранилище (у меня ClickHouse), регулярная заливка статистики Директа в таблицы, SQL под каждый чарт и собранные дашборды. Под десяток аккаунтов и зрелый процесс — оправданно. Под один кабинет на старте — оверкилл: на поднятие и поддержку уйдёт больше времени, чем сэкономит сам дашборд.

Промежуточный слой между «строю отчёты руками» и «поднимаю ClickHouse» — Google Sheets с Apps Script. У таблицы уже есть UI, хранение, шаринг и движок формул; мне оставалось дописать выгрузку из API и разложить цифры по разрезам. Я взял готовый скрипт-основу под Reports API, переписал под свою структуру листов и довёл до читаемого вида: добавил уровни, динамику и быстрые переходы в кабинет.

Как данные попадают в таблицу

Источник — Reports API Яндекс.Директа (сервис Reports). Запрос возвращает TSV-отчёт с заданным набором полей, диапазоном дат и параметрами атрибуции. Транспорт со стороны таблицы — UrlFetchApp в Apps Script: формируем тело отчёта, шлём POST с заголовком авторизации, парсим TSV и раскладываем по листам.

Поля отчёта (FieldNames), которые тянутся из API:

  • CampaignId, CampaignName — идентификатор и название кампании;

  • Cost — расход (в валюте кабинета; параметр НДС вынесен в настройки, об этом ниже);

  • Impressions, Clicks — показы и клики;

  • Bounces — отказы;

  • Conversions — конверсии по целям; в запросе задаются параметры Goals (ID целей Метрики) и AttributionModels, и API возвращает отдельную колонку на каждую цель — имя вида Conversions_<GoalId>_<Модель> (шаблон рассчитан на десяток целей);

  • AdNetworkType — тип площадки: SEARCH или AD_NETWORK, на нём держится разрез Поиск/Сети.

CTR, CPC, CR и стоимость лида в API не запрашиваются — они считаются формулами уже в таблице из расхода, кликов и суммы конверсий. Так меньше расхождений: одна и та же конверсия не приедет два раза под разными именами.

Один нюанс, на котором легко споткнуться, — атрибуция конверсий. По умолчанию в шаблоне стоит LYDC — последний переход из Яндекс.Директа (не путать с LSC, последним значимым переходом: это разные модели и разные цифры). От модели атрибуции напрямую зависит, сколько конверсий API отдаст за период, поэтому если ваши цифры расходятся с интерфейсом Метрики — первым делом сверяйте именно модель, а не ищите баг в формулах.

Обновление повешено на устанавливаемые (installable) триггеры Apps Script — на открытие таблицы и на правку полей конфигурации. Важно, что именно installable, а не простые onOpen/onEdit: простые триггеры запускаются без авторизации пользователя и не имеют права вызывать UrlFetchApp, а нам нужен внешний запрос к API — поэтому триггеры ставятся через ScriptApp/интерфейс триггеров и работают уже с разрешениями. Плюс ручной перезапуск через чекбокс на листе — удобно, когда хочешь дёрнуть данные, ничего не меняя. Здесь же сидит первое тихое ограничение: время выполнения скрипта и число вызовов UrlFetchApp в Apps Script квотируются. На одном аккаунте с разумным окном дат вы в лимиты не упрётесь, но проектировать тут «выгрузку за два года по всем кампаниям ежечасно» бессмысленно — об этом в разделе про предел.

Структура листов: три уровня обзора

Логика подачи — от общего к частному, тремя уровнями. По строкам идут метрики, по столбцам — периоды (недели или дни), на пересечении — значение. Привычная сводная таблица, читается по диагонали.

Уровень 1. Весь аккаунт по неделям. Строки: недельный бюджет (план открутки), расход, клики, количество лидов из Директа, CR, стоимость лида. Сюда же — строка «План» для сверки план/факт по бюджету. Это верхнеуровневый монитор: видно общее состояние канала и сразу заметно, если расход поехал относительно плана.

Уровень 2. Площадки — Поиск и Сети по отдельности. На каждый тип: расход, клики, CTR, количество лидов, CPC, CR, стоимость лида. Делёж идёт по полю AdNetworkType. Самый частый диагноз отсюда — Сети набирают клики и формальные конверсии, а стоимость качественного лида по ним заметно хуже Поиска. На общем уровне это усреднялось и пряталось.

Уровень 3. Кампании. На каждую РК: номер, название, бюджет кампании, расход, клики, CTR, CPC, количество лидов, CR, стоимость лида. Рядом с каждой строкой — три ссылки-перехода: «Стата» (статистика кампании в Директе), «Ред.» (редактирование), «Ист.» (история). Это превращает таблицу из монитора в точку входа: увидел проблемную кампанию — провалился в её статистику одним кликом, без поиска нужного кабинета и перелогинов.

Для корректной работы переходов в «Стату» нужен отдельный параметр — о нём ниже, в настройке. Ссылки ведут в старый интерфейс статистики, и без этого токена они открываются криво.

Слой качества: две цены лида в одной таблице

Это часть, ради которой всё и затевалось. Лиды из Директа (конверсии по целям Метрики) — это вершина воронки: человек оставил заявку. Но заявка и квалифицированный лид — разные деньги, и кампания вполне бывает дешёвой по заявкам и дорогой по тем, кто дошёл до отдела продаж.

Поэтому в сводке под лидами из Директа заведены ещё три блока строк:

  • новые лиды из Roistat — со своими CR и стоимостью;

  • лиды «в работе + квалифицированные» — со своими CR и стоимостью;

  • квалифицированные лиды — со своим CR и стоимостью квал-лида.

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

Важная честность про реализацию: эти строки заполняются руками. Из Reports API качество стадий не вытащить — данные о том, кто из лидов дошёл до «квала», живут в Roistat и CRM, в шаблоне под них просто подготовлены ячейки для ручного ввода раз в неделю. Можно дотянуться до Roistat по их API и закрыть ввод автоматикой, но это уже другой класс системы и другая стоимость поддержки. Для одного аккаунта один ввод в неделю оказался разумным компромиссом.

Динамика: понедельный тренд и подневное скользящее окно

Динамика разнесена на две вкладки, потому что недельный и дневной горизонты ловят разные вещи.

Понедельная вкладка держит тренд: колонки идут по неделям, видно, куда ползёт стоимость лида от недели к неделе. Здесь вылезает дата начала из настроек — группировка считает недели от стартовой даты, и если старт стоит не на понедельник, границы недель поедут относительно календарных. Сравнивать такие недели между собой уже бессмысленно.

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

Связка горизонтов и даёт ту самую «минуту утром»: тренд держит понедельный лист, дневное окно подсвечивает свежую аномалию, провалиться в неё можно через ссылку «Стата».

Настройка: пять полей на листе API

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

  1. Скопировать шаблон себе на Google Drive (File → Make a copy). Apps Script-проект копируется вместе с таблицей. При первом запуске Google попросит выдать скрипту разрешения (доступ к таблице и внешним запросам) — стандартный диалог авторизации Apps Script.

  2. OAuth Token* — получается одной ссылкой через oauth.yandex.ru: это штатный OAuth Яндекса, логин и пароль не уходят ни в таблицу, ни третьим лицам, в ячейку кладётся только сам токен. Практическая деталь: на время авторизации лучше выключить VPN — сервисы Яндекса под VPN нередко отвечают некорректно, и токен либо не выдаётся, либо потом не работает.

  3. Client login* — логин, на котором лежит Директ. Именно владелец кампаний, не агентский логин с делегированным доступом, иначе отчёт приедет пустым.

  4. Date from* — стартовая дата, обязательно понедельник (см. выше про границы недель). Date to оставляем равной сегодняшней дате, чтобы окно всегда было актуальным.

  5. Goals — ID целей из Яндекс.Метрики (Метрика → «Цели», столбец «Номер цели»), которые вы считаете лидом; через ;, до десяти. Цели суммируются — по сумме конверсий считаются количество лидов, CR и CPL.

Ещё два необязательных поля: VAT (NO/YES — включать ли НДС в расход; в запросе это параметр отчёта IncludeVAT) и Token stat — отдельный токен из старого интерфейса статистики Директа, нужен исключительно для корректных переходов по ссылке «Стата». Без него таблица считает всё верно, просто переходы в статистику открываются криво.

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

function pullDirectReport(cfg) {
  const body = {
    params: {
      SelectionCriteria: { DateFrom: cfg.dateFrom, DateTo: today() },
      Goals: cfg.goals,                 // ID целей Метрики → колонки Conversions_<GoalId>_<Модель>
      AttributionModels: ["LYDC"],
      FieldNames: ["CampaignId","CampaignName","AdNetworkType",
                   "Cost","Impressions","Clicks","Bounces","Conversions"],
      ReportType: "CUSTOM_REPORT",
      DateRangeType: "CUSTOM_DATE",
      Format: "TSV"
    }
  };
  const resp = UrlFetchApp.fetch(REPORTS_ENDPOINT, {
    method: "post",
    contentType: "application/json",
    headers: { Authorization: "Bearer " + cfg.token,
               "Client-Login": cfg.clientLogin,
               "Accept-Language": "ru",
               "returnMoneyInMicros": "false",   // Cost в валюте кабинета, а не в микроединицах
               "processingMode": "auto" },
    payload: JSON.stringify(body),
    muteHttpExceptions: true
  });
  return parseTsv(resp.getContentText());   // → строки по кампаниям
}

Дальше распарсенные строки группируются по AdNetworkType для уровня площадок, агрегируются для уровня аккаунта и раскладываются по неделям/дням; CTR, CPC, CR и CPL дорисовывают формулы на листах. Полная инструкция со скриншотами лежит внутри самой таблицы.

Где у конструкции предел

Раздел, ради которого стоит дочитать, если вы такое собираете. Таблица закрывает контроль одного аккаунта и упирается в три стенки.

Ручной слой качества. Строки Roistat и «квала» заполняются вручную. Пока аккаунт один и ввод раз в неделю — терпимо. Дальше это либо съедает время, либо требует интеграции с Roistat/CRM по API, и тогда вы уже строите не таблицу, а маленький ETL.

Лимиты Apps Script и API. Время выполнения скрипта, число и частота вызовов UrlFetchApp, объём данных, который Sheets держит без тормозов, — всё это конечно. Несколько аккаунтов или длинная история по всем кампаниям с частым обновлением упрутся в квоты и в скорость пересчёта листа. Архитектурно это потолок инструмента, а не баг конкретной реализации.

Хрупкость обновления. Триггеры onOpen/onEdit и ручной чекбокс — это не планировщик с ретраями и алертами. Сбой запроса к API в худшем случае останется тихим: данные не обновились, а ты узнаешь об этом, только заглянув в таблицу.

Когда этих стенок становится тесно, дальше дорога одна — в нормальное хранилище. Свои боевые дашборды я перенёс в DataLens поверх ClickHouse: статистика заливается регулярно, обновление стабильнее, разрезов и визуализаций кратно больше, несколько аккаунтов живут рядом. Это и есть зрелая версия той же идеи.

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

Что забрать с собой

Практические тезисы, если будете делать своё:

  • Reports API + UrlFetchApp в Apps Script — рабочая связка под мониторинг одного аккаунта, без отдельного бэкенда.

  • Минимум полей из API (Cost, Clicks, Conversions_1..10, AdNetworkType), а производные CTR/CPC/CR/CPL — формулами в таблице: меньше дублей и расхождений.

  • Модель атрибуции (в шаблоне LYDC) фиксируйте явно и сверяйте с Метрикой: чаще всего «неправильные» цифры растут именно отсюда.

  • Дата старта строго с понедельника, иначе понедельная группировка теряет смысл.

  • Два горизонта динамики: понедельный тренд и подневное скользящее окно ловят разные классы проблем.

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

  • Лимиты Apps Script/Sheets — реальный потолок. Перерастёте — переезжайте в хранилище и BI (у меня это DataLens на ClickHouse).

Шаблон — пустая таблица без клиентских данных: Google-таблица. Скопируйте себе (File → Make a copy) — Apps Script-проект переедет вместе с ней, инструкция со скриншотами лежит на первом листе. Переписывайте структуру под себя.

А как у вас устроен ежедневный контроль Директа между отчётами — свой дашборд, BI поверх выгрузок, сторонний сервис? Особенно интересно, как решаете слой качества лида: тянете из CRM автоматически или заносите руками. Любопытно сверить решения в комментариях.

Комментарии (0)