Как я снизил долю отказов в РСЯ с 43,51% до 13,46% за 1 день с помощью Logs API: подробный гайд

Как я снизил долю отказов в РСЯ с 43,51% до 13,46% за 1 день с помощью Logs API: подробный гайд

Приветствую. Сегодня я хочу поделиться реальным кейсом, как анализ «сырых» данных из Яндекс.Метрики помог мне выявить и значительно сократить объем ботного трафика в РСЯ.

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

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

Я начал использовать метод, основанный на анализе неагрегированных данных через Logs API, и он показал отличные результаты.

Что такое Logs API?

В арсенале Яндекс.Метрики есть мощный, но не всем известный инструмент — Logs API.

Это интерфейс программирования приложений (API), который предоставляет доступ к неагрегированным («сырым») данным о действиях пользователей на вашем сайте. Проще говоря, с помощью Logs API мы получаем необработанную информацию о каждом взаимодействии с сайтом, что открывает широкие возможности для глубокого анализа.

Хиты и визиты: в чем разница?

Чтобы правильно анализировать данные, важно понимать разницу между основными метриками:

  • Хит (Hit) — это любое единичное действие пользователя на сайте: просмотр страницы, клик по кнопке, загрузка файла.
  • Визит (Visit) — это сессия одного пользователя, которая включает в себя один или несколько хитов. Визит начинается, когда пользователь заходит на сайт, и заканчивается после определённого периода неактивности.

Наша задача — выгрузить данные по хитам и визитам, объединить их по уникальному идентификатору пользователя (clientID) и найти аномалии.

Что нужно для работы с Logs API?

Основной недостаток этого метода — относительная сложность первоначальной настройки. Вам понадобится зарегистрировать приложение в Яндексе, получить специальный ключ доступа (токен). Я покажу, как это сделать шаг за шагом.

Шаг 1: Регистрация приложения в Яндексе

  1. Перейдите на страницу Яндекс.OAuth.
  2. Нажмите кнопку «Создать приложение».
  3. В появившемся окне заполните форму:Название: Введите что-то понятное, например, Metrika_Logs_API.Платформы: Выберите «Веб-сервисы» и в поле «Callback URI» нажмите «Подставить URL для разработки».Доступ к данным: Найдите в списке «Яндекс.Метрика» и выберите право «Получение статистики, чтение параметров своих и доверенных счётчиков».
  4. Нажмите «Создать приложение».

После создания вы увидите ClientID вашего приложения. Сохраните его, он скоро понадобится.

Как я снизил долю отказов в РСЯ с 43,51% до 13,46% за 1 день с помощью Logs API: подробный гайд

Шаг 2: Получение токена

OAuth-токен — это уникальный ключ, который подтверждает, что ваше приложение имеет право получать данные от вашего имени.

Важно: Токен — это как пароль. Храните его в надёжном месте и никому не показывайте!

  1. Скопируйте следующую ссылку и вставьте её в адресную строку браузера: https://oauth.yandex.ru/authorize?response_type=token&client_id=<Ваш_ClientID>
  2. Замените <Ваш_ClientID> на идентификатор, который вы получили на предыдущем шаге.
  3. Перейдите по ссылке. Яндекс попросит вас подтвердить, что вы разрешаете приложению доступ к данным. Нажмите «Разрешить»
  4. После этого вас перенаправит на страницу, где будет указан ваш токен. Он действителен в течение одного года. Скопируйте и сохраните его.

Как я снизил долю отказов в РСЯ с 43,51% до 13,46% за 1 день с помощью Logs API: подробный гайд

Шаг 3: Верификация

Следующим шагом будет прохождение верификации аккаунта разработчика через Госуслуги. Если вы увидите такое уведомление в интерфейсе Яндекс.OAuth, нажмите на него и следуйте инструкциям. Процедура обычно занимает 5-10 минут.

Шаг 4: Подготовка окружения для скрипта

Для автоматизации выгрузки мы будем использовать язык программирования Python.

  1. Установите Python. Если у вас его нет, скачайте с официального сайта python.org и установите.
  2. Установите текстовый редактор. Подойдёт любой, например, Sublime Text, VS Code или Notepad++.
  3. Создайте папку проекта. Создайте на рабочем столе папку с названием metrika_logs

Шаг 5: Создание скриптов

Внутри папки metrika_logs создайте два файла: metrika_logs.py для выгрузки данных и merge_hits_visits.py для их объединения.

Файл №1: metrika_logs.py

