Оптимизация SEO для фильтруемых страниц каталога (faceted navigation SEO)
Фасетная навигация — фильтрация каталога по атрибутам: цвет, размер, бренд, ценовой диапазон, рейтинг. Каждая комбинация фильтров генерирует уникальный URL. На каталоге из 1000 товаров с 10 атрибутами по 20 значений каждый — математически возможны миллионы URL. Google попытается их все обойти, потратит весь crawl budget, ни одна страница не получит достаточно сигналов, сайт замедляется в индексации.
Это одна из самых технически сложных SEO-задач, потому что решение нетривиально: часть URL нужно закрыть, часть — оставить открытой и оптимизировать, а граница между ними определяется поисковым спросом.
Диагностика масштаба проблемы
Сначала нужно понять, сколько уникальных URL генерирует текущая фасетка:
# Краулинг через Screaming Frog с фиксацией параметров
# Configuration → Spider → Crawl Behaviour → Enable JavaScript
# Configuration → URL → Ignore parameters → НЕ игнорируем, хотим увидеть всё
# Альтернатива — sitemap анализ
curl -s https://example.com/sitemap.xml | grep '<loc>' | wc -l
# GSC: Coverage report — Excluded → Crawled - currently not indexed
# Если там тысячи URL с параметрами — проблема подтверждена
Параллельно через Ahrefs Site Audit → страницы с параметрами → количество уникальных URL по паттерну ?color=, ?size=, ?brand=.
Классификация URL фильтров по ценности
Не все фильтры одинаково бесполезны для SEO. Методология:
Ценные (нужна индексация): комбинации, под которые есть поисковый спрос:
-
/catalog/laptops/?brand=apple→ «ноутбуки apple» — высокочастотный запрос -
/catalog/dresses/?color=black&length=midi→ «чёрное миди платье» — средне-частотный
Технический мусор (закрыть от индексации):
-
/catalog/?sort=price_asc— сортировки -
/catalog/?page=2&color=red— комбинация пагинации с фильтром -
/catalog/?min_price=0&max_price=99999— ценовые диапазоны без спроса -
/catalog/?color=red&color=blue— мультивыбор одного атрибута
Инструмент для анализа спроса — Ahrefs Keywords Explorer или Яндекс Wordstat. Берём топ-20 комбинаций атрибутов, проверяем частотность.
Технические решения
Метод 1: robots.txt — закрыть параметры от краулинга
Самый грубый инструмент. Использовать только для параметров без SEO-ценности:
# robots.txt
User-agent: *
Disallow: /catalog/*?*sort=
Disallow: /catalog/*?*page=
Disallow: /catalog/*?*min_price=
Disallow: /catalog/*?*max_price=
Проблема: Google может не соблюдать директивы Disallow с wildcard * стабильно. Метод рабочий, но не гарантированный.
Метод 2: noindex + follow для нежелательных комбинаций
Более надёжный вариант — серверная логика, которая добавляет noindex в зависимости от типа URL:
// Laravel Middleware
class FacetedSeoMiddleware
{
private const NOINDEX_PARAMS = ['sort', 'page', 'min_price', 'max_price', 'per_page'];
private const ALLOWED_SINGLE_FACETS = ['brand', 'color', 'size', 'material'];
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
$queryParams = $request->query();
$paramKeys = array_keys($queryParams);
$shouldNoindex = $this->shouldApplyNoindex($paramKeys, $queryParams);
if ($shouldNoindex) {
$response->headers->set('X-Robots-Tag', 'noindex, follow');
}
return $response;
}
private function shouldApplyNoindex(array $paramKeys, array $params): bool
{
// Технические параметры — всегда noindex
foreach (self::NOINDEX_PARAMS as $noindexParam) {
if (in_array($noindexParam, $paramKeys)) {
return true;
}
}
// Больше 2 фасетных параметров — noindex
$facetParams = array_intersect($paramKeys, self::ALLOWED_SINGLE_FACETS);
if (count($facetParams) > 2) {
return true;
}
return false;
}
}
Метод 3: Canonical для дублирующихся комбинаций
Если /catalog/?color=red&brand=nike и /catalog/?brand=nike&color=red генерируют одинаковый контент (разный порядок параметров):
// Нормализация порядка параметров для canonical
function buildCanonicalUrl(Request $request): string
{
$params = $request->query();
ksort($params); // Сортируем ключи по алфавиту
$allowedFacets = ['brand', 'color', 'size'];
$filteredParams = array_filter(
$params,
fn($key) => in_array($key, $allowedFacets),
ARRAY_FILTER_USE_KEY
);
$baseUrl = $request->url();
return $filteredParams
? $baseUrl . '?' . http_build_query($filteredParams)
: $baseUrl;
}
<link rel="canonical" href="{{ $canonicalUrl }}" />
Метод 4: Отдельные SEO-страницы для ценных комбинаций
Самый мощный подход: вместо параметризованных URL создаём чистые slug-based страницы для высокочастотных комбинаций:
/catalog/laptops/apple/ → «ноутбуки apple»
/catalog/dresses/black/midi/ → «чёрное миди платье»
Фильтр на фронтенде может вести на эти URL. Параметризованные дубли закрываются canonical или noindex.
# Редирект с параметра на slug
rewrite ^/catalog/laptops/\?brand=apple$ /catalog/laptops/apple/ permanent;
Контент на этих страницах должен отличаться от базового каталога: уникальный <h1>, описание подборки, хлебные крошки с ключевым словом.
Хлебные крошки и внутренняя перелинковка
Фасетные страницы должны получать внутренние ссылки — иначе Google не посчитает их достаточно важными для индексации, даже если технически они открыты.
<!-- Schema.org BreadcrumbList -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{"@type": "ListItem", "position": 1, "name": "Каталог", "item": "https://example.com/catalog/"},
{"@type": "ListItem", "position": 2, "name": "Ноутбуки", "item": "https://example.com/catalog/laptops/"},
{"@type": "ListItem", "position": 3, "name": "Apple", "item": "https://example.com/catalog/laptops/apple/"}
]
}
</script>
Блок «популярные фильтры» в sidebar или footer с прямыми ссылками на ценные комбинации — это и UX-элемент, и источник внутренних ссылок.
GSC Parameter Handling (устаревший, но полезный контекст)
До 2022 года в Google Search Console был раздел «URL Parameters» для явного указания поисковику, как обрабатывать параметры. Google его убрал. Теперь всё решается через canonical, noindex и robots.txt — описанные выше методы актуальны.
Мониторинг после внедрения
# Скрипт мониторинга: сколько параметризованных URL в индексе GSC
from google.oauth2 import service_account
from googleapiclient.discovery import build
import re
def get_indexed_faceted_urls(site_url: str, credentials) -> list:
service = build('searchconsole', 'v1', credentials=credentials)
response = service.searchanalytics().query(
siteUrl=site_url,
body={
'startDate': '2024-01-01',
'endDate': '2024-03-31',
'dimensions': ['page'],
'rowLimit': 25000,
'dimensionFilterGroups': [{
'filters': [{
'dimension': 'page',
'operator': 'contains',
'expression': '?'
}]
}]
}
).execute()
faceted_urls = [
row['keys'][0]
for row in response.get('rows', [])
if re.search(r'\?(sort|page|min_price|max_price)=', row['keys'][0])
]
return faceted_urls
Метрика успеха: снижение количества crawled URL с параметрами через 4–8 недель после внедрения noindex/canonical. Можно отследить в GSC Coverage report.
Сроки
Аудит фасетной структуры, классификация параметров, разработка стратегии — 3–5 рабочих дней. Техническая реализация (middleware noindex, нормализация canonical, SEO-страницы для ценных комбинаций) — 5–10 дней в зависимости от объёма и стека. Мониторинг эффекта в GSC — через 4–6 недель после внедрения.







