Обложка статьи PPC Rebels про GAQL и запросы к Google Ads API в 2026 году

GAQL в 2026: запросы к Google Ads API без кривых цифр

Вы выгрузили расходы за месяц через Google Ads API, свели их в отчёт — и сумма не сошлась с кабинетом. На 4%, на 11%, иногда вдвое. Баг ищут в коде, в токенах, в BigQuery. Почти всегда он в одной строке: запросы к Google Ads API выглядят как обычный SQL, но ведут себя иначе, и ломается всё в одном месте — в SELECT попал лишний сегмент, или фильтр по дате отрезал не то окно, или метрику уровня кампании сложили со строками уровня ключевого слова.

GAQL (Google Ads Query Language) выглядит как SQL и ведёт себя иначе. Этот текст — разбор того, как язык устроен на самом деле: какие сущности можно запрашивать вместе, почему строки размножаются, где теряются кампании без показов и как за десять минут сверить выгрузку с интерфейсом. Если вы пишете отчётность на API или принимаете её от разработчика — после статьи вы сможете читать чужой запрос и видеть, где он врёт.

GAQL — это не SQL, и в этом вся проблема

Синтаксис знакомый: SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT .... Дальше сходство заканчивается, и каждое отличие — источник ошибки в отчёте.

  • Нет JOIN. В FROM указывается ровно один ресурс. Связанные сущности доступны не потому, что вы их присоединили, а потому что Google заранее решил, какие атрибуты «видны» с этого ресурса. Из ad_group можно взять campaign.name, но нельзя произвольно подтянуть данные другого аккаунта или несвязанный объект.
  • Нет агрегатных функций. SUM(), COUNT(), GROUP BY в GAQL отсутствуют. Агрегацию выполняет сервер: уровень детализации задаётся ресурсом в FROM и набором сегментов в SELECT. Складывать строки вы будете уже у себя.
  • Нет подзапросов и вычисляемых выражений. Нельзя написать metrics.cost_micros / 1000000 AS cost. Деление, конвертация, производные метрики — всё на вашей стороне.
  • Запятые в SELECT имеют цену. Каждый добавленный сегмент меняет количество строк в ответе, а значит и смысл всех метрик в этих строках.

Практический вывод: GAQL — не язык аналитики, а язык выборки, и запросы к Google Ads API нужно проектировать под эту логику. Аналитика начинается после того, как данные легли в вашу витрину. Как эту витрину строить, мы подробно разобрали в материале про выгрузку Google Ads в BigQuery — там как раз показано, какие таблицы складывать и как не дублировать строки при ежедневной догрузке.

Анатомия запроса: четыре типа полей

Любое поле в GAQL относится к одной из четырёх групп, и от группы зависит поведение строки.

Группа Префикс Что это Влияет на число строк
Ресурс campaign., ad_group. Сам объект и его атрибуты: имя, статус, тип Да — определяет уровень
Атрибуты связанных ресурсов campaign.name из ad_group Поля «родителя», доступные с текущего ресурса Нет
Сегменты segments. Разрезы: дата, устройство, сеть, тип клика Да — размножают строки
Метрики metrics. Показы, клики, расход, конверсии Нет, но пересчитываются под разрез

Минимальный честный запрос расхода по кампаниям за период выглядит так:

SELECT
  campaign.id,
  campaign.name,
  campaign.status,
  metrics.impressions,
  metrics.clicks,
  metrics.cost_micros,
  metrics.conversions
FROM campaign
WHERE segments.date BETWEEN '2026-10-01' AND '2026-10-20'
  AND campaign.status != 'REMOVED'
ORDER BY metrics.cost_micros DESC

Обратите внимание: segments.date стоит в WHERE, но не в SELECT. Это и есть разница между «расход по кампании за период» и «расход по кампании по дням». Первый запрос вернёт одну строку на кампанию, второй — двадцать.

Шесть ошибок, из-за которых цифры расходятся с кабинетом

1. Сегмент в SELECT размножил строки

Самая частая. Разработчик добавил segments.device «чтобы было», и теперь на каждую кампанию приходится до четырёх строк — MOBILE, DESKTOP, TABLET, CONNECTED_TV. Если потом взять первую строку как «данные кампании», расход упадёт в несколько раз. Если сложить metrics.ctr по строкам — получится бессмыслица.

Правило: сегмент в SELECT = ещё одно измерение таблицы. Сегменты, которые чаще всего ломают сведение: segments.date, segments.device, segments.ad_network_type, segments.conversion_action, segments.click_type. Какие разрезы и когда действительно меняют выводы, разобрано в статье про сегменты в отчётах Google Ads — логика там та же, что и в API, просто в интерфейсе её прячет кнопка «Сегменты».

