Next.js
검색 결과의 제목이 매번 달라질 때 canonical과 메타데이터를 고친 튜토리얼
쿼리스트링이 붙은 같은 페이지가 검색에 섞였을 때 Next.js metadata로 canonical을 지정한 짧은 튜토리얼.
같은 글인데 주소가 여러 개였다
공유 링크에 ?ref=twitter가 붙은 글과 원래 글이 검색 결과에 함께 보였다. 내용은 같았지만 제목 뒤에 사이트 이름이 덧붙는 방식도 제각각이었다. Search Console에서 색인 주소를 확인한 뒤, 페이지마다 기준 URL을 명시하기로 했다.
App Router에 기준 주소를 설정한다
metadataBase를 한 곳에서 정하고 각 글 페이지에는 실제 slug로 canonical을 만든다. 로컬 주소를 그대로 배포하지 않도록 환경 변수도 함께 점검했다.
// app/layout.tsx
export const metadata = {
metadataBase: new URL('https://blog.example.com'),
};
// app/posts/[slug]/page.tsx
export async function generateMetadata({ params }: Props) {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
alternates: { canonical: `/posts/${post.slug}` },
};
}
브라우저 화면만 보지 않고 소스를 봤다
처음에는 개발 서버의 Elements 탭만 확인했다. 배포 뒤에는 실제 HTML 응답에서 <link rel="canonical">가 하나인지 확인하는 편이 정확했다.
curl -sL https://blog.example.com/posts/hello?ref=newsletter | rg -o '<link[^>]+rel="canonical"[^>]*>'
목록, 글 상세, 태그 페이지에 모두 같은 규칙을 기계적으로 적용하면 안 된다. 페이지네이션과 필터 결과는 독립 페이지로 남겨야 할 수도 있다. 기준 URL은 '중복을 숨기는 버튼'이 아니라 대표 문서를 알려 주는 신호다.
마무리: 배포 전 세 가지만 확인
- title과 description이 글의 실제 내용과 맞는가
- canonical이 절대 기준으로 하나만 출력되는가
- Open Graph URL도 같은 대표 주소를 가리키는가
작은 메타데이터 수정이지만, 링크를 배포할 때마다 주소 규칙을 고민하지 않게 됐다.