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

Это третий и последний воркфлоу из связки n8n-seo-monitor-suite. Про GEO-мониторинг видимости в ИИ-ответах и про ежедневный/еженедельный контент-аудит я уже писал.

Воркфлоу и пример сообщения
Воркфлоу и пример сообщения

Один воркфлоу, два независимых запуска

Как и в предыдущих двух, здесь общий источник правды на несколько кадансов: Daily_Monitor (те же URL категорий, что и в контент-аудите), Master_Briefs (эталонные Title/H1/границы интента) и Owner_Map - таблица "какой URL за каким запросом закреплён" читаются и помесячным отчётом, и еженедельным сканом каннибализации.

                [ ОБЩИЙ КОНФИГ ]
    Daily_Monitor · Baseline_Metrics · Master_Briefs · Owner_Map
                         │
        ┌────────────────┴─────────────────┐
        ▼                                   ▼
┌────────────────────────┐        ┌──────────────────────────┐
│ ПОМЕСЯЧНЫЙ ОТЧЁТ         │        │ СКАН КАННИБАЛИЗАЦИИ      │
│ 1-е число месяца         │        │ понедельник, 09:00       │
├─────────────────────────┤        ├────────────────────────────┤
│ • GSC/Метрика/Вебмастер │        │ • GSC query+page, 4 среза │
│   28д к прошлым 28д и   │        │   (28д/7д × текущий/пред.)│
│   аналогичному месяцу   │        │ • риск-скоринг 0-100      │
│   год назад              │        │ • контроль primary-запросов│
│ • модель "ожидаемо по    │        │   (не влияет на скоринг)  │
│   сайту" вместо порога   │        │ • Query Discovery         │
│ • трекинг ручных правок  │        │ • живой SerpApi — только  │
│   (SEO_Change_Log)       │        │   когда кэш не годится    │
└───────────┬──────────────┘        └─────────────┬──────────────┘
            │                                       │
            ▼                                       ▼
     Monthly_Log (append)          Cannibalization_State / _History (upsert)

Оба режима читают и пишут в общие таблицы свежести (SEO_Run_State, SEO_Page_Snapshot) и если данные за нужный день уже собраны другим прогоном, повторный фетч GSC/Метрики не делается.

Два вида конфликта

Скан различает два сценария:

  • Внутренняя конкуренция категорий: по кластеру запросов вместо назначенного владельца ранжируется другая категория того же сайта.

  • Сквозной перехват: категорию обгоняет карточка товара, статья или любой другой URL не того типа.

Это не одна и та же проблема: если категорию обгоняет сосед-категория, то вопрос в границах интента и Title/H1 обеих. Если карточка товара обгоняет категорию - вопрос уже в перелинковке и хлебных крошках, а не в переписывании текста.

Модель риска: шесть факторов, а не "пересечение = тревога"

Ядро - Code-нода Cannibalization Engine, 1500+ строк. Для каждой пары "владелец / конкурент" по общему кластеру запросов считаются шесть компонентов, каждый с собственным потолком:

Фактор

Вес

Что меряет

Доминирование

0-25

доля показов конкурента в паре; ниже 35% - 0 баллов

Смещение позиции

0-20

насколько конкурент выше владельца в выдаче

Захват кликов

0-15

доля кликов конкурента, если есть минимум 2 клика в паре

Тренд периода

0-20

владелец падает, конкурент растёт - на 28-дневном и 7-дневном окне отдельно

Структурное несоответствие

0-10

у владельца 0 показов при 10+ у конкурента, запрещённая страница, легаси-редирект

Персистентность

0-10

сколько прогонов подряд конфликт держится (0 при первом появлении, максимум с третьего)

Код: вычисление факторов риска и итогового Risk Score
// Доминирование: 0..25
const dominanceScore = compShare <= 0.35 ? 0 : clamp((compShare - 0.35) / 0.55 * 25, 0, 25);

// Персистентность: 0..10
const persistenceScore = prevRuns >= 3 ? 10 : (prevRuns >= 2 ? 7 : (prevRuns >= 1 ? 4 : 0));

Сумма (максимум 100) умножается на коэффициент уверенности от 0.25 до 1.0, который понижает итоговый балл, если суммарных показов в паре мало:

