
Фасетные фильтры и SEO: полный гайд
Безопасная SEO-стратегия для фасетных фильтров строится на whitelist — заранее утверждённом списке: в индекс открывают только комбинации с подтверждённым спросом, стабильным ассортиментом и самостоятельной ценностью.

Безопасная SEO-стратегия для фасетных фильтров строится на whitelist — заранее утверждённом списке: в индекс открывают только комбинации с подтверждённым спросом, стабильным ассортиментом и самостоятельной ценностью. Остальные состояния интерфейса нормализуют, исключают из индекса, ограничивают от обхода или оставляют только в JavaScript — в зависимости от задачи. При этом robots.txt управляет обходом и сам по себе не удаляет URL из поиска, noindex работает лишь на доступной роботу странице, а rel="canonical" остаётся рекомендацией поисковой системе.
Материал актуален на 6 сентября 2026 года. Он подходит для интернет-магазинов, маркетплейсов, каталогов услуг и SaaS-директорий. Ниже есть матрица решений, модель отбора посадочных страниц, требования к URL, примеры для Next.js и обычного бэкенда, план миграции и проверка по Google Search Console, Яндекс Вебмастеру и логам сервера.
Что такое фасетная навигация и откуда берётся SEO-риск
Фасет — характеристика объекта, по которой пользователь сужает каталог: бренд, цвет, размер, цена, страна, интеграция, тариф, тип лицензии. Обычный фильтр может менять один параметр. Фасетная навигация позволяет комбинировать несколько независимых параметров и выбирать несколько значений внутри каждого. Далее UX-фильтрами называются состояния, созданные для удобства пользователя и не отобранные как поисковые посадочные.
Для пользователя это быстрый путь к подходящим объектам. Для поискового робота каждая комбинация может выглядеть как новая страница:
/noutbuki/?brand=asus&ram=16&os=windows
/noutbuki/?ram=16&brand=asus&os=windows
/noutbuki/asus/windows/16-gb/
/noutbuki/?brand=asus&ram=16&os=windows&sort=price&page=2
Первые три адреса могут показывать одну выборку. Четвёртый меняет порядок и страницу списка, но наследует те же фасеты. Если приложение не задаёт единый URL-контракт, робот обнаруживает перестановочные дубли, сортировки, пустые сочетания и страницы за пределами пагинации. Для более широкого разбора URL и структуры пригодится статья об оптимизации структуры сайта для SEO.
Как оценить масштаб до разработки
Для фасетов с одним выбранным значением верхняя оценка числа состояний равна:
N = (1 + v1) × (1 + v2) × ... × (1 + vk) − 1
v1...vk — число значений в каждом фасете, единица означает «фасет не выбран». Если внутри фасета разрешено любое подмножество значений, оценка становится гораздо больше:
N = 2^(v1 + v2 + ... + vk) − 1
Допустим, в категории есть 5 цветов, 6 брендов и 7 размеров.
| Режим | Расчёт | Потенциальные состояния |
|---|---|---|
| Один вариант каждого фасета | 6 × 7 × 8 − 1 |
335 |
| Любой мультивыбор | 2^(5+6+7) − 1 |
262 143 |
| Мультивыбор × 4 сортировки × 20 страниц | 262 143 × 4 × 20 |
20 971 440 |
Это верхняя граница. Реальные несовместимые сочетания сократят число результатов, но сервер всё равно получит запрос, если не распознает ошибку заранее. Три параметра, разрешённые в любом порядке, дают до шести перестановок одной комбинации. Tracking-параметры, представление плиткой или списком, валюта и язык умножают пространство ещё раз.
SEO-риск начинается раньше миллиона URL. Небольшой каталог может получить десятки тысяч тяжёлых запросов к базе, одинаковые title, конкурирующие посадочные и задержку обнаружения новых карточек. Термин «crawl budget» особенно важен для крупных и быстро обновляемых сайтов, но нормализация URL и корректные статусы полезны при любом размере.
Разделите обход, индекс, canonical и обнаружение
Основная ошибка при настройке фильтров — ожидать одинакового результата от четырёх разных механизмов.
| Задача | Главный вопрос | Подходящие инструменты | Ограничение |
|---|---|---|---|
| Контроль обхода | Может ли робот загрузить URL и сколько запросов он потратит? | robots.txt, отсутствие бесконечных ссылок, 404/410, redirect, нормализация |
Запрет обхода не гарантирует исчезновение адреса из поиска |
| Контроль индекса | Может ли загруженная страница участвовать в выдаче? | meta robots: noindex, X-Robots-Tag, 404/410, авторизация |
Чтобы увидеть noindex, робот должен открыть URL |
| Каноникализация | Какую эквивалентную версию считать основной? | 301/308, rel="canonical", согласованные sitemap и внутренние ссылки |
Canonical — сигнал-подсказка; поисковик может выбрать другой URL |
| Обнаружение | Как найти важные посадочные и дальние карточки? | <a href>, пагинация, категории, хлебные крошки, sitemap |
Кнопка или пользовательский JS-сценарий не создают надёжный путь обхода |
Что реально делает robots.txt
Disallow запрещает роботу запрашивать совпадающий URL. Это полезно, когда параметрические страницы заведомо не нужны поиску, а их обход создаёт нагрузку. Но адрес может остаться или появиться в индексе без содержимого, если он известен из ссылок. Поэтому robots.txt нельзя использовать как единственный способ удалить уже индексируемые фильтры.
Есть ещё одно последствие: заблокировав URL, вы закрываете роботу доступ к HTTP-статусу, canonical, noindex и ссылкам на карточки внутри листинга. Массовое правило вида Disallow: /*?* способно одновременно остановить сортировки, важную пагинацию, языковые параметры и выбранные SEO-посадки.
Почему noindex и Disallow конфликтуют
Страница с noindex должна отвечать роботу. Если тот получает запрет в robots.txt, он не загружает HTML и не видит метатег или X-Robots-Tag. Для очистки уже известных URL обычно нужен период доступного обхода с noindex. Ограничение обхода можно включать после подтверждённого удаления, если эти URL больше не нужны для обнаружения карточек.
Такой переход следует проводить осторожно. Если снять большой запрет с миллионов URL одновременно, нагрузка вырастет. До разблокировки нужны нормализация, лимиты на параметры, кэш, 404 для невозможных сочетаний и поэтапный rollout по разделам.
Когда нужен canonical
Canonical уместен для одинаковых или очень похожих представлений:
- разные перестановки одной комбинации;
- URL с tracking-меткой и чистый URL;
- сортировка, которая меняет порядок, но не состав набора;
- технический дубль, временно доступный до redirect.
Если фильтр «ноутбуки ASUS с 16 ГБ» заметно отличается от общей категории, canonical на /noutbuki/ может быть проигнорирован. Он также противоречит цели отдельной SEO-посадки. Предпочтительная посадочная должна иметь self-canonical, собственные метаданные и внутренние ссылки.
noindex + canonical на категорию не стоит назначать всем фильтрам по шаблону. Noindex решает задачу исключения из поиска, canonical — задачу выбора версии среди дублей. Для страницы с другим набором объектов часто честнее оставить noindex без попытки канонизировать её на родителя.
Матрица решений для URL каталога
Матрица задаёт начальную политику. Её уточняют по текущему индексу, способу обнаружения карточек и нагрузке.
| Тип URL | HTTP | Обход | Индекс | Canonical | Внутренние ссылки | Sitemap |
|---|---|---|---|---|---|---|
| Базовая категория | 200 | Разрешён | index, follow |
На себя | Прямые ссылки из меню и таксономии | Да |
| Whitelist-посадочная под спрос | 200 | Разрешён | index, follow |
На себя | Прямые ссылки из категории, хаба, хлебных крошек | Да |
| Обычное состояние фильтра без поисковой ценности | 200 | Доступно для UX; crawl-политику включают по масштабу | noindex, follow на этапе очистки/если нужен обход ссылок |
Обычно отсутствует или на эквивалентную нормализованную версию | Не создавать массовую сетку crawlable-ссылок | Нет |
| Перестановочный или синтаксический дубль | 301/308 | Запрос возможен до переобхода | Целевой URL | Целевой URL | Всегда генерировать только целевой URL | Нет |
| Tracking/session-параметр без изменения контента | 301 с удалением, если параметр больше не нужен после входа; иначе 200 | Разрешён до нормализации | Как у чистой страницы | Чистая страница | Ссылки без параметра | Только чистый URL |
| Сортировка или вид списка | 200 либо 301 на вариант без параметра | Для новых сайтов можно ограничить; для старых сначала очистить индекс | Обычно noindex | На тот же набор без sort/view, если он действительно эквивалентен | Управление может быть формой/кнопкой; не плодить ссылки | Нет |
| Внутренний поиск | 200 | Разрешён для чтения noindex либо ограничен после очистки | noindex, follow |
Обычно отсутствует | Не ставить в навигацию как SEO-страницы | Нет |
| Валидная пагинация категории/SEO-посадки | 200 | Разрешён | Обычно index, follow |
Каждая страница на себя | Последовательные <a href> |
Обычно только первая страница серии |
| Страница за пределами пагинации | 404 | Разрешён получить статус | Исключена по статусу | Нет | Не ссылаться | Нет |
| Пустая или бессмысленная комбинация | 404 | Разрешён получить статус | Исключена по статусу | Нет | Не ссылаться | Нет |
| Временно малый ассортимент | 200 | Разрешён | Index только если посадочная остаётся полезной и стабильной | На себя для сохранённой посадочной | По ценности | Только если indexable |
| Удалённая SEO-посадочная с прямым преемником | 301/308 | Разрешён получить redirect | Целевой URL | Целевой URL | Обновить все ссылки | Нет |
| Удалённая посадочная без аналога | 410 или 404 | Разрешён получить статус | Исключена по статусу | Нет | Удалить ссылки | Нет |
Не требуется закрывать каждый noindex-URL в robots.txt после очистки. Решение зависит от числа URL, частоты обхода, стоимости запросов и необходимости находить карточки через листинг. Оптимизация должна уменьшать измеримую проблему, а не просто увеличивать число директив.
Какие комбинации открывать для поискового трафика
Рабочая единица — отдельная посадочная страница, включённая в реестр. Автоматическое правило «индексировать один фасет и закрыть два» слишком грубое: у сочетания двух параметров может быть высокий спрос, а у отдельного цвета — никакого.
Отбор по спросу и ассортименту
Для каждого кандидата оцените шесть групп сигналов.
| Критерий | Что проверить | Причина отказа |
|---|---|---|
| Поисковый спрос | Частотность, формулировки, сезонность, география, выдача | Нет отдельного кластера или интент информационный |
| Коммерческий смысл | Пользователь действительно выбирает по этому сочетанию | Параметр служебный или меняет только отображение |
| Ассортимент | Число объектов, разнообразие, стабильность по неделям/месяцам | Один случайный объект, частые нулевые результаты |
| Отличие от родителя | Состав и задача заметно отличаются | Почти полный дубль категории |
| Качество страницы | Можно дать точный title, H1, вводный блок, полезные ссылки | Получится серия бессодержательных шаблонов |
| Измеримость | Есть события, выручка/лиды, Search Console и лог-классификация | Невозможно понять пользу и откатить решение |
Порог частотности и минимальное число объектов определяют по нише. У B2B SaaS запрос на десять показов в месяц может приводить дорогой лид. У массового магазина такая частота не окупит отдельную страницу. Поэтому фиксируйте решение и доказательства в реестре, а не зашивайте число 50 или 200 в код.
Пример записи:
{
"routeKey": "crm/for-real-estate/russian-language",
"category": "crm",
"filters": {
"industry": ["real-estate"],
"language": ["ru"]
},
"status": "indexable",
"minInventory": 5,
"queryCluster": "crm для агентства недвижимости на русском",
"locale": "ru-RU",
"reviewedAt": "2026-09-06"
}
Статусы удобно разделить на candidate, indexable, noindex и retired. Только indexable получает self-canonical, индексируемые metadata, ссылки и sitemap. Так UI может поддерживать тысячи пользовательских состояний, а поисковая архитектура останется конечной и проверяемой.
Статическая страница или динамический фильтр
Статическая SEO-посадочная не обязана хранить вручную выбранные карточки. Она может выполнять динамический запрос по сохранённому набору фасетов. Статичность означает стабильный URL, утверждённый intent и управляемые metadata.
| Подход | Когда подходит | Риск |
|---|---|---|
Чистый path из реестра: /noutbuki/asus/16-gb/ |
Важная долговечная посадочная, редакционно управляемый URL | Нужно поддерживать маршруты и редиректы при переименовании |
Нормализованный query: /noutbuki/?brand=asus&ram=16 |
Много валидных комбинаций, единый обработчик | Легче породить перестановки и ненужные ссылки |
| Отдельный slug, связанный с filter JSON | Сложные SaaS/B2B-кластеры и локализация | Нужен реестр соответствий и контроль дрейфа фильтров |
| JS-state без индексируемого URL | UX-фильтры без поисковой ценности | Нельзя поделиться результатом; требуется отдельный путь к карточкам |
Path сам по себе не даёт преимуществ в ранжировании. Его выбирают за читаемость, стабильность и возможность строгого whitelist. Query удобнее для временных состояний и большого числа параметров. На одном сайте эти подходы можно сочетать: SEO-посадки в path, остальные фильтры в query.
Спроектируйте единый URL-контракт
Контракт должен одинаково выполняться сервером, клиентом, canonical-генератором, ссылками, sitemap, аналитикой и кэшем.
Порядок и нормализация
Для каждого запроса:
- Разрешите только известные ключи.
- Приведите ключи и значения к каноническому регистру.
- Декодируйте и повторно кодируйте значение одним алгоритмом.
- Удалите пустые, дублирующиеся и несовместимые значения.
- Отсортируйте значения внутри мультивыбора.
- Отсортируйте ключи в фиксированном порядке.
- Сбросьте
page, когда меняется фильтр или сортировка. - Удалите параметры со значением по умолчанию:
sort=popular,page=1,view=grid. - Сравните входной URL с нормализованным и сделайте 301/308, если смысл полностью совпадает.
- Верните 404 для неизвестных, противоречивых и невозможных комбинаций.
Вход:
/catalog/?size=m&brand=Acme&brand=acme&page=1&sort=popular
Канонический адрес:
/catalog/?brand=acme&size=m
Redirect сильнее canonical и не оставляет пользователю два адреса. Не перенаправляйте пустые фильтры на категорию: такой redirect превращает ошибочный URL в soft 404 — адрес без результата, который отвечает как нормальная страница, — и скрывает проблему генератора ссылок.
Разделители и кодирование
Для query используйте стандартный & между параметрами. Зарезервированные символы percent-encode в UTF-8. Не превращайте запятые, точки с запятой и квадратные скобки в самодельные разделители параметров.
Для мультивыбора практичен повторяющийся ключ:
/krossovki/?brand=adidas&brand=nike&color=black
Значения brand сортируются, дубли удаляются. Альтернатива — один параметр со стабильным, строго описанным форматом значения, но сервер не должен принимать одновременно несколько синтаксисов. Иначе адреса brand=nike,adidas, brand=adidas,nike и два повторяющихся ключа создадут три версии одной выборки.
Для path зафиксируйте порядок типов фасетов, например category → brand → use-case → color. Адреса с переставленными сегментами перенаправляйте на один вариант. Невалидный дубль сегмента должен получить 404.
GET, POST, hash и History API
GET-адрес нужен, когда состояние должно открываться по ссылке, сохраняться в закладке, анализироваться и потенциально индексироваться. POST-запрос или состояние только в памяти приложения не создаёт страницы.
Фрагмент после # обычно не участвует в HTTP-запросе и не подходит для индексируемого результата. Он может быть осознанным выбором для чисто пользовательских фильтров, если важные категории и карточки имеют отдельные crawlable-ссылки. Для shareable состояния без перезагрузки используйте History API и нормализованный query URL.
JavaScript может обновлять список мгновенно, но исходный или серверно отрендеренный HTML должен содержать:
- правильный title, robots и canonical;
- видимый H1 и объяснение индексируемой посадочной;
- основные карточки текущей выборки;
- обычные
<a href>на пагинацию и важные посадочные; - корректный HTTP-статус до гидратации.
Кнопка onClick={() => loadNext()} без ссылки не обеспечивает обнаружение следующей страницы. Sitemap помогает найти URL, но не заменяет связную архитектуру.
Пагинация, сортировка, поиск и остатки
Пагинация
Google рассматривает страницы пагинации как отдельные URL. Каждая валидная страница должна иметь собственный адрес и self-canonical:
/noutbuki/ canonical → /noutbuki/
/noutbuki/?page=2 canonical → /noutbuki/?page=2
/noutbuki/?brand=asus&page=2 canonical → тот же нормализованный URL
Не канонизируйте всю серию на первую страницу: состав карточек различается, а дальние товары могут стать хуже доступны для обхода. Свяжите страницы последовательными <a href>, добавьте возврат к первой и возвращайте 404 для page=0, нечислового номера и номера выше последней страницы.
Google больше не использует rel="next" и rel="prev". Их можно сохранить для другого потребителя, но они не заменяют ссылки пагинации. В sitemap обычно включают первую страницу категории или SEO-посадки. Дальние страницы находятся через ссылки.
Большой SEO-текст не нужно повторять на каждой странице. На продолжениях достаточно листинга, навигации и ясного контекста. Номер страницы можно добавить в title/H1 ради удобства, хотя Google способен распознать последовательность и без уникализации каждого description.
Infinite scroll и «Показать ещё» допустимы как UX-слой. За ними должна существовать серверная пагинация с адресами и ссылками. Проверяйте сценарий с отключённым JavaScript и на мобильном viewport.
Сортировка и вид отображения
sort=price, direction=asc, view=list обычно не создают новый intent. Если меняется только порядок одного набора:
- исключите вариант из sitemap;
- не создавайте массовые индексируемые ссылки;
- canonical может указывать на тот же фильтр без сортировки;
- для старых индексируемых URL сначала дайте роботу увидеть noindex или redirect;
- для нового бесконечного пространства можно ограничить обход паттерна, предварительно убедившись, что правило не заденет страницы и фасеты.
Если сортировка фактически меняет набор, например «только новые за неделю», это уже фильтр. Решение принимают по спросу и стабильности, а не по имени параметра.
Внутренний поиск
Результаты ?q= зависят от произвольного ввода, создают почти бесконечное число URL и часто содержат тонкие или пустые страницы. Базовая политика — noindex, отсутствие в sitemap и отсутствие SEO-сетки ссылок. Популярный устойчивый запрос лучше превратить в управляемую категорию или SEO-посадочную.
Не объявляйте q через Clean-param: поисковая фраза меняет содержимое. Для высокой crawl-нагрузки шаблон поиска можно закрыть в robots.txt после очистки индекса. При этом товары должны находиться через категории и пагинацию.
Нулевой и малый ассортимент
Для обычной пустой комбинации возвращайте 404 по исходному URL. Страница может показать пользователю снятые фильтры, похожие категории и поиск, но HTTP-статус остаётся 404. Redirect всех пустых результатов на категорию создаёт soft 404.
Есть исключение: утверждённая долгоживущая посадочная может временно остаться без товара. Она сохраняет 200, если всё ещё решает задачу — объясняет категорию, показывает ожидаемое пополнение, доступные аналоги и честное состояние. Пустой шаблон с H1 и меню для этого недостаточен.
Для каждой SEO-посадочной задайте операционный порог и окно наблюдения:
если inventory < minInventory 14 дней подряд:
indexable → review
если inventory = 0 и полезного долгоживущего контента нет:
noindex либо 404/410 по политике жизненного цикла
если появился точный преемник:
301 на него
Не переключайте index/noindex ежедневно вслед за остатком. Частая смена сигналов создаёт нестабильность и лишний обход. Используйте гистерезис: отдельные пороги и периоды для выключения и повторного включения.
Не создавайте дубли карточек товара или сервиса
Фильтр должен приводить к канонической карточке. Ссылки вида /product/123?color=red&size=m допустимы для предвыбранного варианта, если canonical и внутренние ссылки согласованы.
| Сценарий | Рекомендуемый URL |
|---|---|
| Цвет/размер не меняет самостоятельную сущность | Один URL товара; query выбирает вариант, canonical на чистый URL |
| У варианта свой SKU, цена, наличие и поисковый спрос | Отдельный стабильный URL варианта с уникальными данными и связью с группой |
| Параметр пришёл только из фильтра | Не переносить весь filter state в ссылку на карточку либо хранить его в referrer/session |
| Карточка удалена, есть точная замена | 301 на замену |
| Карточка удалена без аналога | 410/404, удалить из листингов и sitemap |
Structured data Product относится к конкретному товару или группе вариантов. Не размечайте весь листинг как один Product. На SEO-посадочной полезны BreadcrumbList и честная семантика списка; разметка должна совпадать с видимым содержимым и не гарантирует расширенный результат.
Для SaaS-директории действует тот же принцип: карточка сервиса имеет один стабильный URL. Параметры «для маркетинга», «есть API», «бесплатный тариф» выбирают набор сервисов, но не создают новые копии карточки.
Как оформить индексируемую посадочную
Самостоятельная страница должна отвечать на конкретный запрос лучше общей категории.
| Элемент | Требование | Пример |
|---|---|---|
| URL | Стабильный, нормализованный, без служебных параметров | /crm/dlya-agentstv-nedvizhimosti/ |
| Title | Категория + ключевой признак + полезное уточнение | CRM для агентств недвижимости: сервисы и сравнение |
| H1 | Один, естественный, соответствует выборке | CRM для агентств недвижимости |
| Вводный блок | Объясняет состав и критерий, не повторяет шаблон родителя | Кому нужен набор, что включено, дата актуальности |
| Листинг | Соответствует фильтру в HTML и данным | Только подходящие карточки, честные счётчики |
| Навигация | Хлебные крошки и ссылки на родителя/соседние ценные страницы | Каталог → CRM → Для недвижимости |
| Metadata | index, follow, self-canonical |
Один и тот же URL во всех сигналах |
| Sitemap | Только canonical URL, точный lastmod |
Обновлять при значимом изменении |
Уникальный текст не компенсирует пустую или почти одинаковую выборку. Автогенерация тысяч абзацев по шаблону создаёт дорогое сопровождение и риск слабых страниц. Сначала подтверждают intent и ассортимент, затем готовят текст.
Внутренние ссылки
Индексируемые фасеты получают обычные ссылки из тематически близких страниц:
- блок «Популярные подборки» на родительской категории;
- навигационные хабы по брендам, задачам или отраслям;
- хлебные крошки;
- контекстные ссылки из руководств и сравнений;
- ссылки между действительно соседними посадочными.
Не выводите тысячи значений фасета как <a href> на каждой странице. Пользовательские чекбоксы могут быть формой или JS-управлением, а crawlable-ссылки получают только whitelisted страницы. На ссылках используйте канонический порядок и кодирование параметров.
Sitemap и lastmod
В sitemap включают URL, которые должны участвовать в поиске:
- базовые категории;
- индексируемые фасетные посадочные;
- карточки объектов;
- другие canonical-страницы.
Noindex, redirect, 404, сортировки, внутренний поиск, произвольные фильтры и перестановочные дубли туда не попадают. Отдельный sitemap для SEO-фасетов упрощает мониторинг: видно, сколько утверждённых страниц обнаружено и проиндексировано.
lastmod меняется после значимого обновления состава, текста, разметки или ссылок. Перезаписывать дату ежедневно без изменения страницы вредно для диагностики.
Hreflang
У каждой локали должен быть собственный canonical в том же языке. Все участники hreflang-кластера ссылаются на себя и остальные версии. Не указывайте русскую страницу canonical на английскую только потому, что там исходный каталог.
Для Google hreflang можно разместить в HTML, HTTP headers или sitemap. Для Яндекса используйте link-элементы в head: Яндекс больше не поддерживает языковые версии через sitemap. Состав доступных фильтров может отличаться по стране; включайте в hreflang только реальные эквиваленты, а не любой URL с тем же slug.
Mobile rendering, скорость и кэш
Фасеты часто ломаются именно в мобильной версии: панель спрятана, выбранные параметры не видны, кнопка закрывает результаты, а сервер отдаёт разные metadata для desktop и mobile.
Проверяйте:
- одинаковый основной набор и indexability на мобильном и широком экране;
- фильтр доступен с клавиатуры и скринридера, выбранные значения можно снять;
- применение фильтра не меняет URL на ненормализованный;
- кнопка «Показать ещё» имеет серверную пагинацию;
- canonical, robots, hreflang и structured data присутствуют в итоговом HTML;
- счётчики фасетов не вызывают десятки последовательных запросов;
- URL с 404 действительно отдаёт 404 до выполнения JavaScript.
Кэш без взрыва ключей
Сеть доставки контента (CDN) и backend могут создать отдельную запись для каждой перестановки query. Нормализуйте URL до чтения кэша и включайте в ключ только параметры, влияющие на результат.
cache key = locale + category + normalizedFilterHash + page + effectiveSort
Tracking-метки, view, порядок параметров и default-значения не должны дробить кэш. Для популярных SEO-посадочных полезен прогрев или более долгий срок хранения (TTL). Для хвоста — короткий TTL, ограничение числа записей и защита от лавины параллельных пересчётов.
Возвращайте 304 Not Modified при валидных ETag/Last-Modified, если содержимое не менялось. Следите за временем до первого байта (TTFB), временем запроса к базе, долей попаданий в кэш, 5xx и числом одновременно вычисляемых счётчиков. Быстрый HTML помогает и пользователю, и роботу, но кэширование не исправляет бесконечный генератор адресов.
Паттерн реализации в Next.js с SSR
При серверном рендеринге (SSR) в Next.js App Router удобно разделить URL-парсер, SEO-policy и запрос данных. В Next.js 16 searchParams асинхронны. Один и тот же модуль должен обслуживать страницу и generateMetadata, чтобы метатеги не расходились с данными.
Тип результата policy engine
type FacetDecision = {
normalizedPath: string
normalizedAbsoluteUrl: string
filters: Record<string, string[]>
page: number
mode: 'category' | 'seo-landing' | 'ux-filter' | 'invalid'
indexable: boolean
canonical: string | null
shouldRedirect: boolean
title: string
description: string
hreflang: Record<string, string>
}
Парсер принимает allowlist ключей и значений, сортирует мультивыбор, убирает defaults, проверяет совместимость и ищет комбинацию в seo_facet_pages. Не стройте indexability из условия params.length <= 2: решает запись реестра.
export function decideFacetUrl(input: {
category: string
searchParams: Record<string, string | string[] | undefined>
}): FacetDecision {
const parsed = parseAllowedFacets(input.searchParams)
if (!parsed.valid) return invalidDecision()
const normalizedPath = buildNormalizedUrl(input.category, parsed)
const landing = findSeoLanding(input.category, parsed.filters)
const isCategory = parsed.filterCount === 0
const indexable = isCategory || Boolean(landing)
const normalizedAbsoluteUrl = toAbsoluteUrl(normalizedPath)
return {
normalizedPath,
normalizedAbsoluteUrl,
filters: parsed.filters,
page: parsed.page,
mode: isCategory ? 'category' : landing ? 'seo-landing' : 'ux-filter',
indexable,
canonical: indexable ? normalizedAbsoluteUrl : null,
shouldRedirect: normalizedPath !== parsed.requestPath,
title: landing?.title ?? categoryTitle(input.category, parsed.page),
description: landing?.description ?? categoryDescription(input.category),
hreflang: landing?.hreflang ?? {},
}
}
findSeoLanding в реальном приложении будет асинхронным запросом или чтением кэша. Пример показывает границу ответственности.
Metadata и страница
import type { Metadata } from 'next'
import { notFound, permanentRedirect } from 'next/navigation'
type Props = {
params: Promise<{ category: string }>
searchParams: Promise<Record<string, string | string[] | undefined>>
}
export async function generateMetadata(props: Props): Promise<Metadata> {
const category = (await props.params).category
const query = await props.searchParams
const decision = await getFacetDecision(category, query)
if (decision.mode === 'invalid') {
return { robots: { index: false, follow: false } }
}
return {
title: decision.title,
description: decision.description,
...(decision.canonical
? {
alternates: {
canonical: decision.canonical,
languages: decision.hreflang,
},
}
: {}),
robots: decision.indexable
? { index: true, follow: true }
: { index: false, follow: true },
}
}
export default async function CatalogPage(props: Props) {
const category = (await props.params).category
const query = await props.searchParams
const decision = await getFacetDecision(category, query)
if (decision.mode === 'invalid') notFound()
if (decision.shouldRedirect) permanentRedirect(decision.normalizedPath)
const result = await findCatalogItems(decision)
if (result.total === 0 && decision.mode !== 'seo-landing') notFound()
return <CatalogView decision={decision} result={result} />
}
Policy engine должен вернуть self-canonical с page для каждой индексируемой страницы пагинации и null для обычного UX-фильтра, если у него нет эквивалентного canonical-URL. В рабочем коде не выполняйте тяжёлые запросы дважды: переиспользуйте результат одинакового чтения policy/data в рамках рендера и применяйте подходящий серверный кэш. Redirect лучше делать до дорогой выборки. Проверяйте итоговый HTTP-ответ, потому что красивый компонент 404 без статуса 404 остаётся soft 404.
Ссылки и фильтры
Whitelisted посадочные выводите через Link или обычный <a href>. Чекбоксы остальных фасетов могут обновлять query через router/History API. После изменения фильтра сбрасывайте page.
<Link href="/crm/dlya-agentstv-nedvizhimosti/">
CRM для агентств недвижимости
</Link>
На сервере отрендерите текущие карточки и пагинацию. Клиентская гидратация добавляет мгновенное обновление, состояние загрузки и mobile drawer, но не определяет SEO-policy.
robots.txt и Clean-param в Next.js
app/robots.ts подходит для стандартных Allow/Disallow/Sitemap. Директива Яндекса Clean-param не входит в обычную типизированную модель Next.js. Если она нужна, отдавайте статический public/robots.txt или контролируемый text route и проверяйте точный ответ после сборки.
User-agent: Yandex
Clean-param: utm_source&utm_medium&utm_campaign /catalog/
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml
Не добавляйте сюда brand, color, price, page: они меняют содержимое или путь обнаружения. Паттерны Disallow для сортировок внедряйте только после теста на реальных URL и оценки уже индексируемых страниц.
Полезные актуальные детали реализации собраны в гайде Google по фасетным URL и справке Яндекса по Clean-param.
Паттерн для любого серверного бэкенда
Стек не меняет порядок обработки запроса.
request
→ parse and validate route/query
→ normalize keys and values
→ redirect semantic duplicate
→ classify by SEO registry
→ fetch catalog data
→ 404 invalid/empty ordinary combination
→ render status + metadata + list + links
→ log normalized class and timings
Контракт ответа
| Класс | Status | Robots | Canonical | Кэш |
|---|---|---|---|---|
INDEXABLE_FACET |
200 | index, follow | Self | Длинный TTL/прогрев по спросу |
UX_FACET |
200 | noindex, follow | Только на эквивалентную версию | Ограниченный TTL и размер |
DUPLICATE_SYNTAX |
301/308 | — | Через Location | Кэшировать redirect |
EMPTY_OR_INVALID |
404 | — | Нет | Короткий negative cache |
RETIRED_WITH_SUCCESSOR |
301/308 | — | Через Location | Кэшировать redirect |
RETIRED_GONE |
410 | — | Нет | Кэшировать статус |
Регистрируйте policy version в ответе или внутреннем логе. Тогда после релиза можно сравнить, какой набор правил породил URL и быстро откатить классификацию.
SQL-запросы строят только из проверенных фасетов. Значения передаются параметрами, а не конкатенируются в строку. Для числовых диапазонов задайте минимумы, максимумы и шаг; запрос price_from=-999999999 не должен создавать тяжёлый план или новый кэш-ключ.
Как мигрировать каталог, где фильтры уже разрослись
Миграцию нельзя начинать с общего запрета. Сначала нужно понять, какие URL уже дают трафик, какие участвуют в поиске и через какие листинги робот находит карточки.
Инвентаризация
Соберите за 30–90 дней:
- landing pages и queries из Search Console и Яндекс Вебмастера;
- все URL из sitemap и внутренних ссылок;
- URL, которые обходили Googlebot, YandexBot и Bingbot;
- частоту параметров, уникальные нормализованные комбинации, статусы и время ответа;
- страницы с organic sessions, конверсиями и доходом;
- canonical, robots и indexability из выборочного crawl;
- число карточек, доступных только через фильтр или бесконечную прокрутку.
Сгруппируйте адреса по классу и нормализованному ключу. Отдельно посчитайте перестановочные дубли, сортировки, поиск, page overflow, пустые и 5xx.
Теневой режим
Запустите новый policy engine без изменения ответов. Он записывает предполагаемое решение:
requested_url
normalized_url
old_policy
new_policy
reason
inventory_count
render_ms
Сравните минимум неделю, включая пик трафика и обновление ассортимента. Исправьте случаи, где valuable page попала в noindex/404 либо разные URL получают один и тот же normalized key при разном содержимом.
Порядок релиза
- Остановите генерацию новых дублей: нормализуйте ссылки, параметры и формы.
- Добавьте настоящие 404 для невозможных комбинаций и page overflow.
- Введите whitelist SEO-посадочных и отдельный sitemap.
- Включите redirect для чистых синтаксических дублей малыми группами.
- Для уже индексируемых ненужных URL разрешите обход и отдайте noindex либо redirect.
- Дождитесь подтверждённого сокращения индекса по выборке и отчётам.
- Только затем ограничивайте crawl-паттерны с высокой нагрузкой, если карточки доступны другим путём.
- Раскатывайте категории по очереди и сравнивайте контрольную группу.
Если раньше стоял широкий Disallow, его снятие делайте по одному path/параметру. До этого включите rate limiting для аномальных клиентов, кэш нормализованных выборок, лимиты базы и 404. Не отдавайте 429 или 5xx как постоянную SEO-политику: они сообщают о временной перегрузке и вызывают повторные попытки.
Rollback
Подготовьте до релиза:
- переключатель функции (feature flag) для новой классификации;
- сохранённую версию whitelist и redirect map;
- быстрый возврат старого metadata-поведения;
- возможность убрать новые внутренние ссылки и sitemap-сегмент;
- дашборд 5xx, задержки, попаданий в кэш и частоты запросов роботов;
- владельца решения и условия остановки.
Откат приложения не мгновенно возвращает поисковый индекс. 301 может кэшироваться, а переобход занимает время. Поэтому irreversible-похожие действия — массовые redirect, удаление URL и смена canonical — выпускают меньшими партиями.
Условия автоматической остановки задайте заранее, например: рост 5xx, двукратный рост 95-го процентиля времени ответа, выпадение indexable URL из HTML, неожиданный 404 на контрольных посадочных, резкое падение обнаружения новых карточек.
QA перед выпуском
Проверяйте не одну «красивую» страницу, а матрицу URL.
| Тест | Ожидаемый результат |
|---|---|
| Параметры в другом порядке | Один 301/308 на нормализованный URL |
| Два одинаковых значения | Дубль удалён либо 404 по контракту |
| Неизвестный ключ/значение | 404 или безопасное удаление только заранее разрешённого служебного параметра |
| Reserved/Unicode-символы | Единое UTF-8 percent-encoding, без двойного кодирования |
| Мультивыбор в другом порядке | Один нормализованный URL и тот же набор |
page=1 |
Redirect на URL без default-параметра |
page выше последней |
HTTP 404, не пустой 200 |
| Пустая комбинация | HTTP 404 либо проверенная долгоживущая страница |
| Сортировка | Та же выборка в другом порядке, noindex/canonical по policy |
| Whitelist-посадочная | 200, index/follow, self-canonical, точные title/H1, ссылка и sitemap |
| UX-фильтр | 200, noindex виден в исходном/отрендеренном HTML, отсутствует в sitemap |
| Пагинация | <a href> вперёд/назад, self-canonical, карточки доступны без клика JS |
| Hreflang | Взаимные ссылки, self-reference, canonical той же локали |
| Mobile | Тот же статус, metadata, основной контент и рабочий фильтр |
| Cache | Перестановки не создают разные ключи; нет утечки между локалями/фильтрами |
| Structured data | Совпадает с видимым содержимым, без Product на весь листинг |
Дополнительно проверьте HTML от имени робота, но не доверяйте одному User-Agent: сервер должен давать одинаковую сущность пользователю и поисковику. Для подтверждения принадлежности bot-трафика используйте рекомендуемую поисковиком DNS/IP-проверку, потому что User-Agent легко подделать.
Мониторинг после запуска
Успех выражается не только уменьшением числа URL. Нужно убедиться, что важные карточки быстрее обнаруживаются, посадочные сохраняют показы и сервер тратит меньше ресурсов на хвост.
Google Search Console
Следите за:
- Page indexing: indexed,
Crawled - currently not indexed,Discovered - currently not indexed, duplicate/canonical, noindex, soft 404 и blocked by robots; - Crawl stats: запросы, типы ответов, среднее время, всплески по хосту;
- URL Inspection для контрольных URL каждого класса: fetched HTML, user-declared и Google-selected canonical, разрешение обхода, indexability;
- Search results performance по группам SEO-посадочных и запросам;
- sitemap фасетов: submitted, discovered и indexed не следует смешивать в один показатель.
Инструмента URL Parameters в Google Search Console больше нет. Старые инструкции, предлагающие настроить в нём sort, page и фильтры, не подходят.
Яндекс Вебмастер
Проверяйте:
- «Индексирование → Статистика обхода» по path и GET-параметрам;
- «Страницы в поиске» и причины Clean-param, noindex, canonical, robots;
- «Настройка GET-параметров» для обнаруженных параметров и конфликтов;
- «Анализ robots.txt» на конкретных контрольных URL;
- «Проверка страницы» для статуса, доступности и версии робота;
- мониторинг важных SEO-посадочных;
- скорость обхода только после анализа причин нагрузки.
Clean-param применяйте к параметрам, которые не меняют содержимое. Правила поддерживайте в одном месте с URL-контрактом и тестами. Изменение настройки GET-параметров может применяться до недели, а переобход и переклейка не имеют гарантированного срока.
Bing Webmaster Tools
Site Explorer позволяет отфильтровать indexed, robots-disallowed, noindex, redirects, canonical sources и ошибки сервера. В sitemap перечисляйте только canonical URL. IndexNow используйте для уведомления о создании, обновлении и удалении выбранных страниц; он не заменяет policy и не гарантирует индексирование.
Серверные логи и аналитика
Логируйте для каждого запроса:
timestamp
verified_bot / user_segment
requested_url_hash
normalized_url_hash
route_class
policy_version
http_status
canonical_target_hash
result_count_bucket
db_ms
render_ms
cache_status
response_bytes
Полные query могут содержать персональные данные и поисковые фразы. Маскируйте значения, ограничивайте срок хранения и храните только необходимые измерения.
Еженедельный отчёт удобно строить по классам:
| Метрика | Зачем |
|---|---|
| Bot requests к UX-фильтрам | Показывает, уменьшается ли бесполезный обход |
| Доля 200/3xx/404/410/5xx | Находит soft 404, циклы и перегрузку |
| Уникальные requested / normalized URL | Измеряет перестановочные и tracking-дубли |
| Медиана и 95-й процентиль времени render/БД | Проверяет стоимость фасетов |
| Cache hit по route class | Находит фрагментацию кэша |
| Время до первого обхода новой карточки | Проверяет discovery |
| Indexed SEO-посадочные / whitelist | Находит утечки и выпадения |
| Clicks, conversion, revenue/lead quality | Проверяет реальную ценность посадочных |
Сравнивайте одинаковые сезонные периоды и контрольные категории. Падение числа обходов само по себе не является успехом, если одновременно перестали находиться новые товары.
Вывод
Фасетные фильтры становятся SEO-активом, когда поисковая архитектура конечна и управляется данными. Утвердите небольшой whitelist посадочных под спрос, нормализуйте каждый URL, возвращайте честные статусы и обеспечьте карточкам обычный ссылочный путь. Остальные фильтры оставьте инструментом пользователя и задайте им явную policy.
Выбирайте механизм по цели: robots.txt — для прекращения обхода, noindex — для исключения доступной страницы из выдачи, canonical — для эквивалентных дублей, redirect — для устранения лишнего адреса, ссылки и sitemap — для обнаружения важных страниц. Выпускайте изменения по разделам, проверяйте HTML, индекс и серверные логи, а rollback готовьте до массовой переклейки.
Автор статьи

Редактор и автор статей
Пишет экспертные материалы о цифровом маркетинге и автоматизации. Журналист с опытом в деловых медиа, отвечает за качество и достоверность публикаций.
Вопросы и ответы
Не гарантированно. Robots.txt запрещает обход, но известный по ссылкам URL может остаться или появиться в поиске без содержимого. Для удаления дайте роботу увидеть noindex, верните 404/410 либо настройте redirect по реальной цели страницы.
Это мешает удалению: заблокированный робот не загрузит страницу и не прочитает noindex. Для уже известных URL сначала разрешают обход и отдают noindex, проверяют исключение, затем при необходимости ограничивают будущий обход паттерна.
Только если страницы действительно одинаковы или очень похожи. Фильтр с другим набором объектов и отдельным intent может заставить поисковик проигнорировать canonical. Индексируемая SEO-посадочная должна иметь canonical на себя.
Поисковая ценность зависит от стабильности, содержимого и ссылок, а не от вида разделителя. Path удобен для whitelisted посадочных, query — для временных UX-состояний. В обоих случаях нужен единый порядок, нормализация и защита от дублей.
Универсального числа нет. Открывайте только страницы с отдельным спросом, устойчивым ассортиментом, собственным intent, качественными metadata и внутренними ссылками. Реестр и регулярный review важнее глубины из одного или двух фасетов.
Обычно такая страница слишком нестабильна и конкурирует с карточкой. Исключение возможно для ценного узкого intent, если посадочная полезна сама по себе и ассортимент не исчезает случайно. Решение подтверждают спросом и конверсией.
Для обычной пустой или бессмысленной комбинации — HTTP 404 по исходному URL. Не перенаправляйте все пустые страницы на категорию. Утверждённая долгоживущая посадочная может сохранить 200, если содержит полезное объяснение, актуальное состояние и реальные альтернативы.
Нет. У каждой валидной страницы пагинации должен быть собственный URL и self-canonical. Между страницами нужны обычные , иначе дальние карточки могут остаться необнаруженными.
Google их больше не использует. Другие системы могут учитывать эти отношения, но основа — отдельные URL, self-canonical и последовательные ссылки пагинации.
AJAX не гарантирует отсутствие URL: робот может найти их в ссылках, sitemap, аналитических отчётах или внешних источниках. Если фильтр не должен создавать поисковые страницы, не генерируйте crawlable-сетку. Важные листинги и карточки всё равно должны быть доступны через SSR и .
Нет, это директива Яндекса. Она подходит только для параметров, не меняющих содержимое, например tracking-меток. Для Google используйте нормализацию, redirect, canonical, noindex и robots.txt в соответствии с задачей.
Добавляйте только утверждённые indexable-посадочные с self-canonical и HTTP 200. Произвольные фильтры, сортировки, поиск, noindex, redirects и ошибки в sitemap не нужны.
Произвольные from/to создают огромное пространство и редко подходят для индексации. Ограничьте минимум, максимум и шаг, нормализуйте ввод. Под заметный спрос создайте несколько управляемых диапазонов как отдельные посадочные, остальные оставьте UX-состояниями.
Нет. Разметка помогает понять уже доступное содержимое и не отменяет robots, noindex, canonical или оценку качества. Product относится к конкретному товару или группе вариантов; листинг не следует размечать как один товар.
Гарантированного срока нет. Он зависит от частоты обхода, размера сайта, ссылок и типа изменения. В Яндекс Вебмастере настройка GET-параметров может применяться до недели, но полная очистка или переклейка занимает дольше. Измеряйте контрольную выборку и не меняйте policy ежедневно.




Комментарии(0)
Оставьте комментарий
Войдите, чтобы присоединиться к обсуждению