2. Кампании без показов исчезли

Если в SELECT есть хотя бы одна метрика, API возвращает только строки, по которым за период была статистика. Кампания на паузе, группа без показов, ключ, который не сработал — их в ответе не будет. Отчёт «все кампании аккаунта» так не построить.

Решение — два запроса. Первый без метрик, чисто за структурой (SELECT campaign.id, campaign.name, campaign.status FROM campaign), второй со статистикой. Соединяете по campaign.id на своей стороне, пустые заполняете нулями. Иначе каждый отчёт будет тихо прятать всё, что не откручивалось, — а именно там обычно и живут проблемы.

3. Даты: часовой пояс аккаунта и «недозревшие» конверсии

Все даты в GAQL — в часовом поясе рекламного аккаунта, а не вашего сервера и не UTC. Если аккаунт в America/New_York, а скрипт запускается по Москве, граница суток уедет, и ежедневная выгрузка будет систематически недобирать или перебирать вечерний трафик.

Второй слой — конверсии. Константы вроде DURING LAST_30_DAYS считают окно до вчера включительно, сегодняшний день в них не входит. А метрика metrics.conversions атрибутируется к дате клика, а не к дате конверсии: вчерашняя строка будет дозаполняться ещё неделями по мере того, как пользователи возвращаются. Выгрузка «за вчера», снятая один раз и больше не обновляемая, занижает конверсии по определению. Это ровно та же механика, из-за которой расходятся кабинет и аналитика, — подробный разбор в материале про расхождение конверсий Google Ads и GA4.

Рабочая практика: перезаписывать последние 14–30 дней при каждой выгрузке, а не только вчерашний день. Окно выбирайте по своему реальному лагу конверсий, а не «на глаз».

4. Конверсии посчитаны дважды

metrics.conversions — только действия, отмеченные как основные для оптимизации. metrics.all_conversions — все, включая вторичные. Это разные числа, и в кабинете они лежат в разных столбцах. Половина «расхождений» объясняется тем, что в отчёте взяли одну метрику, а в интерфейсе смотрят на другую.

Отдельная ловушка — segments.conversion_action. Этот сегмент разбивает строку по типам конверсий, и если вы потом просуммируете metrics.conversions вместе с ещё одним сегментом, часть действий посчитается повторно. Если нужен разрез по действиям — делайте его отдельным запросом и не смешивайте с общим отчётом по расходу.

5. Метрики разных уровней сложили в одну таблицу

Расход с ресурса campaign, расход с keyword_view и расход с search_term_view не обязаны совпадать. Поисковые запросы не покрывают трафик PMax и Demand Gen; ключевые слова не покрывают динамические форматы; часть показов не атрибутируется на уровень ключа вовсе. Складывать такие выгрузки в одну таблицу «расходов» — гарантированная ошибка.

И отдельно: средние метрики не складываются. metrics.ctr, metrics.average_cpc, metrics.cost_per_conversion нужно пересчитывать из сырых компонентов (клики / показы, расход / клики), а не усреднять по строкам.

6. Микроединицы и валюта

Все денежные поля приходят в микроединицах: metrics.cost_micros, campaign_budget.amount_micros, ставки. Делить на 1 000 000. Валюта — та, что задана в аккаунте, и API её не конвертирует: мультиаккаунтный отчёт без приведения к одной валюте показывает сумму, которой не существует. Валюту отдаёт customer.currency_code, часовой пояс — customer.time_zone. И то и другое меняется только при пересоздании аккаунта, о чём мы писали в разборе лимитов аккаунта Google Ads.

Ресурсы, которые закрывают 90% отчётности

Ресурс Что отдаёт Нюанс
customer Аккаунт: валюта, часовой пояс, статус Первое, что нужно запросить перед любой выгрузкой
campaign Кампании и их статистика Базовый уровень большинства отчётов
campaign_budget Бюджеты, в том числе общие Суммы в микроединицах
ad_group / ad_group_ad Группы и объявления, статусы модерации Статус policy-проверки лежит здесь
ad_group_criterion Ключи, аудитории, плейсменты, минус-слова Разные типы критериев в одном ресурсе
keyword_view Статистика по ключевым словам Только там, где есть ключи
search_term_view Реальные поисковые запросы Покрывает не весь трафик; агрегируется с задержкой
asset_group / asset_group_asset Структура Performance Max Отчётность PMax собирается из нескольких ресурсов
geographic_view / user_location_view География: «физическое присутствие» и «интерес» Это разные ресурсы, не путать
change_event История изменений в аккаунте Глубина ограничена; требует фильтра по дате
click_view Отдельные клики с GCLID Только один день за запрос и ограниченная глубина — не для исторических выгрузок