let confidence = pairImp >= 300 ? 0.95 :
                 pairImp >= 100 ? 0.85 :
                 pairImp >= 30  ? 0.70 :
                 pairImp >= 10  ? 0.50 : 0.30;
const riskScore = Math.round(rawScore * confidence);

Итоговые пороги:

Severity

Условие

LOW_DATA

суммарно меньше 10 показов и меньше 2 кликов

WATCH

risk_score ≥ 30

HIGH

risk_score ≥ 55

CRITICAL

risk_score ≥ 75, конкурент держит ≥65% показов пары, и либо 2+ прогона подряд, либо 200+ показов

Условие для CRITICAL явно требует ИЛИ повторяемости, ИЛИ объёма - один разовый всплеск трафика конкурента, даже сильный, сам по себе не может пробить критический порог. Это прямой ответ на проблему, которую в daily-weekly решали на глаз по графику; здесь разделение сигнала от шума зашито в формулу.

Диагноз зависит от типа конфликта

Движок классифицирует характер конфликта и для каждого типа даёт свою рекомендацию:

  • Легаси-редирект тянет видимость: сигнал переклейки/переобхода, не повод трогать контент.

  • Категория против категории: сверить Title/H1/H2 и границы интента обеих, ничего не менять до подтверждения конкретного пересечения.

  • Товар против категории: проверить анкоры, хлебные крошки и блоки рекомендаций; фразу из карточки не убирать автоматически.

  • Статья против категории: возможна нормальная смешанная выдача (информационный и коммерческий интент законно уживаются) - сначала подтвердить, потом решать.

Четыре разных типа конфликта → четыре разных способа решения, а не одно радикальное решиние "объединить страницы".


Живой SERP - по расписанию кэша, а не всегда

GSC и Метрика бесплатные, живой запрос в SerpApi - нет. Поэтому вызывается он не каждый прогон:

  • кэш SERP-позиции живёт 14 дней (SERP_CACHE_TTL_DAYS);

  • на прогон - жёсткий потолок в 32 живых запроса (SERP_LIVE_MAX_QUERIES), даже если кандидатов на проверку больше;

  • локация и домен зашиты явно (Moscow,Moscow,Russia, google.ru/yandex.ru) — SERP чувствителен к гео, случайный запрос без локации показал бы не ту выдачу.

Эти правила я использую под свою ситуацию, чтобы уложиться в бесплатные лимиты на 250 запросов в месяц.

Отдельный, более узкий случай - "доуточнение неизвестных позиций владельца". Если по кластеру в топ-10 уже сидит чужая страница сайта, а свежей проверки именно позиции владельца ещё не было - это тот самый неоднозначный случай, где кэш не отвечает на вопрос. Нода-планировщик собирает только такие пары:

Код: отбор запросов на доуточнение позиций владельца
// Нужно свежее доуточнение позиции владельца, только если в TOP10 уже сидит другая страница сайта
if (dataErr || !found || ownerMatch) continue;
const exactOk = !!er && !boolVal(er.data_error, false) && ...;
if (exactOk) continue;
tasks.push({ engine, slug, category, query: q, owner_url: owner, reason: 'OWNER_POSITION_UNKNOWN' });

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

Query Discovery — подсказывает кластер, не назначает его

Отдельная очередь: какие запросы вообще появились в GSC, но ещё не прописаны в Owner_Map. Для каждого такого запроса нода пытается угадать владельца по маркерам-словам с проверкой на границу слова (чтобы "ложки" не сработало внутри "вилки"):

// Маркер должен начинаться на границе токена
return new RegExp(`(^|[^а-яёa-z0-9])${esc}[а-яёa-z0-9-]*`, 'i').test(q);

Результат - предложение с меткой уверенности:

Метка

Уверенность

Что значит

MASTER_PRIMARY

высокая

точное совпадение с эталонным запросом категории

RULE_MARKER

высокая

сработал один однозначный маркер-слово

AMBIGUOUS

низкая

сработали маркеры нескольких категорий сразу - нужна ручная проверка

MODEL_QUERY

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

UNCLASSIFIED

ни один маркер не сработал

