Canonical и дубли страниц

Главный инструмент против дублей: указываем поисковику, какая версия страницы — настоящая.

canonical — тег <link rel="canonical" href="...">, который говорит поисковику: «среди похожих/одинаковых URL вот этот — основной, индексируй его».

Откуда берутся дубли

Дубли — это когда один и тот же контент доступен по нескольким URL. Источники, с которыми разработчик сталкивается постоянно:

  • параметры: ?utm_source=..., ?ref=..., ?sort=...;
  • фильтры и пагинация каталога;
  • версии с/без завершающего слэша, с/без www, http/https;
  • один товар в нескольких категориях: /phones/x и /sale/x.

Дубли вредны: поисковик дробит ссылочные сигналы между копиями, тратит бюджет краулинга и может выбрать в индекс «не ту» версию.

Как ставить canonical

Тег живёт в <head> и указывает на абсолютный URL канонической версии. На основной странице он ссылается сам на себя (self-canonical) — это норма и хорошая практика.

<!-- На странице /shop/keyboards?sort=price -->
<head>
  <link rel="canonical" href="https://codechick.io/shop/keyboards">
</head>

<!-- На самой /shop/keyboards — ссылка на себя -->
<link rel="canonical" href="https://codechick.io/shop/keyboards">

На codechick.io self-canonical стоит на страницах туториалов и статей — это страхует от случайных дублей с метками и параметрами.

canonical — это подсказка, а не приказ

Важный нюанс: для Google canonical — лишь сильная рекомендация. Если сигналы противоречивы (внутренние ссылки ведут на одну версию, а canonical на другую), поисковик может выбрать иначе. Поэтому canonical должен быть согласован с остальными сигналами: ссылками, sitemap, редиректами.

Как работает под капотом: нормализация и выбор канона

Чтобы понять, что два URL — дубли, их сначала нормализуют (единый регистр, убрать трекинговые параметры, унифицировать слэш), а затем сравнивают. Модель:

from urllib.parse import urlsplit, parse_qsl, urlencode, urlunsplit

TRACKING = {"utm_source", "utm_medium", "utm_campaign", "ref", "fbclid", "gclid"}

def canonicalize(url):
    parts = urlsplit(url.lower())
    # выкидываем трекинговые параметры, сортируем оставшиеся
    params = [(k, v) for k, v in parse_qsl(parts.query) if k not in TRACKING]
    params.sort()
    path = parts.path.rstrip("/") or "/"
    return urlunsplit((parts.scheme, parts.netloc, path, urlencode(params), ""))

urls = [
    "https://CodeChick.io/shop/keyboards/",
    "https://codechick.io/shop/keyboards?utm_source=tg",
    "https://codechick.io/shop/keyboards?ref=mail",
]
for u in urls:
    print(canonicalize(u))

Вывод:

https://codechick.io/shop/keyboards
https://codechick.io/shop/keyboards
https://codechick.io/shop/keyboards

Все три URL свелись к одному канону — именно его и стоит указать в теге canonical.

Частые ошибки

  • canonical на несуществующий/закрытый URL — указали на страницу с noindex или 404.
  • Относительный или неполный URL вместо абсолютного — рискованно, лучше полный с протоколом и доменом.
  • Все страницы canonical на главную — массовая ошибка шаблона, выкидывает из индекса всё, кроме главной.
  • Конфликт сигналов: canonical говорит одно, внутренние ссылки и sitemap — другое.

Итог

  • canonical указывает поисковику главную версию среди дублей; на основной странице — self-canonical.
  • Это сильная рекомендация, а не приказ: согласуйте её со ссылками, sitemap и редиректами.
  • Используйте абсолютные URL и не направляйте canonical на закрытые/несуществующие страницы.
Проверьте себя
1. Что делает тег rel=canonical?
AЗапрещает индексацию страницы
BУказывает поисковику главную версию страницы среди дублей
CУскоряет загрузку страницы
DПеренаправляет пользователя на другой URL
2. canonical для Google — это…
AЖёсткий приказ, который нельзя игнорировать
BСильная рекомендация, которую поисковик учитывает вместе с другими сигналами
CУстаревший тег, который не работает
DАналог 301-редиректа
3. Почему «все страницы canonical на главную» — серьёзная ошибка?
AГлавная начнёт грузиться медленнее
BПоисковик сочтёт все страницы дублями главной и выкинет их из индекса
Crobots.txt перестанет работать
DЭто удвоит бюджет краулинга