Ресурс change_event заслуживает отдельного упоминания: это та же история изменений, по которой диагностируют просадки, только машиночитаемая. Собрав её в свою базу, вы получаете алерт «кто и что поменял за час до падения CPA» вместо ручного копания. Сам процесс диагностики разобран в статье про историю изменений Google Ads.

Фильтры, которые экономят квоту и нервы

GAQL поддерживает =, !=, >, <, IN, NOT IN, LIKE, CONTAINS ANY, REGEXP_MATCH, BETWEEN и константы DURING (TODAY, YESTERDAY, LAST_7_DAYS, LAST_30_DAYS, THIS_MONTH, LAST_MONTH).

Несколько практичных приёмов:

  1. Фильтруйте на сервере, а не в коде. Выгрузить всё и отфильтровать у себя — значит потратить квоту и время на строки, которые выбросите.
  2. Для view-ресурсов дата обязательна. Многие «отчётные» ресурсы просто не отдадут данные без ограничения по segments.date.
  3. Исключайте удалённое. campaign.status != 'REMOVED' и аналогично для групп — иначе в отчёт попадут годы мусора.
  4. Используйте searchStream для больших выгрузок. Потоковый метод отдаёт результат без постраничной навигации и заметно быстрее на объёмах; обычный search удобнее для маленьких точечных запросов.
  5. Помните про PARAMETERS. include_drafts подтягивает черновики и эксперименты, omit_unselected_resource_names убирает служебные поля из ответа и уменьшает объём.

Если запрос отдаёт сотни тысяч строк — почти наверняка в SELECT лишний сегмент, а не в аккаунте слишком много сущностей. Уберите сегменты по одному и смотрите, на каком число строк падает на порядок.

Как проверить запросы к Google Ads API до продакшена

Три инструмента, которые экономят часы отладки:

  • Query Builder и валидатор в документации Google Ads API. Собирают запрос мышкой и сразу подсвечивают несовместимые поля — а совместимость в GAQL нетривиальна: не каждый сегмент разрешён с каждым ресурсом.
  • Метаданные через сам API. Запрос к google_ads_field отдаёт по каждому полю, с какими ресурсами и сегментами оно совместимо и является ли оно выбираемым, фильтруемым и сортируемым. Это надёжнее, чем угадывать по документации.
  • Сверка на одном дне. Прежде чем запускать выгрузку за год, выгрузите один день по одной кампании и сравните четыре числа с интерфейсом: показы, клики, расход, конверсии. Сошлось — масштабируйте.

Процедура сверки за десять минут

  1. Возьмите один аккаунт, один день, одну кампанию со стабильным трафиком.
  2. В кабинете выставьте тот же день и снимите четыре метрики без сегментов.
  3. Выполните запрос без единого сегмента в SELECT, только с фильтром по дате.
  4. Сравните показы и клики. Расходятся — проблема в дате или часовом поясе.
  5. Сравните расход. Расходится при совпавших кликах — проблема в микроединицах или валюте.
  6. Сравните конверсии. Расходятся — смотрите conversions против all_conversions и лаг конверсий.
  7. Только после этого добавляйте сегменты — по одному, сверяя сумму с общей строкой на каждом шаге.

Три запроса к Google Ads API, которые стоит держать под рукой

Ниже — заготовки, которые закрывают три регулярных задачи. Подставьте свои даты и пороги.

Поисковые запросы, на которые ушли деньги без конверсий

SELECT
  campaign.name,
  ad_group.name,
  search_term_view.search_term,
  segments.keyword.info.match_type,
  metrics.impressions,
  metrics.clicks,
  metrics.cost_micros,
  metrics.conversions
FROM search_term_view
WHERE segments.date DURING LAST_30_DAYS
  AND metrics.clicks > 5
  AND metrics.conversions = 0
ORDER BY metrics.cost_micros DESC
LIMIT 500

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

Кампании, упирающиеся в бюджет

SELECT
  campaign.id,
  campaign.name,
  campaign_budget.amount_micros,
  campaign.primary_status,
  campaign.primary_status_reasons,
  metrics.impressions,
  metrics.cost_micros
FROM campaign
WHERE segments.date DURING YESTERDAY
  AND campaign.status = 'ENABLED'
ORDER BY metrics.cost_micros DESC

Поля primary_status и primary_status_reasons — недооценённая пара. Именно они объясняют, почему кампания включена, но не откручивается: ограничение бюджетом, отсутствие активных объявлений, проблемы с оплатой, отклонённые ассеты. Это готовая основа для ежедневного алерта «что сегодня не работает».

Изменения в аккаунте за последние сутки

SELECT
  change_event.change_date_time,
  change_event.user_email,
  change_event.change_resource_type,
  change_event.resource_change_operation,
  change_event.changed_fields,
  campaign.name