Разница с основным скорингом принципиальна: Discovery никогда не становится доказательством каннибализации сама по себе - это отдельная очередь на ревью, а не источник инцидентов.


Контроль важных запросов отдельно от скоринга

Кроме взвешенной оценки, у каждой категории есть primary_query из Master_Briefs - эталонный запрос, за которым следят отдельно от того, попал ли он в скоринг. Проверка сверяет, кто фактически лидирует в GSC, с кэшированным или живым SERP, и выдаёт один из статусов: подтверждён нужный URL, подтверждён конфликт, смешанный результат, владелец вне топ-10, ошибка данных или "неоднозначный запрос", если в нём есть название бренда и в выдаче участвует главная страница или карточка товара (по бренду законно ранжируется что угодно, это не конфликт категорий).

Это сознательно отдельный от скоринга слой: контроль эталонных запросов ничего не добавляет и не снимает с risk_score, это параллельная сверка "ранжируется то, что должно?", ценная сама по себе, даже когда общий скоринг ничего не подсветил.

Визуализация: граф конфликтов, а не просто список

На выходе скана - два изображения. Первое - это Graphviz DOT-граф: блок целевой категории → блок с перехваченными запросами и цветом по severity → блок конкурирующей страницы. Показываются только два самых рискованных активных конфликта, с явной пометкой "ещё N - в полном отчёте", если их больше.

Второе изображение - это обычный горизонтальный bar-чарт risk_score по всем активным инцидентам, тот же принцип, что и в контент-аудите: зелёного тут нет в принципе, чарт рисует только то, что уже прошло порог WATCH.

Помесячный отчёт: три графика, модель отклонения от сайта и AI-резюме

Отчёт 1-го числа месяца включает не только каннибализацию — у него собственный аналитический контур, сопоставимый по объёму со всей остальной системой.

Раз в месяц воркфлоу генерирует управленческий пакет:

  • Текстовую экспресс-сводку в Telegram (трафик, конверсии, поведение и срез после переоптимизации).

  • AI-интерпретацию поверх детерминированных расчётов с прогнозом (? НАБЛЮДАТЬ).

  • Три графических среза (макротренд, матрица категорий, позиции в выдаче).

  • Прикреплённый файл SEO_Categories_Monthly_YYYY-MM-DD.md с постраничной аналитикой по всем 16 категориям и сравнением год к году.


Три графика: от макротренда к позициям в выдаче

1. История 6 месяцев (сжато) + последние 60 дней подробно с таймлайном правок
Позволяет отличить сезонный спад от технической просадки и сопоставить тренд с реальными релизами.

SEO категорий: история 6 месяцев и 60 дней подробно
SEO категорий: история 6 месяцев и 60 дней подробно
  • Линия baseline: отсечка, с которой начался регулярный мониторинг и замеры.

  • Маркеры правок (SEO - 1 авг, SEO - 12 авг): точечные даты выкатки правок из таблицы SEO_Change_Log. Наглядно видно, изменился ли тренд после изменений на странице.

  • Сведение Google и Яндекс на одну шкалу: позволяет мгновенно заметить расхождение между поисковиками.


2. Матрица изменений по категориям за последний месяц
Построчный срез в разрезе каждого раздела каталога: Яндекс-визиты, Google-клики и показы с индикаторами динамики (▲ / ▼ / ●).

SEO категории: изменения за последний месяц
SEO категории: изменения за последний месяц
  • Фиксация ножниц: если показы растут (Google: 68 → 109 ▲), а клики стоят на месте (1 → 1 ●) - проблема в сниппете, кликабельности (CTR) или несоответствии интента.

  • Категории-локомотивы: сразу показывает ядро трафика - 7 036 из 13 996 показов Google приходятся на одну категорию ("Категория 1").


3. Тепловая карта primary-запросов (Google vs Яндекс)
Срез по 16 эталонным запросам категорий с цветовой кодировкой: ? топ 1-4, ? топ 5-10, ? >10. Стрелки месячного движения подключаются после накопления истории от 21 до 45 дней.