import requests import time import gzip import pandas as pd from io import BytesIO import datetime import json # --- НАСТРОЙКИ --- # 🔑 Вставьте ваш токен и ID счётчика TOKEN = "ВАШ_OAUTH_ТОКЕН" COUNTER_ID = "ВАШ_НОМЕР_СЧЁТЧИКА" # 📅 Укажите даты для выгрузки в формате (ДАТА_НАЧАЛА, ДАТА_КОНЦА) DATES = [("2025-10-15", "2025-10-15"), ("2025-10-16", "2025-10-16")] # ✅ Поля для таблицы с хитами (hits) HITS_FIELDS = ",".join([ "ym:pv:dateTime", "ym:pv:watchID", "ym:pv:clientID", "ym:pv:URL", "ym:pv:title", "ym:pv:referer", "ym:pv:browser", "ym:pv:deviceCategory", "ym:pv:regionCity", "ym:pv:regionCountry", "ym:pv:ipAddress", "ym:pv:UTMSource", "ym:pv:UTMMedium", "ym:pv:UTMCampaign" ]) # ✅ Поля для таблицы с визитами (visits) VISITS_FIELDS = ",".join([ "ym:s:visitID", "ym:s:date", "ym:s:clientID", "ym:s:startURL", "ym:s:pageViews", "ym:s:bounce", "ym:s:ipAddress", "ym:s:deviceCategory", "ym:s:browser", "ym:s:lastTrafficSource", "ym:s:lastUTMSource", "ym:s:lastUTMMedium", "ym:s:lastUTMCampaign" ]) # --- КОНЕЦ НАСТРОЕК --- def create_log_request(source, fields, date1, date2): """Создаёт запрос на выгрузку в API Метрики.""" url = f"https://api-metrika.yandex.net/management/v1/counter/{COUNTER_ID}/logrequests" data = {"date1": date1, "date2": date2, "source": source, "fields": fields} headers = {"Authorization": f"OAuth {TOKEN}"} r = requests.post(url, headers=headers, data=data) if r.status_code != 200: print(f"❌ Ошибка при создании запроса {source} для {date1}:") print(json.dumps(r.json(), indent=4, ensure_ascii=False)) raise SystemExit() req_id = r.json()["log_request"]["request_id"] print(f"📤 Запрос создан для '{source}' за {date1}: ID {req_id}") return req_id def wait_for_ready(request_id): """Ожидает, пока Метрика подготовит отчёт.""" url = f"https://api-metrika.yandex.net/management/v1/counter/{COUNTER_ID}/logrequest/{request_id}" headers = {"Authorization": f"OAuth {TOKEN}"} while True: r = requests.get(url, headers=headers) r.raise_for_status() status = r.json()["log_request"]["status"] if status == "processed": print(f"✅ Отчёт {request_id} готов.") return elif status in ("created", "processing"): print(f"⏳ Ожидаем готовности отчёта {request_id} (статус: {status})...") time.sleep(20) else: raise RuntimeError(f"Неожиданный статус отчёта: {status}") def download_and_convert(request_id, date_label, source): """Скачивает, распаковывает и конвертирует данные в Excel.""" url = f"https://api-metrika.yandex.net/management/v1/counter/{COUNTER_ID}/logrequest/{request_id}/part/0/download" headers = {"Authorization": f"OAuth {TOKEN}"} print(f"⬇️ Скачиваю отчёт '{source}' за {date_label}...") resp = requests.get(url, headers=headers) resp.raise_for_status() data = resp.content if data[:2] == b"\x1f\x8b": # Проверка на gzip архив print("🗜️ Файл сжат, распаковываю...") data = gzip.decompress(data) df = pd.read_csv(BytesIO(data), sep="\t", dtype=str, low_memory=False) out_file = f"metrika_{source}_{date_label}.xlsx" df.to_excel(out_file, index=False) print(f"💾 Файл сохранён: {out_file}") def main(): today = datetime.date.today().strftime("%Y-%m-%d") for date1, date2 in DATES: if date2 >= today: print(f"⏭️ Дата {date2} ещё не завершилась, пропускаем.") continue print(f"\n🚀 Начинаю обработку периода {date1} - {date2}...") for source, fields in [("hits", HITS_FIELDS), ("visits", VISITS_FIELDS)]: try: req_id = create_log_request(source, fields, date1, date2) wait_for_ready(req_id) download_and_convert(req_id, date1, source) except Exception as e: print(f"❌ Произошла ошибка при обработке '{source}' за {date1}: {e}") if __name__ == "__main__": main() input("\nНажмите Enter для выхода...")

Вставьте ваш токен, номер счетчика яндекс метрики, а также замените даты.

