reels-analytics-for-brokers — радар восходящих офферов
Демонстрационный образец инструмента разведки Instagram под конкретную нишу.
Ниша здесь — брокеры и риелторы, но код нишу не знает: она целиком описана в
config/niche.brokers.json. Замени ключевые слова и эталонные аккаунты, и тот
же пайплайн будет работать по стоматологам, автоподбору, фитнесу или школам.
Зачем это нужно
Рекламный оффер в нише живёт три-четыре недели. Связка, которая стреляет сегодня, через месяц уже не окупается: её скопировали, аудитория выгорела, алгоритм перестал считать её свежей.
Отсюда единственный полезный вопрос: что начинает набирать силу прямо сейчас. Не «что сработало» — это история, её уже поздно повторять. Ответить на него разовым разбором нельзя: один срез показывает картинку, а нужна производная. Поэтому это не отчёт, а радар — регулярный прогон, который каждый раз сравнивает себя с прошлым и показывает, что растёт, а что затухает.
Практический вывод: одиночный запуск почти бесполезен. Ценность появляется со второго прогона, а нормальный режим — раз в неделю. При жизни оффера в 3-4 недели недельный шаг даёт 3-4 точки на кривую и позволяет поймать связку на первой-второй, пока окно открыто.
⛔ Правило номер ноль: первую сотню конкурентов ты собираешь РУКАМИ
Не запускай скрипты, пока не собрал базу из ~100 аккаунтов ниши своими руками. Это не разминка и не формальность — это условие, без которого вся дальнейшая автоматика выдаёт мусор.
Почему так. Когда человек сразу запускает агента, он не понимает, как эту работу делает человек. Он не может оценить результат: не видит, что фильтр выкинул половину нужных, а притащил соседнюю нишу; не замечает, что «конкурент» в его понимании и «конкурент» в понимании алгоритма — разные вещи. Ручной проход по ленте рекомендаций даёт то, что не достаётся никаким фильтром: чувство ниши. Кто здесь вообще считается конкурентом. Какие форматы тут живут, а какие никто не снимает. Как выглядит нормальный аккаунт, а как — накрученный.
Автоматизировать можно только то, что ты уже сделал руками хотя бы раз. Агент масштабирует твоё понимание. Если понимания нет — он масштабирует его отсутствие, просто быстрее и на большем объёме.
Как собирать руками
- Открой профиль эталонного аккаунта ниши — крупного, живого, с рилсами.
- Листай его ленту рекомендаций и блок похожих профилей. Instagram сам показывает соседей по нише — это его основная работа.
- Заходи в каждый подходящий, смотри 5-10 секунд: тематика, свежесть постов, есть ли рилсы. Подходит — сохраняй юзернейм в текстовый файл.
- Из сохранённых снова открывай похожие профили. Ниша разворачивается веером.
- Набей до сотни.
Это работа на один вечер. Она окупается качеством всего, что построено сверху: ключевые слова ты после неё пишешь не из головы, а из того, что реально видел в именах и описаниях.
Результат — простой текстовый файл, по одному юзернейму на строку:
# manual-100.txt — собрано руками, дата
brokername_msk
realty.ivanova
kvartira_pro
Дальше в дело вступают скрипты. Но первый шаг делается своей головой.
Чем это делается
| Инструмент | Роль в пайплайне | Порядок цены | Где взять |
|---|---|---|---|
| Руки и лента рекомендаций | Первая сотня конкурентов, чувство ниши. Незаменимо на старте | бесплатно, один вечер | |
| HikerAPI | Данные Instagram: профили, рилсы, комментарии, подписки, подписчики, поиск | ~$0.001 за запрос, тариф уточняй в кабинете | https://hikerapi.com |
| FFmpeg | Раскадровка первых секунд, извлечение аудиодорожки | бесплатно, open source | https://ffmpeg.org · https://github.com/FFmpeg/FFmpeg |
| Groq (Whisper) | Транскрипция речи из рилсов — быстро и дёшево | центы за час аудио, есть бесплатный лимит | https://groq.com · https://console.groq.com |
Поиск конкурентов идёт двумя путями, и оба нужны:
- через API — подписчики эталонного аккаунта, подписки конкурентов, поиск по хэштегам и по рилсам. Масштабируется, но видит только то, что попало под ключевые слова;
- вручную через ленту рекомендаций — не масштабируется, зато ловит аккаунты, которые не подписали себя «риелтор», и даёт понимание ниши. Обязателен на старте.
Подготовка
export HIKER_API_KEY="..." # https://hikerapi.com
export GROQ_API_KEY="..." # https://console.groq.com — опционально, для транскрипции
python3 --version # 3.9+
ffmpeg -version # https://ffmpeg.org/download.html
Ключи только через переменные окружения. Не вписывай их в файлы скилла и не коммить. Скрипты зависимостей не требуют — только стандартная библиотека Python.
Пайплайн
Один прогон = одна папка среза: runs/2026-07-26/. Папки не удаляй — из них
строится динамика.
Шаг 0. Ручная база (руками, один раз)
См. правило номер ноль выше. Результат: manual-100.txt, ~100 юзернеймов.
Шаг 1. Снежный ком: сотня превращается в три сотни
Каждый из отобранных руками брокеров сам подписан примерно на сотню коллег по нише — на конкурентов, на застройщиков, на тех, у кого учится. Это готовая разметка ниши, сделанная за тебя людьми, которые в ней работают.
Механика: берём каждого из 100, читаем его список подписок, прогоняем всё через тот же фильтр по ключевым словам и активности.
100 аккаунтов руками
× ~100 подписок у каждого = ~10 000 ссылок
→ дедупликация (в узкой нише пересечение большое) ≈ 4 000-5 000 уникальных
→ бесплатный фильтр по имени (~20% проходят) ≈ 1 000 кандидатов
→ платная проверка профиля и активности ≈ 200-250 целевых брокеров
Цена этого шага: ~250 запросов на списки подписок + ~1 000 на профили + ~1 200 на рилсы ≈ 2 450 запросов, порядка $2.5, около десяти минут.
Ручная сотня превращается в три сотни автоматически.
python3 scripts/seed_pool.py \
--config config/niche.brokers.json \
--out runs/2026-07-26 \
--sources manual,following \
--seed-file manual-100.txt
Шаг 2. Досев через API
Снежный ком расширяет то, что уже известно. Чтобы поймать аккаунты вне этого круга, добавь остальные источники: подписчиков эталонного аккаунта, хэштеги, поиск по рилсам и аккаунтам.
python3 scripts/seed_pool.py \
--config config/niche.brokers.json \
--out runs/2026-07-26 \
--sources manual,following,followers,hashtag,search \
--seed-file manual-100.txt
Источники комбинируются, а не выбираются: аккаунт, всплывший сразу в двух
источниках, — более сильный кандидат. Скрипт складывает источники в поле
sources и сортирует пул по их количеству.
Шаг 3. Фильтр до денег — главный приём
Это место, где пайплайн либо стоит копейки, либо десятки долларов.
Списочные эндпоинты (подписчики, подписки) отдают юзернейм и имя профиля бесплатно — они приходят внутри той же страницы списка. А вот описание профиля бесплатно не отдаётся: за био нужен отдельный платный запрос на каждый аккаунт.
Значит грубый отсев по ключевым словам делается до платных запросов. В нише недвижимости это работает особенно хорошо: брокеры сами пишут «Риелтор Москва» или «Недвижимость Сочи» прямо в имени профиля — им это нужно для поиска.
Разница на реальном прогоне:
| Подход | Платных запросов | Стоимость | Время |
|---|---|---|---|
| Сплошной перебор 36 929 подписчиков | 36 929 | ~$37 | ~1,7 ч при --rps 6; до полутора суток, если долбить по одному запросу |
| Умный обход с фильтром до денег | 63 | $0.06 | 4 минуты (замер) |
Про время в этой таблице: оно зависит от того, с какой параллельностью ты работаешь, а стоимость — нет. 36 929 запросов стоят $37 при любой скорости. Замеренные «4 минуты» на 63 запроса — это не 6 запросов в секунду, а латентность профильных и клипных вызовов; сравнивать надо цифру запросов, она честная.
Стоимость упала примерно в шестьсот раз.
Честная оговорка, чтобы не обмануться самому: экономия здесь складывается из двух вещей. Первая — порядок операций: платный запрос уходит только на тех, кто прошёл бесплатный фильтр. Вторая — ранняя остановка: умный обход просмотрел не все 36 929 подписчиков, а первые 118, и этого хватило, чтобы набрать десять целевых аккаунтов. Сплошной перебор всех подписчиков не нужен, пока цель — рабочая выборка, а не перепись ниши. Если тебе нужна именно перепись, считай по таблице масштабирования ниже, а не по этой строке.
Фильтр настраивается в конфиге: keywords_free — широкий список для
бесплатного шага, negative_keywords — соседние ниши, которые ловятся на те же
слова (ремонт, интерьер, мебель) и без отсечки забивают пул.
Шаг 4. Квалификация аккаунта
Первый шаг, который тратит деньги: один запрос профиля на кандидата, потом рилсы — только для тех, кто прошёл.
python3 scripts/qualify_accounts.py \
--config config/niche.brokers.json \
--out runs/2026-07-26
Ворота, по возрастанию цены:
- Профиль — ключевые слова в био и категории, отсечка по подписчикам, приватные отсеиваются. Один запрос.
- Активность — не меньше 10 рилсов за 30 дней. Аккаунт, который постит раз в квартал, ничего не говорит о том, что работает сейчас; его медиана бессмысленна, а значит бессмысленны и всплески. Это не придирка, а условие того, чтобы выборка состояла из людей, реально ведущих игру.
Для прошедших считаются: медиана просмотров (не среднее — один залетевший
ролик утаскивает среднее и ломает базу для сравнения) и отношение охвата к
базе подписчиков (median_views / followers) — показывает, выходит ли аккаунт
за пределы своей аудитории в принципе.
На выходе: accounts.json, reels.json, qualify_stats.json со всей воронкой
отказов — по ней видно, что именно резать в конфиге.
Шаг 5. Отбор рилсов: всплеск, а не абсолют
python3 scripts/rank_reels.py --out runs/2026-07-26 --config config/niche.brokers.json
# окно и глубину можно задать флагами — они перекрывают конфиг:
# python3 scripts/rank_reels.py --out runs/2026-07-26 --top 250 --days 14
Ранжирование идёт по всплеску относительно собственной медианы аккаунта, а не по абсолютным просмотрам.
Почему абсолют вводит в заблуждение: он ранжирует не идеи, а размер аккаунта. 40 000 просмотров у агентства с базой в 200 000 — это обычный вторник, ролик даже не вышел за пределы своей аудитории. Те же 40 000 у брокера с базой 500 — это алгоритм понёс видео холодным людям, и причиной могло быть только само содержание. Копировать можно второе. Сортировка по абсолюту первым делом покажет крупные аккаунты и спрячет ровно то, ради чего всё затевалось.
Два предохранителя от ложных всплесков: пол по просмотрам (--min-views, иначе
аккаунт с медианой 30 просмотров даёт «десятикратный всплеск» из шума) и
минимум роликов на аккаунт, чтобы медиана вообще что-то значила.
Из тысячи аккаунтов до 200-300 роликов доходят так: 30 дней на расчёт медианы, 14 дней на поиск всплесков внутри них, порог всплеска, затем срез топа.
Шаг 6. Разбор ролика
# один ролик
./scripts/teardown_reel.sh CODE runs/2026-07-26/teardowns
# пачкой по топу, последовательно и с паузой
python3 -c "
import json
for r in json.load(open('runs/2026-07-26/top-reels.json'))[:50]:
print(r['code'])
" | while read -r code; do
./scripts/teardown_reel.sh "$code" runs/2026-07-26/teardowns || true
sleep 3
done
Что собирается по каждому ролику:
- видео по временной ссылке из API (ссылки подписанные, живут часы);
- раскадровка первых 3 секунд с шагом 0,5 секунды — шесть кадров. Первые три секунды решают, поедет ролик или нет; шести кадров хватает, чтобы увидеть чем открывается видео и сравнить десятки открытий, не досматривая ни одного;
- аудиодорожка и транскрипция через Groq Whisper;
- комментарии — там видно, отвечают ли люди кодовым словом;
- призыв к действию и кодовое слово — вытаскиваются на следующем шаге.
Видео после раскадровки удаляется (KEEP_VIDEO=1 чтобы оставить): 300 роликов
это несколько гигабайт. Готовые разборы кэшируются — опубликованный ролик уже
не изменится, повторный прогон его не перекачивает.
Шаг 7. Синтез и сравнение срезов
python3 scripts/offers_diff.py extract --out runs/2026-07-26 \
--transcripts runs/2026-07-26/teardowns
python3 scripts/offers_diff.py diff \
--previous runs/2026-07-12 --current runs/2026-07-26
extract группирует ролики по офферам: вытаскивает кодовое слово из подписи и
транскрипта, распознаёт лид-магниты (гайд, чек-лист, подборка, консультация) и
«ссылку в шапке». По каждому офферу — сколько аккаунтов его крутят, сколько
роликов, медиана всплеска, дата первого появления.
Отдельно смотри группу no_cta. Ролики без распознанного призыва — обычно
самая содержательная находка, а не мусор (см. реальный прогон ниже).
diff сравнивает два среза и присваивает статус:
| Статус | Что значит | Что делать |
|---|---|---|
| RISING | аккаунтов стало больше, всплеск не падает | забирать сейчас, окно открыто |
| NEW | оффера в прошлом срезе не было | проверить на следующем срезе |
| PEAK | аккаунтов много, всплеск встал | окно закрывается, входить поздно |
| FADING | всплеск просел заметно | не трогать |
| DEAD | в свежем срезе не встречается | история |
Поверх машинной группировки читается содержание: какие хуки, какая длина, какой
формат, какой оффер. Метод разбора хуков — references/analysis.md.
Шаг 8. Отчёт
Прогон оставляет после себя:
| Файл | Что внутри |
|---|---|
accounts.json |
таблица аккаунтов: подписчики, активность, медиана, отношение охвата к базе |
top-reels.csv |
топ роликов: дата, аккаунт, просмотры, всплеск, охват к базе, вовлечённость, ссылка |
summary.json |
медиана и 90-й процентиль выборки, число всплесков, лидер |
teardowns/<code>/frames/ |
раскадровка первых 3 секунд |
teardowns/<code>/transcript.txt |
транскрипт |
offers.json |
живые офферы с датой первого появления |
offers-diff.md |
динамика к прошлому срезу: что растёт, что умирает |
seed_stats.json, qualify_stats.json |
воронка и честная стоимость прогона |
Как читать цифры
Три числа на ролик, и они отвечают на разные вопросы.
| Метрика | Формула | Вопрос |
|---|---|---|
| Всплеск | просмотры / медиана аккаунта | обогнал ли ролик своего автора |
| Охват к базе | просмотры / подписчики | вышел ли за пределы своей аудитории |
| Вовлечённость | (лайки + комментарии) / просмотры | насколько тёплым был трафик |
Про вовлечённость важно: она считается к просмотрам, а не к подписчикам. Посчитанная на подписчика, при залёте она растёт и не сообщает ничего. Посчитанная на просмотр — падает, и это честный сигнал, что залёт означает выход на холодную аудиторию, а не любовь своей. Ролик может собрать в двадцать раз больше просмотров и при этом стать в десять раз менее интересным тем, кто его увидел. Это нормально и это надо знать заранее: залёт даёт охват, а не доверие, и конверсия у него другая.
Что показал реальный прогон
Цифры ниже — с живого прогона по нише брокеров, приведены как доказательство работоспособности метода, а не как эталон ниши.
Воронка сбора. У эталонного аккаунта 36 929 подписчиков. Списком просмотрено 118, фильтр по ключевым словам прошли 24, годных брокеров после квалификации — 10. Итого 63 запроса, $0.06, 4 минуты. Сплошной перебор всех 36 929 стоил бы ~$37 и около 12 часов.
Выборка. 84 рилса за 14 дней по десяти аккаунтам. Медиана выборки — 1 580 просмотров.
Лидер. Аккаунт на 522 подписчика собрал 35 559 просмотров. Это 68 своих аудиторий и всплеск 18,6× к собственной медиане. Никакой сортировкой по абсолютным просмотрам его бы не нашли — он потерялся бы под любым средним агентством.
Охват. Обычный ролик доходит до 87% своей базы подписчиков — то есть даже не до всех своих. Залетевшие уходят на 959%, 2 099% и 6 812%. Разрыв между «обычным» и «залетевшим» здесь не в разы, а на порядок с лишним.
Цена залёта. Вовлечённость на просмотр: 1,97% медиана выборки против 0,14% у лидера. Залёт — это выход на холодных, а не любовь аудитории.
Хуки трёх топовых роликов. Все три открываются текстовой плашкой на нулевой секунде. Ни одной склейки в первые 2,5 секунды. В двух из трёх в кадре говорит не автор, а собеседник. Это и есть та самая формула, ради которой строился пайплайн: не «снимай интересно», а три проверяемых признака.
Главный провал ниши. 71 000 просмотров суммарно и ноль заявок по кодовому слову. Причина при разборе видна сразу: кодовое слово стоит только в подписи либо звучит на 101-й секунде — то есть после того, как ролик досмотрели единицы. Ниша умеет собирать охват и не умеет его забирать. Для того, кто заходит в неё сейчас, это самая дорогая находка отчёта.
Масштабирование до 1000 аккаунтов
Полные расчёты, разбивка на партии и стратегия кэширования —
references/scaling.md. Коротко:
| Этап | Запросов на пул в 1000 аккаунтов | Стоимость |
|---|---|---|
| Списки подписок и подписчиков | ~250-500 | $0.25-0.50 |
| Профили кандидатов (после бесплатного фильтра) | ~2 400 | $2.40 |
| Рилсы для квалификации | ~3 000 | $3.00 |
| Метаданные и комментарии топ-300 роликов | ~600-900 | $0.60-0.90 |
| Итого API | ~6 200-6 800 | ~$6-7 |
Узкое место — не деньги и не лимит запросов. При потолке в 8 запросов в секунду вся сборка данных укладывается в 15-25 минут. Упирается всё в обработку видео: скачивание 300 роликов (несколько гигабайт, последовательно, с паузами) и транскрипция — это часы, а не минуты. Оптимизировать надо там: кэшировать разборы навсегда, тереть видео сразу после раскадровки, разбирать только топ по всплеску, а не весь пул.
Что кэшировать между прогонами: профили (7-30 дней), списки подписок (7 дней), рилсы аккаунта (24 часа), разборы роликов — навсегда. Работать партиями по 200 аккаунтов с чекпоинтом после каждой, чтобы обрыв не стоил всего прогона.
Честно про кэш: в скриптах его нет. Кэшируются только разборы роликов —
teardown_reel.sh пропускает то, что уже разобрано. Всё остальное из таблицы
выше — проектная рекомендация, которую надо дописать самому, а пока её нет,
повторный прогон стоит полную цену, а не «несколько сотен запросов». Схема и
ключи кэша расписаны в references/scaling.md.
Ограничения — читай до того, как строить на этом бизнес
Доступ к данным неофициальный. HikerAPI — сторонний сервис, а не Instagram Graph API. Официальный API Meta таких данных о чужих аккаунтах не отдаёт вовсе, и именно поэтому существуют сервисы вроде этого. Отсюда всё остальное.
Это может перестать работать в любой день. Instagram регулярно меняет внутренние ответы. Форматы полей плывут, эндпоинты отваливаются, поля обнуляются. Скрипты написаны защитно (ищут поля в нескольких местах), но гарантий нет. Если пайплайн вернул пустоту — сначала проверяй, что изменился ответ, а не твой конфиг.
Риск блокировки. Твой личный аккаунт Instagram при таком использовании не задействован и не рискует — запросы идут через инфраструктуру сервиса. Рискует твой ключ: превышение лимитов и агрессивные прогоны ведут к троттлингу или приостановке. Скачивание видео идёт напрямую с CDN Instagram — вот там частые параллельные запросы с одного адреса ловят ограничения. Поэтому: не выше 6 запросов в секунду, скачивание строго последовательно с паузой 2-4 секунды, экспоненциальный откат на 429 и 5xx. Никогда не подставляй в такие пайплайны логин и пароль собственного аккаунта.
Чего сервис не отдаёт в принципе:
- охваты, досматриваемость, удержание, переходы — это данные из кабинета владельца аккаунта. Снаружи их нет ни у кого. Просмотры — не охват;
- личные сообщения и заявки — сколько людей реально написало кодовое слово, снаружи не видно. Виден только след в комментариях, и это нижняя оценка;
- поиск по описанию профиля — искать по био нельзя, только получать био уже известного аккаунта. Именно поэтому фильтр на шаге 3 идёт по имени, а не по описанию: это не выбор, это единственный доступный путь;
- надёжные просмотры на всех эндпоинтах — на части ключей
play_countприходит нулевым. Ноль просмотров — это чаще «не отдали», чем «не смотрели»; такие ролики надо отбрасывать, а не считать провалившимися; - исторические данные — API отдаёт срез на сегодня. Динамику можно получить только собственными регулярными срезами. Ещё одна причина, почему это радар.
Смещения выборки, о которых надо помнить. Закрытые аккаунты невидимы. Фильтр по ключевым словам системно теряет тех, кто не подписал себя брокером — как раз сильных персональных блогеров. Лента рекомендаций показывает похожее на то, что ты уже смотрел, поэтому ручной сбор тоже смещён. Медиана по 10-15 роликам шумная. Выводы формулируй как гипотезы для проверки, а не как факты.
Юридическая аккуратность. Собирай только публично опубликованное и только в объёме, нужном для анализа рынка. Не собирай персональные данные, не строй базы физлиц, не используй результат для рассылок и холодных контактов. Проверь, что твоё использование не противоречит условиям Instagram и местному законодательству о персональных данных — в разных юрисдикциях правила разные. Публикуя выводы, не выставляй конкретные аккаунты в негативном свете: работай с агрегатами. Чужие ролики — это чужая интеллектуальная собственность: разбирать и учиться можно, перезаливать нельзя.
Перенос на другую нишу
Меняются только данные, код не трогается:
- Скопируй
config/niche.brokers.jsonвconfig/niche.<своя>.json. - Замени
keywords_free,keywords_bio,negative_keywords,hashtags,search_queries,reference_accounts. - Подкрути пороги:
min_reels_in_window,min_followers, окна. - Собери свою ручную сотню. Заново, для новой ниши. Правило номер ноль не отменяется тем, что скрипты уже написаны.
Ключевые слова пиши после ручного сбора, а не до: ты увидишь, как люди в этой нише реально называют себя в имени профиля, и список получится в разы точнее придуманного за столом.
Регламент
Раз в неделю, один и тот же день. Прогон в новую папку runs/<дата>, затем
offers_diff.py diff против прошлой. Смотреть в первую очередь RISING и NEW,
потом группу no_cta. Старые папки не удалять — они и есть история.
Если что-то не работает
| Симптом | Причина и что делать |
|---|---|
HIKER_API_KEY is not set |
ключ не экспортирован в текущей сессии |
| Пул пустой | слишком узкие keywords_free; для ручного списка нужен --sources manual |
Все кандидаты отсеяны с no_bio_keyword |
keywords_bio строже keywords_free; смотри воронку в qualify_stats.json |
low_activity почти у всех |
порог 10 рилсов за 30 дней высок для этой ниши — снижай |
| Всплески у всех гигантские | поднимай --min-views: медианы считаются по шуму |
| Просмотры нулевые | эндпоинт не отдал play_count; отбрось такие ролики, не считай их провалами |
| Скачивание видео даёт 403 | подписанная ссылка протухла — перезапусти разбор ролика |
| Много 429 | снизь --rps и --workers, откат отработает сам |
Когда НЕ использовать
Публикация контента, автолайки, автоподписки, любые действия от твоего имени — скилл только читает. YouTube и TikTok — другие источники. Сбор персональных данных людей — прямо запрещено. Разовый вопрос «покажи топ рилсов у одного аккаунта» — здесь избыточно, это делается одним запросом к API.