SERP primary: текущие позиции категорий
SERP primary: текущие позиции категорий
  • Алгоритмический рассинхрон: "Категория 3" сидят на #1 в Яндексе и на #5 в Google; "Категория 5" - #4 в Яндексе и >10 в Google. Это сразу отсекает текстовый переспам и указывает на ссылочные или поведенческие различия.

  • Изолированный контроль: статус primary-запросов не влияет на скоринг каннибализации это параллельная витрина ранжирования ключевых страниц.


Экспресс-сводка и AI-выжимка в Telegram

Бот присылает компактную сводку прямо в канал, чтобы оценить общую динамику без открытия таблиц:

Пример сообщений в Telegram: экспресс-сводка и AI-резюме

? SEO Сводка по Категориям (30 дней)

ТРАФИК И ДИНАМИКА • Яндекс Визиты: 140 (пред. 30 дней: 195, Δ -55 ?) • Google Клики: 220 (пред. 30 дней: 360, Δ -140 ?) • Google Показы: 31 500 (пред. 30 дней: 45 000, Δ -13 500 ?)

ПОСЛЕ ПЕРЕОПТИМИЗАЦИИ (факт к ожиданию по сайту) • Яндекс: 170 → 140 ? -17.6% · ожидалось ~185 · хуже тренда сайта • Google клики: 350 → 220 ? -37.1% · ожидалось ~310 · хуже тренда сайта • Google показы: 42 000 → 31 500 ? -25.0% · ожидалось ~30 800 · в русле сайта

КОНФЛИКТЫ И ВЫДАЧА • ?️ Каннибализация категорий: 1 конфликт (ущерб низкий) • ? Межтиповой перехват: 1 пересечение (ущерб низкий) • ? SERP primary (16 запросов): Google 4? / 4? / 8? · Яндекс 3? / 6? / 7?

? SEO-анализ категорий за месяц (AI-резюме)

  1. Макротренд: трафик категорий снизился сильнее общего движения сайта (Яндекс по сайту +5.8%, по категориям -28.2%). При этом показы в Google просели синхронно с общим трендом каталога.

  2. Драйверы: основной объём трафика удерживают категории сегментов "Alpha" и флагманская линейка "Бренд X". В Яндексе локальный спад затронул большинство ключевых посадочных страниц.

  3. SERP: в Google в первой четвёрке ранжируются эталонные запросы категорий Alpha, Beta, Gamma и Delta. В Яндексе в топ-4 удерживаются коммерческие посадочные категорий Epsilon, Alpha и Zeta.

  4. Прогноз: ? НАБЛЮДАТЬ. Трафик категорий падает быстрее сайта, зафиксированы единичные пересечения интентов без подтверждённого коммерческого ущерба. Рекомендовано подготовить варианты разграничения интентов в метатегах и продолжать сбор метрик.


Модель ожиданий по сайту: почему плохой месяц — не всегда RED

Оценивать категорию в вакууме бессмысленно: если раздел упал на 15%, а весь каталог из-за сезонности просел на 30%, категория чувствует себя лучше рынка.

Система рассчитывает две оценки отклонения от ожидания: structural_residual_pct (к годовому тренду сайта) и short_residual_pct (к динамике за последний месяц). Итоговый статус балансирует оба сигнала: если годовой тренд отрицательный, но за последние 30 дней наметился разворот вверх, категория не уходит в тревогу.

Код: расчет ожиданий по сайту и калибровка статуса
const expectedFromSite = (yoyValue, siteCurrent, siteYoy) =>
  (Number(siteYoy) > 0 ? Number(yoyValue) * Number(siteCurrent) / Number(siteYoy) : null);

const residualPct = (actual, expected, minExpected = 1) =>
  (expected !== null && Number(expected) >= minExpected 
    ? round1((Number(actual) / Number(expected) - 1) * 100) 
    : null);

// Разворот на коротком окне смягчает застарелый негативный годовой тренд
if (structural === 'CATEGORY_SPECIFIC_LOSS') {
  if (shortRelative === 'BETTER_THAN_SITE' || shortS === 'UP') return 'YELLOW';
  return 'RED';
}

Статус

Код

Логика классификатора

В отчёте за месяц

? Норма

GREEN

Раздел растёт или держится в русле тренда сайта

0 категорий (весь каталог просел сильнее сайта)

? Наблюдение

YELLOW