Файл №2: merge_hits_visits.py

import pandas as pd import os # === Пути к файлам === base_path = r"/Users/max0vo/Desktop/metrika_logs" hits_file = os.path.join(base_path, "metrika_hits_2025-10-15.xlsx") visits_file = os.path.join(base_path, "metrika_visits_2025-10-15.xlsx") output_file = os.path.join(base_path, "merged_hits_visits.xlsx") print("📂 Загружаем файлы...") hits = pd.read_excel(hits_file, dtype=str) visits = pd.read_excel(visits_file, dtype=str) print("🔧 Нормализуем clientID...") for df in [hits, visits]: for col in df.columns: if 'clientid' in col.lower(): df[col] = df[col].str.replace(',', '.', regex=False) df[col] = df[col].str.replace(' ', '', regex=False) df[col] = df[col].str.extract(r'(\d+)', expand=False) # Определяем реальные названия колонок hit_client_col = [c for c in hits.columns if 'clientid' in c.lower()][0] visit_client_col = [c for c in visits.columns if 'clientid' in c.lower()][0] visit_id_col = [c for c in visits.columns if 'visitid' in c.lower()][0] print(f"🔗 Объединяем по {hit_client_col} и {visit_client_col}...") # Мержим по clientID merged = pd.merge( hits, visits, left_on=hit_client_col, right_on=visit_client_col, how="inner", suffixes=("_hit", "_visit") ) print(f"✅ Объединено строк: {len(merged)}") # Сохраняем результат merged.to_excel(output_file, index=False) print(f"💾 Итог сохранён: {output_file}")
Вам необходимо полностью заменить эти строки своими данными base_path = "путь к вашей папке metrika_logs hits_file = os.path.join(base_path, "Название файла выгрузки хитов") isits_file = os.path.join(base_path, "Название файла выгрузки визитов") Заменять hits_file = os.path.join(base_path, "Название файла выгрузки хитов") isits_file = os.path.join(base_path, "Название файла выгрузки визитов") НУЖНО ТОЛЬКО ПОСЛЕ ТОГО КАК ВЫ ВЫГРУЗИТЕ ДАННЫЕ Пример как это выглядит у меня: # === Пути к файлам === base_path = r"/Users/max0vo/Desktop/metrika_logs" hits_file = os.path.join(base_path, "metrika_hits_2025-10-15.xlsx") visits_file = os.path.join(base_path, "metrika_visits_2025-10-15.xlsx")

Шаг 6: Запуск скриптов

1. Откройте терминал (командную строку).

2. Перейдите в папку проекта с помощью команды cd.

Пример: cd Desktop/metrika_logs

3. Создайте и активируйте виртуальное окружение. Это изолирует библиотеки проекта.

python -m venv venv source venv/bin/activate (для macOS/Linux) venv\Scripts\activate (для Windows)

4. Установите необходимые библиотеки:

pip install requests pandas openpyxl

5. Запустите файл выгрузки

python metrika_logs.py

После успешного запуска в папке metrika_logs должны появится данные по хитам и визитам. На следующем этапе мы "склеим" эти данные и объединим в 1 файле.

Выполните команду

python merge_hits_visits.py

Теперь у вас есть объединённый файл со всей «сырой» информацией.

Шаг 7: Анализируем данные

Для быстрого анализа подойдет Chatgpt. Загрузите таблицу и попросите ИИ ассистента проанализировать данные на предмет подозрительного трафика (IP, устройства, браузеры и прочее)

После анализа примените соответствующие настройки и корректировки внутри рекламной кампании.

Мой опыт и результаты

Я применил этот метод для проекта, где после перехода на новый рекламный кабинет столкнулся с резким ростом отказов. Ручная чистка площадок не давала эффекта, а старые, проверенные площадки перестали приносить результат.

Проанализировав логи, я выявил несколько сетей IP-адресов и пару версий мобильных браузеров, генерировавших 90% «мусорного» трафика.

Результаты до чистки (15 октября):

Отказы: 43,51% (общий показатель с момента запуска достиг 46,72%).
Отказы: 43,51% (общий показатель с момента запуска достиг 46,72%).

Результаты после оптимизации (16 октября):

Отказы: 13,46% (средний показатель за последующий период держится на уровне 18,29%)
Отказы: 13,46% (средний показатель за последующий период держится на уровне 18,29%)

При этом мне не пришлось блокировать потенциально качественные площадки или отключать весь мобильный трафик. Я просто точечно удалил источник проблемы.

Надеюсь, этот гайд был полезен. Спасибо за внимание 😊

1
Начать дискуссию