Перейти к основному содержимому

Отчёты Яндекс.Метрики и Директа в таблицу

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

Что понадобится:

  • таблица Coverse на тарифе «Бизнес» или выше;
  • доступ к счётчику Метрики и к рекламному кабинету Директа;
  • 20 минут, для Директа ещё одобрение доступа к API, оно занимает до нескольких дней.

1. Получите токен OAuth​

Метрика и Директ пускают в API по токену OAuth вашего аккаунта Яндекса.

  1. Откройте oauth.yandex.ru и создайте приложение для доступа к API или отладки.
  2. Отметьте доступы: чтение статистики Метрики (metrika:read) и API Директа (direct:api). Если нужна только Метрика, второй доступ не нужен.
  3. В адресе для перенаправления укажите https://oauth.yandex.ru/verification_code и сохраните приложение. Скопируйте его ClientID.
  4. Войдите в Яндекс тем аккаунтом, к чьим данным нужен доступ, и откройте адрес https://oauth.yandex.ru/authorize?response_type=token&client_id=ClientID, подставив свой ClientID.
  5. Разрешите доступ. Токен будет в адресной строке после access_token= — скопируйте его до знака &.
  6. В редакторе скрипта на вкладке «Секреты» добавьте секрет 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 по расписанию, токен хранится в секретах.

Что дальше​