Разнонаправленные метрики или отскок на коротком окне

10 категорий (в т.ч. "категория 1")

? Внимание

RED

Синхронное падение по месяцу и году без отскока

0 категорий (системного краха нет)

Мало данных

LOW_DATA

Меньше 10 визитов/кликов (нерепрезентативный объём)

6 категорий (выводы отложены)

Детальный Markdown-аудит

Вместе с графиками бот отправляет файл SEO_Categories_Monthly. В нём каждая категория расписана по визитам, отказам, времени на странице и динамике YoY. Это позволяет сразу провалиться в цифры конкретного URL, получившего статус YELLOW.

Пример полного Markdown-отчёта
# SEO-анализ категорий за месяц · 30 дней

> Только категории каталога.

## ? После переоптимизации

- Яндекс-визиты: **79 → 56** (-29.1%); ожидалось по движению сайта ~83; **хуже общего тренда сайта**.
- Google клики: **185 → 109** (-41.1%); ожидалось по движению сайта ~148; **хуже общего тренда сайта**.
- Google показы: **19 906 → 14 398** (-27.7%); ожидалось по движению сайта ~14 041; **примерно в русле сайта**.

## ? Сводка за последние 30 дней

- Яндекс-визиты: **81 → 56** (-30.9%)
- Google клики: **181 → 108** (-40.3%)
- Google показы: **20 011 → 13 996** (-30.1%)
- Яндекс по всему сайту: **2 533 → 2 691** (+6.2%)
- Google клики по всему сайту: **1 871 → 1 457**
- Google показы по всему сайту: **88 831 → 60 970**

## ? Год к году · дополнительный контекст

- Яндекс: 4 из 16 категорий · 54 → 32 (-40.7%)
- Google клики: 6 из 16 · 69 → 71 (+2.9%)
- Google показы: 9 из 16 · 7 506 → 12 709 (+69.3%)

## ? SERP primary — позиции и динамика

> Показана позиция именно назначенной категории (owner URL). Месячные стрелки появятся после накопления истории 21–45 дней.

- Primary-запросов: **16**
- Текущий срез: **2026-08-27**
- Google: TOP 1–4 **4** · 5–10 **4** · >10 **8**
- Яндекс: TOP 1–4 **3** · 5–10 **6** · >10 **7**

| Категория | Primary query | Google | Δ | Яндекс | Δ |
|---|---|---:|---:|---:|---:|
| Категория Alpha | `купить товар alpha каталог` | #2 | — | #3 | — |
| Категория Beta | `товары категории beta цена` | #4 | — | >10 | — |
| Категория Gamma | `линейка оборудования gamma` | #5 | — | #1 | — |
| ... | *[ещё 13 primary-запросов]* | ... | — | ... | — |

## ? Изменения под наблюдением

*Активных WATCH-изменений нет.*

---

## ? Норма — 0

*Нет*

---

## ? Требуют наблюдения — 10

### ? Категория Alpha (Флагманская линейка)

**Яндекс Визиты:** **20**
├ Предыдущие 30 дней: 33 (Δ -13) ?
└ Год назад: 9 (Δ +11) ?

**Google Показы:** **7 036**
├ Предыдущие 30 дней: 8 176 (Δ -1 140) ?
└ Год назад: 1 430 (Δ +5 606) ?

**Google Клики:** **34**
├ Предыдущие 30 дней: 48 (Δ -14) ?
└ Год назад: 40 (Δ -6) ?

**Поведение**
Отказы: **50%**
└ Предыдущие 30 дней: 48.5% (Δ +1.5 п.п.) ?

Время: **1м 21с**
└ Предыдущие 30 дней: 1м 4с (Δ +16с) ?

Глубина: **1.6**
└ Предыдущие 30 дней: 1.55 (Δ +0.05) ?

*? Вывод:* За месяц показатели идут в разные стороны: локальный спад месяца на фоне долгосрочного роста к прошлому году. Яндекс снижается, Google-клики снижаются, Google-показы снижаются.

---

### ? Категория Beta (Сегмент Pro / Тяжёлая серия)

**Яндекс Визиты:** **6**
├ Предыдущие 30 дней: 16 (Δ -10) ?
└ Год назад: 32 (Δ -26) ?