FROM change_event
WHERE change_event.change_date_time DURING LAST_14_DAYS
ORDER BY change_event.change_date_time DESC
LIMIT 1000

Обратите внимание: этот ресурс фильтруется по собственному полю времени, а не по segments.date, и требует явного LIMIT. Поле user_email отвечает на главный вопрос при разборе просадки — кто внёс правку. В аккаунтах с несколькими подрядчиками это первая вещь, которую стоит автоматизировать.

И про обход аккаунтов в MCC

Отдельного «запроса по всему MCC» не существует: каждый запрос выполняется в контексте одного клиентского аккаунта. Схема всегда одна — сначала получить список подчинённых аккаунтов, затем пройти по ним циклом, аккуратно обрабатывая ошибки на уровне отдельного аккаунта. Один заблокированный или закрытый аккаунт не должен ронять всю ночную выгрузку: ошибка логируется, цикл идёт дальше. И не забывайте приводить суммы к одной валюте перед агрегацией — иначе сводный отчёт по группе аккаунтов покажет число, не имеющее физического смысла.

Версии API: почему рабочий запрос перестаёт работать

GAQL привязан к версии Google Ads API, а версии выходят регулярно и так же регулярно отключаются. Поля переименовывают, ресурсы объединяют, отдельные сегменты исчезают вместе с устаревшими типами кампаний. Запрос, написанный год назад, может молча отдавать не то или падать с ошибкой несуществующего поля.

Минимальная гигиена: фиксируйте версию API в коде явно, держите список запросов в репозитории, а не в головах, и проверяйте release notes при каждом обновлении. Подробный календарь релизов и сансетов — в материале про версии Google Ads API. Если вы только подступаетесь к интеграции, начните с получения доступа к Google Ads API: developer token, проект в Cloud Console и уровни доступа — отдельный квест до первой строчки GAQL.

Когда GAQL избыточен

Честный ответ: чаще, чем кажется. Если задача — «раз в неделю прислать расход по кампаниям на почту», это делается встроенными средствами кабинета без единой строки кода. Граница между «хватит интерфейса» и «пора в API» разобрана в статье про Google Ads API вместо скриптов.

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

И последнее. Хорошая отчётность не делает рекламу прибыльной — она лишь показывает правду быстрее. Сама экономика кампаний собирается на уровне структуры, ставок и качества трафика. Если вы разбираетесь с Google Ads системно, посмотрите гайд по Google Ads и формат обучения работе с Google Ads от команды PPC Rebels — там разобрана практическая часть, которой в документации API принципиально нет.

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

FAQ

Чем GAQL отличается от обычного SQL?

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

Почему сумма расхода из API не совпадает с кабинетом?

Три главные причины: в SELECT попал сегмент, который размножил строки; период посчитан в другом часовом поясе; расход не поделён на 1 000 000, потому что приходит в микроединицах. Проверяйте в этом порядке.

Куда делись кампании, у которых нет показов?

Если в SELECT есть хотя бы одна метрика, строки без статистики не возвращаются. Структуру нужно запрашивать отдельным запросом без метрик и соединять с данными на своей стороне.

В чём разница между metrics.conversions и metrics.all_conversions?

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

Почему вчерашние конверсии растут задним числом?

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

Можно ли одним запросом выгрузить данные по всем аккаунтам MCC?

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

Как узнать, какие поля совместимы между собой?

Через метаданные самого API: запрос к google_ads_field отдаёт для каждого поля списки совместимых ресурсов и сегментов и признаки «выбираемое / фильтруемое / сортируемое». Это точнее, чем перебирать варианты руками.

Что использовать — search или searchStream?

searchStream для больших выгрузок: отдаёт поток без постраничной навигации и работает быстрее на объёмах. Обычный search удобнее для небольших точечных запросов, где нужен понятный постраничный ответ.

Можно ли через GAQL что-то изменить в аккаунте?

Нет. GAQL — язык чтения. Изменения выполняются отдельными mutate-операциями соответствующих сервисов API.

Почему запрос к click_view возвращает ошибку?

Этот ресурс требует фильтра ровно на один день и имеет ограниченную глубину хранения. Для исторических выгрузок он не предназначен — собирать GCLID нужно ежедневно и складывать в свою базу.

Нужен ли GAQL, если есть встроенная отчётность и скрипты?

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

Как часто придётся переписывать запросы?

Привязывайтесь к конкретной версии API и проверяйте release notes при каждом обновлении: поля переименовываются, ресурсы объединяются, отдельные сегменты исчезают вместе с устаревшими типами кампаний. Запросы стоит держать в репозитории с версионированием, а не в разрозненных скриптах.

Похожие записи