canonical 태그 설정법: 중복 URL이 색인을 나눌 때
같은 내용이 여러 URL로 열릴 때 검색엔진이 어느 쪽을 색인할지 헷갈립니다. canonical 태그로 대표 URL을 지정하는 방법과 흔한 설정 실수, 리다이렉트와의 차이를 정리했습니다.
한 페이지가 여러 주소로 열리는 일은 생각보다 흔합니다. www가 붙은 주소와 붙지 않은 주소, 끝에 슬래시가 있는 주소와 없는 주소, 광고 추적 파라미터가 달린 주소가 모두 같은 화면을 보여줍니다. 사람에게는 같은 페이지지만 검색엔진에는 서로 다른 URL입니다.
이때 생기는 문제가 색인 분산입니다. 검색엔진이 어느 주소를 대표로 삼을지 스스로 판단하게 되고, 그 과정에서 우리가 원하지 않는 주소가 검색 결과에 노출되거나 페이지 평가가 여러 주소로 쪼개집니다. canonical 태그는 이 상황에서 대표 주소를 직접 지정하는 방법입니다.
중복 URL은 어디서 생기나요
가장 흔한 원인은 프로토콜과 호스트입니다. http와 https, www 유무를 합치면 한 페이지가 최대 네 개의 주소를 갖게 됩니다. 서버에서 한쪽으로 리다이렉트하지 않으면 네 주소가 모두 응답합니다.
두 번째는 URL 파라미터입니다. 광고 유입 추적에 쓰는 utm 파라미터, 목록 페이지의 정렬이나 필터 값, 세션 식별자가 붙으면 그때마다 새로운 URL이 만들어집니다. 내용은 같은데 주소만 수십 개로 늘어나는 경우가 여기서 나옵니다.
세 번째는 사이트 구조입니다. 같은 상품이 여러 카테고리 경로로 접근되거나, 인쇄용 페이지와 일반 페이지가 따로 있거나, 페이지네이션의 첫 페이지가 목록 주소와 별도로 존재하는 경우입니다. 블로그에서는 태그 페이지와 카테고리 페이지가 거의 같은 글 목록을 보여주기도 합니다.
마지막으로 대소문자와 슬래시입니다. 서버 설정에 따라 대문자가 섞인 주소와 소문자 주소가 각각 응답하고, 끝의 슬래시 유무도 다른 URL로 취급됩니다. 이 부분은 눈에 잘 띄지 않아 오래 방치되기 쉽습니다.
canonical 태그를 넣는 방법
가장 일반적인 방법은 HTML head 안에 link 요소를 넣는 것입니다. rel 속성을 canonical로 지정하고 href에 대표 주소를 적습니다. 이때 반드시 프로토콜과 도메인을 포함한 절대 주소를 써야 합니다. 상대 경로를 쓰면 의도와 다르게 해석될 수 있습니다.
각 페이지는 자기 자신을 가리키는 canonical을 갖는 것이 기본입니다. 중복이 없는 페이지라도 자기 참조 canonical을 넣어 두면 나중에 파라미터가 붙은 주소로 접근되었을 때 자동으로 정리됩니다. Next.js라면 메타데이터의 alternates 항목에 지정하고, 워드프레스는 대부분의 SEO 플러그인이 자동으로 처리합니다.
HTML을 다룰 수 없는 파일, 예를 들어 PDF 같은 문서는 HTTP 응답 헤더에 Link 항목으로 canonical을 지정할 수 있습니다. 사이트맵에 넣는 URL도 canonical과 일치시키는 것이 좋습니다. 사이트맵은 대표 주소를 알리는 보조 신호로 쓰입니다.
자주 나오는 설정 실수
첫째는 모든 페이지가 홈페이지를 가리키는 경우입니다. 템플릿에 canonical을 넣으면서 값을 고정해 버리면 사이트의 모든 페이지가 홈을 대표 주소로 선언하게 됩니다. 이러면 나머지 페이지가 색인에서 사라질 수 있습니다. 배포 후 서너 개 페이지의 소스를 열어 각각 다른 주소가 들어갔는지 확인해야 합니다.
둘째는 canonical이 가리키는 주소가 실제로 열리지 않는 경우입니다. 리다이렉트되거나 404가 나거나 noindex가 걸린 주소를 대표로 지정하면 검색엔진이 신호를 무시합니다. 지정한 주소는 200으로 응답하고 색인 가능한 상태여야 합니다.
셋째는 페이지네이션에 잘못 쓰는 경우입니다. 목록 2페이지가 1페이지를 canonical로 지정하면 2페이지 이후의 콘텐츠가 색인되지 않습니다. 페이지네이션은 각 페이지가 자기 자신을 가리키게 두는 것이 맞습니다.
넷째는 canonical과 리다이렉트를 함께 거는 경우입니다. A가 B로 리다이렉트되는데 A에 canonical까지 넣을 필요는 없습니다. 리다이렉트가 이미 더 강한 신호이므로 중복 설정은 혼란만 만듭니다.
canonical과 리다이렉트, noindex의 차이
301 리다이렉트는 주소를 완전히 옮길 때 씁니다. 사용자와 검색엔진 모두 새 주소로 이동하고 기존 주소는 더 이상 열리지 않습니다. 주소 체계를 바꾸거나 도메인을 이전할 때 쓰는 방법입니다.
canonical은 두 주소가 모두 열려야 할 때 씁니다. 예를 들어 파라미터가 붙은 주소는 광고 추적을 위해 실제로 동작해야 하므로 리다이렉트할 수 없습니다. 이때 canonical로 대표를 지정하면 사용자는 파라미터 주소로 들어오고 색인은 대표 주소로 모입니다.
noindex는 아예 검색 결과에서 빼고 싶을 때 씁니다. 로그인 화면이나 장바구니, 내부 검색 결과 페이지가 대상입니다. 다만 canonical과 noindex를 같은 페이지에 함께 넣으면 신호가 충돌하므로 둘 중 하나만 써야 합니다.
선택 기준은 단순합니다. 그 주소가 계속 열려야 하면 canonical, 열릴 필요가 없으면 리다이렉트, 열리되 검색에는 안 나와야 하면 noindex입니다.
중복 URL을 정리하는 순서
먼저 한 페이지가 몇 가지 주소로 열리는지 직접 확인합니다. http와 https, www 유무, 끝 슬래시 유무를 하나씩 브라우저에 넣어 보고 모두 200으로 응답하는지 봅니다. 여러 개가 열린다면 서버에서 한쪽으로 리다이렉트하는 것이 먼저입니다.
서버 리다이렉트로 프로토콜과 호스트를 하나로 통일합니다. 이 작업만으로 중복의 상당 부분이 정리됩니다. canonical은 그다음 단계입니다.
모든 페이지에 자기 자신을 가리키는 절대 주소 canonical을 넣습니다. 템플릿에 고정값이 들어가지 않도록 페이지별로 동적으로 생성해야 합니다.
파라미터가 붙는 페이지는 파라미터를 제거한 주소를 canonical로 지정합니다. 다만 파라미터에 따라 내용이 실제로 달라지는 경우, 예를 들어 검색 결과나 필터가 적용된 목록은 각각 다른 페이지이므로 묶으면 안 됩니다.
배포 후 서치콘솔의 URL 검사에서 사용자가 선언한 표준 URL과 구글이 선택한 표준 URL이 일치하는지 확인합니다. 다르다면 우리 신호가 무시되고 있다는 뜻이므로 원인을 찾아야 합니다.
자주 묻는 질문
canonical을 넣으면 반드시 그 주소가 색인되나요?
보장되지는 않습니다. canonical은 지시가 아니라 힌트로 취급됩니다. 검색엔진은 내부 링크, 사이트맵, 리다이렉트, 콘텐츠 유사도를 함께 보고 대표 주소를 판단하며, 우리 선언과 다른 결론을 내릴 수도 있습니다. 신호를 일치시킬수록 반영 가능성이 높아지므로 내부 링크도 canonical과 같은 주소를 쓰는 것이 좋습니다.
다른 사이트에 실린 우리 글에도 canonical을 쓸 수 있나요?
가능합니다. 언론사나 파트너 사이트에 같은 글을 싣는 경우, 그쪽 페이지에서 우리 원문을 canonical로 지정하면 원문 쪽으로 평가를 모을 수 있습니다. 다만 상대 사이트가 협조해야 하고, 실제 반영 여부는 검색엔진 판단에 달려 있습니다. 신디케이션 계약을 맺을 때 이 조건을 넣어 두면 좋습니다.
네이버도 canonical 태그를 인식하나요?
인식합니다. 네이버 서치어드바이저 문서도 중복 문서 처리를 위해 canonical 사용을 권장하고 있습니다. 다만 검색엔진마다 신호를 다루는 비중이 다르므로, 어느 쪽이든 확실히 하려면 서버 리다이렉트로 주소를 통일하는 것이 가장 안전합니다.
실행 체크리스트
- http와 https, www 유무, 끝 슬래시 조합이 모두 열리는지 확인합니다.
- 서버 리다이렉트로 프로토콜과 호스트를 한쪽으로 통일합니다.
- 모든 페이지에 자기 자신을 가리키는 절대 주소 canonical을 넣습니다.
- canonical 대상이 200으로 응답하고 noindex가 아닌지 확인합니다.
- 서치콘솔에서 선언한 표준과 선택된 표준이 같은지 점검합니다.
정리
중복 URL은 새 콘텐츠를 만드는 일보다 눈에 덜 띄지만, 방치하면 애써 쓴 페이지의 평가가 여러 주소로 흩어집니다. 특히 광고를 집행하면서 추적 파라미터가 붙기 시작하면 문제가 빠르게 커집니다.
정리 순서는 서버 리다이렉트로 주소 체계를 통일하고, 남는 중복을 canonical로 지정하고, 검색에서 빼야 할 페이지만 noindex로 처리하는 것입니다. 세 가지를 구분해서 쓰면 대부분의 중복 문제는 해결됩니다.