**Google Показы:** **524**
├ Предыдущие 30 дней: 1 201 (Δ -677) ?
└ Год назад: 101 (Δ +423) ?

**Google Клики:** **8**
├ Предыдущие 30 дней: 23 (Δ -15) ?
└ Год назад: недостаточно данных для сравнения

**Поведение**
Отказы: **33.3%**
└ Предыдущие 30 дней: 31.3% (Δ +2.1 п.п.) ?

Время: **4м 58с**
└ Предыдущие 30 дней: 4м 23с (Δ +35с) ?

Глубина: **2**
└ Предыдущие 30 дней: 3.31 (Δ -1.31) ?

⚪ Поведение: выборка меньше 10 визитов из Яндекса — не используем как устойчивый сигнал.

*? Вывод:* Категория снижается заметно сильнее общего тренда сайта. За месяц: Яндекс снижается, Google-клики снижаются, Google-показы снижаются. Требуется ручной аудит сниппетов.

---

... [остальные 8 категорий в статусе ? Требуют наблюдения опущены для краткости] ...

---

## ? Требуют внимания — 0

*Нет*

---

## ? Проверка данных — 0

*Нет*

---

## ⚪ Мало данных — 6

... [6 категорий каталога с выборкой менее 10 визитов/кликов опущены: выводы отложены до накопления данных] ...

---

## ⚙️ Данные

- Метрика Яндекс: OK / OK / OK
- GSC: OK / OK / OK
- Snapshot: PAGE-V3:2026-08-30:M:2026-08-30
- Каннибализация: CANNIB:2026-08-30:YQ:2026-08-30

Отслеживание ручных правок - система не закрывает вопрос сама

Для контроля внедрений заведена таблица SEO_Change_Log. Пайплайн работы с ней выстроен так, чтобы исключить ложные выводы:

  1. Фиксация правки (руками): заносим URL, дату релиза, суть изменения и проверяемую гипотезу со статусом WATCH.

  2. Расчёт эффекта (n8n): нода Analyze SEO Changes Monthly сравнивает фактическую динамику с модельной за равные отрезки времени "до" и "после" даты внедрения, а затем строит график восстановления, когда накопится репрезентативный объём данных.

  3. Валидация результата (руками): система может показать, что трафик восстанавливается быстрее или медленнее прогноза, но перевести статус в RESOLVED может только специалист.

Это осознанное ограничение автоматизации, а не недоработка: подтверждение причинно-следственной связи (помогла именно наша правка, а не апдейт выдачи или сезонный всплеск) всегда остаётся за человеком.


Почему логика детерминированная, а LLM — только рассказчик

Здесь работает тот же инженерный принцип, что и в предыдущих статьях цикла (GEO-детект без второй модели, regex вместо тяжёлого HTML-парсера в контент-аудите):

Вся аналитика строго детерминирована: risk_score, severity, lifecycle и логика диагнозов рассчитываются исключительно математикой в Code-нодах на чистом JS.

LLM (в моём случае Qwen) получает на вход уже готовый JSON и выступает исключительно в роли интерфейса - собирает сухие цифры в связную сводку для Telegram. Замените модель на любую другую, отключите её вовсе или отдавайте сырые данные напрямую в дашборд - скоринг, вердикты и приоритеты не изменятся ни на балл.

Результаты: как именно получается 59 из 100

Собранный воркфлоу производит инцидент-карточки такого вида:

Кластер: "ложки / вилки" — HIGH 59/100
Владелец: /collection/example-a · Конкурент: /collection/example-b (категория)
Confidence: HIGH (0.9) · Lifecycle: PERSISTING · Consecutive runs: 11
Показы 28д: владелец 0 / конкурент 127 (100% доля конкурента)
Клики 28д: владелец 0 / конкурент 0
Пред. 28д: владелец 0 / конкурент 217
7д: владелец 0 / конкурент 14; пред. 7д: владелец 0 / конкурент 37

Разложить 59 баллов на компоненты можно прямо по формуле:

Фактор

Расчёт

Балл

Доминирование

доля конкурента 100% (потолок)

25

Смещение позиции

у владельца 0 показов, у конкурента позиция ≤20

20

