Пошук уроків, статей та іншого контенту
Визначите канонічну адресу сторінки, щоб уникати дублювання контенту та проблем із різними URL.
Одна й та сама сторінка може бути доступна за кількома URL:
https://example.com/articles/nextjs
https://example.com/articles/nextjs?utm_source=newsletter
https://example.com/articles/nextjs?print=trueДля користувача це може бути одна сторінка, але пошукова система може розглядати такі адреси як окремі URL. Це створює дублікати контенту та ускладнює визначення основної сторінки.
Канонічна адреса — це URL, який сайт оголошує основною версією сторінки. У HTML вона має вигляд:
<link rel="canonical" href="https://example.com/articles/nextjs">Канонічна адреса:
допомагає пошуковим системам обрати основну версію сторінки;
об’єднує сигнали різних варіантів URL;
зазвичай не містить технічних параметрів на кшталт utm_source;
має вести на сторінку з тим самим або еквівалентним контентом.
Канонічна адреса не є перенаправленням. Вона не забороняє відкривати альтернативний URL, а лише повідомляє, який URL є пріоритетним.
У Next.js з App Router канонічну адресу задають через Metadata API:
export const metadata = {
alternates: {
canonical: "/articles/nextjs",
},
};Щоб Next.js міг перетворити відносний шлях на повну адресу, потрібно вказати metadataBase.
Наприклад, значення:
metadataBase: new URL("https://example.com")разом із:
canonical: "/articles/nextjs"створить у HTML:
<link rel="canonical" href="https://example.com/articles/nextjs">Для сторінки, URL якої не залежить від параметрів, можна експортувати об’єкт metadata.
Файл app/about/page.tsx:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Про компанію",
alternates: {
canonical: "/about",
},
};
export default function AboutPage() {
return (
<main>
<h1>Про компанію</h1>
<p>Інформація про нашу компанію.</p>
</main>
);
}У кореневому layout потрібно налаштувати базову адресу сайту.
Файл app/layout.tsx:
import type { Metadata } from "next";
import type { ReactNode } from "react";
const siteUrl =
process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000";
export const metadata: Metadata = {
metadataBase: new URL(siteUrl),
title: {
default: "Мій сайт",
template: "%s | Мій сайт",
},
};
export default function RootLayout({
children,
}: {
children: ReactNode;
}) {
return (
<html lang="uk">
<body>{children}</body>
</html>
);
}Для локального запуску буде використано http://localhost:3000. Для production краще задати змінну середовища:
NEXT_PUBLIC_SITE_URL=https://example.comУ результаті сторінка /about матиме канонічну адресу:
https://example.com/aboutДля динамічного маршруту значення канонічної адреси потрібно обчислити з параметра маршруту. Для цього використовується generateMetadata.
Приклад структури:
app/
└── articles/
└── [slug]/
└── page.tsxФайл app/articles/[slug]/page.tsx:
import type { Metadata } from "next";
type PageProps = {
params: Promise<{
slug: string;
}>;
};
export async function generateMetadata({
params,
}: PageProps): Promise<Metadata> {
const { slug } = await params;
return {
title: slug,
alternates: {
canonical: `/articles/${encodeURIComponent(slug)}`,
},
};
}
export default async function ArticlePage({ params }: PageProps) {
const { slug } = await params;
return (
<main>
<h1>Стаття: {slug}</h1>
<p>Вміст статті.</p>
</main>
);
}Для URL:
/articles/nextjsNext.js згенерує:
<link rel="canonical" href="https://example.com/articles/nextjs">generateMetadata виконується для конкретного маршруту, тому кожна стаття може отримати власну канонічну адресу.
У різних версіях Next.js тип
paramsможе відрізнятися. У сучасному App Router параметри маршруту в асинхронних сторінках іgenerateMetadataвикористовуються як Promise, який потрібно очікувати черезawait.
Часто query-параметри змінюють URL, але не створюють окремої сторінки:
/articles/nextjs
/articles/nextjs?utm_source=google
/articles/nextjs?utm_campaign=summerУ такому випадку для всіх варіантів можна вказати один canonical:
export const metadata: Metadata = {
alternates: {
canonical: "/articles/nextjs",
},
};Параметри відстеження зазвичай не повинні входити до канонічної адреси:
utm_source;
utm_medium;
utm_campaign;
інші параметри аналітики.
Для сторінок із фільтрами рішення залежить від того, чи є результат фільтра окремою SEO-сторінкою.
Якщо фільтр лише змінює відображення списку, можна залишити canonical без query-параметрів:
/catalog?color=redКанонічна адреса:
/catalogЯкщо ж сторінка фільтра має власний унікальний контент, заголовок і повинна індексуватися окремо, їй може знадобитися власна канонічна адреса:
/catalog/red-productsГоловне правило: canonical має відповідати сторінці, яку ви вважаєте основною, а не автоматично видаляти всі параметри.
У більшості випадків сторінка повинна мати canonical на саму себе:
Поточний URL: https://example.com/articles/nextjs
Canonical: https://example.com/articles/nextjsЦе називається самоканонічною адресою. Вона явно показує пошуковій системі, який URL є основним, навіть якщо сторінка доступна через додаткові параметри.
Канонічний URL повинен:
Бути абсолютною адресою після обробки metadataBase.
Вести на сторінку, яка повертає успішну відповідь.
Вести на сторінку з тим самим або майже тим самим контентом.
Не містити зайвих параметрів.
Використовувати узгоджені протокол і домен.
Відповідати фактичній структурі URL сайту.
Наприклад, якщо сайт використовує HTTPS, canonical не повинен вести на HTTP:
Неправильно: https://example.com/articles/nextjs
Правильно: https://example.com/articles/nextjsУ production canonical також не повинен випадково посилатися на localhost.
Для сайту потрібно послідовно використовувати один формат:
/articles/nextjsабо:
/articles/nextjs/Не варто допускати, щоб обидві адреси вважалися рівнозначними без чіткої стратегії. Якщо застосунок використовує один формат, canonical має відповідати йому.
Налаштування trailingSlash у next.config.js впливає на формат URL:
/** @type {import('next').NextConfig} */
const nextConfig = {
trailingSlash: true,
};
module.exports = nextConfig;Після цього маршрути матимуть формат зі слешем наприкінці. Значення canonical має відповідати налаштуванню застосунку.
Після запуску застосунку відкрийте сторінку в браузері та перегляньте HTML-документ. У ньому має бути один потрібний елемент:
<link rel="canonical" href="https://example.com/articles/nextjs">Також перевірте:
чи правильний домен;
чи використовується HTTPS;
чи немає localhost у production;
чи не залишилися query-параметри відстеження;
чи canonical веде на доступну сторінку;
чи не створюється кілька canonical-елементів.
metadataBaseТакий код:
export const metadata = {
alternates: {
canonical: "/about",
},
};може бути коректним лише за умови, що metadataBase задано в батьківському layout. Без нього Next.js не матиме надійної базової адреси сайту.
Не слід вказувати один canonical для сторінок, які мають суттєво різний зміст. Canonical не призначений для об’єднання будь-яких сторінок.
Canonical має вести безпосередньо на фінальну сторінку, а не на URL, який перенаправляє на інший URL.
Якщо однакові сторінки доступні через різні query-параметри, але кожна вказує себе як canonical, дублювання не буде чітко об’єднано.
Жорстко заданий локальний домен:
metadataBase: new URL("http://localhost:3000")призведе до неправильних canonical-адрес у production. Для домену краще використовувати змінну середовища.
На сторінці має бути одна канонічна адреса. Не потрібно одночасно додавати її через Metadata API та вручну через інший механізм, якщо це створює два <link rel="canonical">.
Canonical URL визначає основну адресу сторінки серед кількох варіантів.
У Next.js App Router для цього використовується alternates.canonical.
Для повних URL потрібно налаштувати metadataBase.
Для динамічних маршрутів canonical генерується через generateMetadata.
Параметри аналітики зазвичай не повинні входити до canonical.
Canonical має вести на доступну сторінку з тим самим контентом.
У production потрібно використовувати правильний HTTPS-домен і узгоджений формат URL.