Отчёты Яндекс.Метрики и Директа в таблицу
Скрипт раз в день забирает статистику за последние 7 дней и обновляет её в таблице: визиты, посетителей и достижения цели из Метрики, показы, клики и расходы по кампаниям из Директа. Рядом можно посчитать стоимость заявки и построить диаграмму.
Что понадобится:
- таблица Coverse на тарифе «Бизнес» или выше;
- доступ к счётчику Метрики и к рекламному кабинету Директа;
- 20 минут, для Директа ещё одобрение доступа к API, оно занимает до нескольких дней.
1. Получите токен OAuth
Метрика и Директ пускают в API по токену OAuth вашего аккаунта Яндекса.
- Откройте oauth.yandex.ru и создайте приложение для доступа к API или отладки.
- Отметьте доступы: чтение статистики Метрики (
metrika:read) и API Директа (direct:api). Если нужна только Метрика, второй доступ не нужен. - В адресе для перенаправления укажите
https://oauth.yandex.ru/verification_codeи сохраните приложение. Скопируйте его ClientID. - Войдите в Яндекс тем аккаунтом, к чьим данным нужен доступ, и откройте адрес
https://oauth.yandex.ru/authorize?response_type=token&client_id=ClientID, подставив свой ClientID. - Разрешите доступ. Токен будет в адресной строке после
access_token=— скопируйте его до знака&. - В редакторе скрипта на вкладке «Секреты» добавьте секрет
YANDEX_TOKEN.
Подробнее — в документации Яндекс ID.
Для Директа доступ к API нужно ещё запросить: в веб-интерфейсе Директа откройте раздел API, примите условия и подайте заявку на доступ с ClientID приложения. Пока заявка не одобрена, Директ отклоняет запросы с ошибкой. В аккаунте должна быть хотя бы одна кампания.
2. Метрика: визиты и цели по дням
Узнайте номер счётчика: он виден в списке счётчиков Метрики и в адресе отчёта. Номер цели — на вкладке «Цели» в настройках счётчика.
const COUNTER = 12345678;
const GOAL = 0;
function metrika() {
const metrics = ["ym:s:visits", "ym:s:users"];
if (GOAL) metrics.push("ym:s:goal" + GOAL + "reaches");
const response = Http.get("https://api-metrika.yandex.net/stat/v1/data", {
headers: { Authorization: "OAuth " + Secrets.get("YANDEX_TOKEN") },
query: {
ids: COUNTER,
metrics: metrics.join(","),
dimensions: "ym:s:date",
date1: "7daysAgo",
date2: "yesterday",
limit: 100,
},
});
if (!response.ok) throw new Error("Метрика ответила с кодом " + response.status + ": " + response.text().slice(0, 300));
const rows = response.json().data.map((item) => [
Utilities.toDate(item.dimensions[0].name),
...item.metrics,
]);
const header = ["Дата", "Визиты", "Посетители"];
if (GOAL) header.push("Цель " + GOAL);
upsert("Метрика", header, rows);
console.log("Дней обновлено:", rows.length);
}
- Номер цели
GOALможно оставить0, тогда скрипт загрузит только визиты и посетителей. - Каждый запуск берёт последние 7 дней без сегодняшнего: Метрика досчитывает данные с задержкой, и строки за прошлые дни обновляются.
- Первый столбец — дата. По ней
upsertнаходит уже записанный день: даты в ячейках он сравнивает по дню.
3. Директ: показы, клики и расходы по кампаниям
function direct() {
const name = "coverse-" + Utilities.formatDate(Utilities.today(), "yyyy-MM-dd");
const response = Http.post("https://api.direct.yandex.com/json/v501/reports", {
params: {
SelectionCriteria: {},
FieldNames: ["Date", "CampaignId", "CampaignName", "Impressions", "Clicks", "Cost"],
ReportName: name,
ReportType: "CAMPAIGN_PERFORMANCE_REPORT",
DateRangeType: "LAST_7_DAYS",
Format: "TSV",
IncludeVAT: "YES",
},
}, {
headers: {
Authorization: "Bearer " + Secrets.get("YANDEX_TOKEN"),
"Accept-Language": "ru",
processingMode: "auto",
returnMoneyInMicros: "false",
skipReportHeader: "true",
skipReportSummary: "true",
},
});
if (response.status === 201 || response.status === 202) {
console.log("Директ готовит отчёт, следующий запуск его заберёт");
return;
}
if (!response.ok) throw new Error("Директ ответил с кодом " + response.status + ": " + response.text().slice(0, 300));
const table = Utilities.parseCsv(response.text(), "\t");
const rows = table.slice(1).map((row) => [
row[0] + " | " + row[1],
Utilities.toDate(row[0]),
asText(row[2]),
Number(row[3]) || 0,
Number(row[4]) || 0,
Number(row[5]) || 0,
]);
upsert("Директ", ["Ключ", "Дата", "Кампания", "Показы", "Клики", "Расход"], rows);
console.log("Строк обновлено:", rows.length);
}
- Отчёт за последние 7 дней без сегодняшнего. С
returnMoneyInMicros: "false"расход приходит в рублях, с НДС, еслиIncludeVAT: "YES". - Большие отчёты Директ готовит в фоне и отвечает кодами 201 или 202. Скрипт тогда выходит, а следующий запуск отправляет тот же запрос с тем же названием отчёта и получает готовый. Поэтому для Директа поставьте расписание чаще, например каждый час: отчёт уже готов, лишние запуски заканчиваются быстро.
- Название отчёта содержит дату, поэтому каждый день готовится новый отчёт.
- Ключ строки — дата и номер кампании: даже у кампаний с одинаковым названием строки не смешаются.
4. Общие функции
Добавьте в тот же скрипт:
function upsert(name, header, rows) {
const sheet = Coverse.table.getSheetByName(name) || Coverse.table.insertSheet(name);
if (sheet.getLastRow() === 0) sheet.appendRow(header);
const keyOf = (value) => value instanceof Date ? Utilities.formatDate(value, "yyyy-MM-dd") : String(value);
const keys = sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues();
const index = new Map(keys.map((row, i) => [keyOf(row[0]), i + 1]));
const added = new Map();
for (const row of rows) {
const at = index.get(keyOf(row[0]));
if (at === undefined) {
added.set(keyOf(row[0]), row);
} else {
sheet.getRange(at, 1, 1, row.length).setValues([row]);
}
}
if (added.size > 0) sheet.appendRows([...added.values()]);
}
function asText(value) {
const text = String(value === undefined || value === null ? "" : value);
return text.charAt(0) === "=" ? "'" + text : text;
}
5. Включите расписание
На вкладке «Триггеры» добавьте два триггера «По расписанию»: функция metrika раз в день и функция direct каждый час. Если нужна только Метрика или только Директ, оставьте один.
Стоимость заявки и другие показатели удобно считать формулами на отдельном листе: скрипт переписывает только свои столбцы на листах «Метрика» и «Директ».
Если что-то не работает
| Симптом | Причина | Что сделать |
|---|---|---|
Метрика ответила с кодом 403 и invalid_token | токен неверный или истёк | получите токен заново и сохраните в секрет YANDEX_TOKEN |
Метрика ответила с кодом 403 без invalid_token | у аккаунта нет доступа к счётчику или в токене нет доступа к Метрике | проверьте доступы приложения и права на счётчик |
Директ ответил с кодом 400 и «Ошибка авторизации» (error_code 53) | токен неверный, истёк или выдан без доступа к Директу | получите токен заново с доступом direct:api |
| Директ ответил с ошибкой о доступе к API | заявка на доступ к API Директа не одобрена | дождитесь одобрения в разделе API Директа |
| Директ ответил с кодом 400 с другой ошибкой | ошибка в параметрах отчёта, текст ошибки в ответе | сверьте поля с документацией Директа |
| код 429 или 420 у Метрики | превышена квота запросов | запускайте реже |
| в журнале «Директ готовит отчёт» на каждом запуске | отчёт большой | уменьшите период или число полей |
Частые вопросы
Как выгружать отчёты Яндекс.Метрики в таблицу?
Скрипт по расписанию запрашивает API отчётов Метрики с токеном OAuth и записывает визиты, посетителей и достижения цели по дням.
Как выгружать расходы Яндекс.Директа в таблицу?
Скрипт запрашивает сервис отчётов API Директа и записывает показы, клики и расходы по кампаниям. Доступ к API Директа нужно сначала одобрить в кабинете Директа.
Нужен ли для этого свой сервер?
Нет. Скрипт работает внутри таблицы Coverse по расписанию, токен хранится в секретах.