Захват кликов

кликов 0 у обоих - фактор не сработал

0

Тренд периода

у владельца 0 показов и до, и после - падать неоткуда, тренд не засчитан

0

Структурное несоответствие

владелец 0 показов при конкуренте 10+

10

Персистентность

11 прогонов подряд ≥ 3

10

Сырая сумма

65

Confidence

127 показов в паре → 0.85, плюс +0.05 за 7+ запросов в кластере

×0.90

Итог

round(65 × 0.90)

59 → HIGH

Показательный момент: у конкурента снижение показов 217 → 127 за месяц и 37 → 14 за неделю - конфликт объективно слабеет, но lifecycle всё равно остаётся PERSISTING, а не переключается в IMPROVING, потому что для IMPROVING риск-скор должен упасть минимум на 10 баллов от прошлого замера, а не просто показать снижение показов конкурента. Отдельная деталь — при confidence 0.90 и compShare 100% формально выполнены два из трёх условий CRITICAL (доля ≥65%, 11 прогонов ≥2), но сама планка risk_score ≥75 не взята: без вклада от тренда и кликов сырых 65 баллов даже с максимальным confidence не хватает. Конфликт стабильный и объёмный, но не "горит" - ровно то разделение, ради которого и городился шестифакторный подсчёт вместо одного правила "доля выше X% → тревога".

Плюсы и ограничения подхода

Область

Сильные стороны (Плюсы)

Ограничения и компромиссы

Скоринг и аналитика

Диагноз вместо списка пересечений: шкала риска 0-100 с конкретным планом действий вместо голого факта совпадения URL.

Эвристические веса: коэффициенты (25/20/15…) и пороги подобраны инженерной оценкой, а не обучены на исторических данных бизнеса.

Фильтрация шума

Защита от ложных тревог: уровень CRITICAL требует повторов или объёма; свежий месячный отскок гасит застарелую годовую тревогу.

Чувствительность к конфигу: модель слепо доверяет Owner_Map - при ошибке в таблице скоринг честно рассчитает риск для неправильной пары.

Инженерия и бюджет

0 рублей на платные тарифы: двухуровневый TTL-кэш и точечные дозапросы строго удерживают SerpApi в лимите 250 запросов/мес.

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

Валидация решений

Контроль причинности: n8n показывает динамику до/после, но статус RESOLVED подтверждает только человек, исключая ложные автовыводы.

Человеческий фактор: система не закрывает инциденты автономно - разбор спорных кейсов и ведение лога правок требуют дисциплины оператора.

Стоимость

GSC, Яндекс.Метрика и Яндекс.Вебмастер - бесплатные. У SerpApi для живых SERP-проверок есть бесплатный лимит - 250 запросов в месяц, дальше тарифы стартуют от $25 за 1000. Вся конструкция с TTL-кэшем и точечным дозапросом построена так, чтобы держаться в этом бесплатном лимите: свежий кэш перекрывает большинство прогонов, а живой запрос идёт только для действительно неоднозначных случаев. Весь дизайн freshness/backfill существует ровно для того, чтобы никогда не пришлось переходить на платный план.

Код

Репозиторий тот же — n8n-seo-monitor-suite. Воркфлоу из этой статьи - в monthly-anticannibal/: README с полной схемой обеих таблиц состояния, форматом карточки инцидента и списком статусов контроля primary-запросов.

Про GEO-мониторинг видимости в ИИ-ответах и про ежедневный/еженедельный контент-аудит - первые две статьи цикла.

Комментарии (2)


  1. romankurnovskii
    11.09.2026 14:36

    в SQL‑запросе используется прямое деление на ContentScore. При значении 0 это приводит к исключению и останавливает весь workflow, такая ситуация может возникнуть?

     фильтр проверяет только, что два URL не перекрываются, будет ли учитывать внутренние ссылки (одна страница может ссылаться на другую,?


    1. Dimazzina Автор
      11.09.2026 14:36

      В воркфлоу же вообще SQL не используется. Про внутренние ссылки: скан работает с данными поисковой аналитики (Google Search Console, Яндекс.Метрика и точечный SERP), а не как краулер. Он не парсит DOM страниц на лету и не строит граф внутренней перелинковки