SEO 실수에 관한 SEO 글 — 가장 부끄러운 종류입니다.
함정
App Router에서 metadata는 계단식으로 상속됩니다. 루트 layout.tsx에 이렇게 두면:
export const metadata = {
alternates: { canonical: "/" },
};…오버라이드하지 않은 모든 페이지가 canonical: "/"를 상속합니다. 즉 상세 페이지도, 카테고리 페이지도, 전부 구글에 "내 정본은 홈페이지"라고 조용히 말합니다. 모두를 /의 중복으로 취급하라는 지시 — 실제 콘텐츠가 색인에서 빠지는 지름길입니다.
앱 5개에 이게 박혀 있는 걸 뒤늦게 봤습니다. 페이지는 멀쩡했고, canonical 태그가 그것들을 버리고 있었습니다.
해결
canonical은 페이지별입니다. 각 라우트가 자기 것을 소유:
// 통짜 layout 기본값이 아니라 각 page/route에서
export const metadata = {
alternates: { canonical: absoluteUrl(thisPagePath) },
};루트 layout에 통짜 canonical을 두지 마세요. 기본값을 원하면 현재 경로에서 도출하되, /를 하드코딩하지 마세요.
솔직한 부분
canonical이 지뢰인 이유는 정확히 아무것도 안 깨지기 때문입니다. 사이트는 빌드되고, 렌더되고, 완벽해 보입니다. 유일한 증상은 몇 주 뒤에도 오지 않는 검색 유입이고, 브라우저에선 안 보입니다. 이제 뭘 만들든 페이지별 canonical은 "컴파일되나" 옆의 체크리스트입니다 — "렌더된다"와 "검색이 색인한다"는 다른 주장이고, dev에 뜨는 건 그중 하나뿐이니까요.