hreflang 구현 방법: 단계별 안내
HTML head 태그, HTTP Link 헤더와 XML 사이트맵 주석의 세 hreflang 방식 모두를 위한 코드, 문법 규칙, 대규모 CMS 자동화와 실제로 올바르게 배포되었는지 확인하는 검증 절차입니다.
이 페이지의 근거 신호 1개
- 관련 라이브 도구 returntag - hreflang checker
hreflang 추가 방법은 정확히 세 가지입니다. head의 HTML link 태그, PDF 같은 비HTML 파일용 HTTP Link 응답 헤더, 대규모에 가장 좋은 XML 사이트맵의 xhtml:link 항목입니다. 하나를 선택하세요. Google은 동등하게 취급하며 결합해도 이점이 없습니다. 모두 자기 참조(각 페이지가 자신을 나열)와 상호 참조(A가 B를 가리키면 B도 A를 가리켜야 하며 아니면 그 쌍이 무시됨)의 두 규칙을 따릅니다. 코드는 ISO 639-1 언어에 선택적인 ISO 3166-1 alpha-2 지역을 더하며 x-default는 대체 경로입니다. 하나의 기준 데이터에서 생성하고 소스 보기만이 아닌 렌더링된 head를 검증하세요. 제 374,756개 도메인 연구에서 hreflang 설정의 67% 이상에 문제가 하나 이상 있었습니다.
TL;DR — hreflang을 추가하는 방법은 세 가지입니다. 페이지
<head>의 작은<link>태그, 서버가 보내는Link:헤더, XML 사이트맵 항목입니다. 하나만 선택하세요. 어떤 방식이든 두 규칙은 같습니다. 모든 페이지가 자신을 나열하고 참조한 모든 페이지가 돌아오는 링크를 제공해야 하며, 그렇지 않으면 Google은 전체 묶음을 무시합니다. 그런 다음 의도한 대로 페이지에 태그가 실제로 나타나는지 확인합니다.
시작점: hreflang이 필요하다는 판단은 이미 끝났습니다
이 글은 구현법입니다. hreflang이 필요한지 또는 무엇을 하는지 아직 확실하지 않다면 hreflang 개요부터 읽으세요. 여기서는 한 페이지에 여러 언어 또는 국가 버전이 있다는 것을 알고 올바르게 구현하려는 상황을 전제합니다.
추가하는 세 방법: 하나를 선택하세요
<head>안의 HTML<link>태그. 각 페이지 HTML 상단에 몇 줄을 추가합니다. 이해하고 확인하기 가장 쉬우며 작은 사이트에 좋습니다.- HTTP
Link:헤더. 같은 정보를 HTML 대신 서버 응답으로 보냅니다. 태그를 넣을<head>가 없는 PDF 같은 비HTML 파일에는 유일한 선택지입니다. - XML 사이트맵. 각 페이지 대신 사이트맵 파일에 모든 언어 버전을 나열합니다. 페이지마다 수정할 필요 없이 전체 관계가 한곳에 있으므로 큰 사이트에 적합합니다.
Google은 세 방식을 동등하게 취급합니다. 더 “빠르거나” “강한” 방식은 없으며 동시에 여러 방식을 쓸 이점도 없습니다. 서로 달라질 수 있는 지점만 늘어납니다.
이 주장에 대한 근거 Google supports equivalent HTML, HTTP-header, and sitemap methods for declaring localized versions; HTTP headers can be used for non-HTML files such as PDFs. 범위: Google Search hreflang implementation methods. 신뢰도: 높음 · 검증일: Google: Localized versionsHTML 방식의 모습
미국 영어, 영국 영어, 독일어 페이지와 사용자가 선택할 수 있는 글로벌 홈페이지가 있다고 합시다. 미국 영어 페이지에는 다음을 넣습니다.
<link rel="alternate" hreflang="en-us" href="https://example.com/us/" />
<link rel="alternate" hreflang="en-gb" href="https://example.com/uk/" />
<link rel="alternate" hreflang="de" href="https://example.com/de/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/" />각 줄은 “이 페이지의 대체 버전이 있고, 이 언어/지역을 위한 것이며, 이 주소에 있다”고 읽으면 됩니다. x-default 줄은 다른 언어와 맞지 않는 사용자를 위한 대체 경로입니다.
hreflang을 작동시키는 두 규칙이므로 다음 두 가지에 주목하세요.
- 미국 페이지가 자신을 나열합니다. 첫 번째
en-us줄은 현재 보고 있는 미국 페이지를 가리킵니다. - 묶음의 다른 모든 페이지에도 돌아오는 링크를 포함한 같은 블록이 있어야 합니다. 영국, 독일어와 홈페이지 모두 이 네 줄을 각각 갖춰야 합니다.
쉽게 설명한 두 규칙
- 모든 페이지가 돌아오는 링크를 제공합니다. 미국 페이지가 독일어 페이지에 링크하면 독일어도 미국 페이지에 링크해야 합니다. 반환 링크가 없으면 Google은 그 쌍을 제외합니다. 사람들이 가장 많이 어기는 규칙입니다.
- 모든 페이지가 자신을 가리킵니다. 각 버전은 묶음에 자신의 URL을 나열합니다. Google은 선택 사항이지만 좋은 관행이라고 합니다. 일관성을 유지하므로 해 두세요.
실제의 완전한 웹 주소 사용
항상 https://로 시작하는 전체 주소를 사용하세요. /us/나 //example.com/us/가 아니라 https://example.com/us/ 전체입니다. Google이 실제 색인하는 정확한 주소와도 같아야 합니다. 프로토콜, www 유무, 끝 슬래시와 대소문자까지 일치해야 합니다.
코드를 정확히 사용하세요
코드는 두 글자 언어이며 선택적으로 하이픈과 두 글자 국가를 붙입니다. en, en-us, de, es-mx가 예입니다. 흔한 실수는 en-uk(올바른 값은 en-gb이며 uk는 실제로 우크라이나어)와 일본어에 jp(올바른 값은 ja)를 쓰는 것입니다.
제대로 적용되었는지 확인하세요
초보자가 놓치는 가장 중요한 점은 배포 후 렌더링된 페이지를 실제로 봐야 한다는 것입니다. 태그가 있으며 <head> 안에 있는지 확인하세요. JavaScript로 추가하면 “페이지 소스 보기”에는 없지만 실제 페이지에는 있을 수 있습니다. Google Search Console의 URL 검사로 Google이 실제로 렌더링한 내용을 볼 수 있습니다.
헤더와 사이트맵 방식의 전체 코드, CMS 전체 자동화, 정확한 검증 단계와 클러스터를 조용히 깨뜨리는 실수까지 보려면 고급 탭으로 전환하세요.
TL;DR — 세 방식 중 하나를 고르세요.
<head>의 HTML<link>태그, PDF 같은 비HTML 파일의 유일한 선택지인 HTTPLink:헤더, 또는 XML 사이트맵의<xhtml:link>항목입니다. 자동 생성 파일 하나로 QA하기 쉬운 사이트맵이 대규모에 가장 좋습니다. Google은 세 방식이 동등하고 결합해도 이점이 없다고 합니다. 모두 자기 참조 + 상호 참조, 절대 URL, ISO 639-1 언어 + 선택적 ISO 3166-1 alpha-2 지역 코드를 따릅니다. 수동 hreflang은 시간이 지나면 어긋나므로 하나의 기준 데이터에서 전체를 생성하세요. 이후 렌더링된 head를 검증하고 전체 클러스터의 상호 참조를 크롤링하며 URL이 바뀔 때마다 재검사하세요. 지역에 따라 크롤러를 자동 리디렉션하지 마세요.
코드를 쓰기 전 결정할 세 가지
1. 구현 방식. Google은 성능이 아닌 편의의 선택이라고 명시합니다. “The three methods are equivalent from Google’s perspective and you can choose the method that’s the most convenient for your site.” (번역) 「Google 관점에서 세 방식은 동등하므로 사이트에 가장 편리한 방식을 선택할 수 있습니다.」 제 대략적인 기준은 다음과 같습니다.
이 주장에 대한 근거 Google supports equivalent HTML, HTTP-header, and sitemap methods for declaring localized versions; HTTP headers can be used for non-HTML files such as PDFs. 범위: Google Search hreflang implementation methods. 신뢰도: 높음 · 검증일: Google: Localized versions- URL이 적고 정적이거나 단순한 사이트이며 로케일이 적음 → HTML
<link>태그. - 비HTML 자산(PDF, 문서) → HTTP
Link:헤더. PDF에는<head>가 없으므로 다른 선택지가 없습니다. - 로케일이 많거나 사이트맵 파이프라인이 이미 있거나 headless/JAMstack 구성 → 프로그래밍 방식으로 생성하는 XML 사이트맵.
의사결정 트리 탭에서 이를 실제 흐름도로 살펴봅니다.
2. 하나의 기준 데이터. 어떤 방식이든 주석은 한곳에서 생성해야 합니다. 데이터베이스의 로케일/번역 테이블, CMS 관계 필드, 작은 사이트라면 스프레드시트 하나입니다. 최악의 방식은 페이지별로 태그를 수동 유지하는 것입니다. 한 로케일의 템플릿이 달라지는 순간 반환 링크가 빠지고 쌍이 제외됩니다.
3. 방식을 결합하지 마세요. 세 방식 모두 실행할 수는 있습니다. 하지만 Google은 이점이 없다고 하며 방식이 늘 때마다 세 사본이 서로 불일치할 지점도 늘어납니다.
이 주장에 대한 근거 Google requires fully qualified alternate URLs and reciprocal links, and recommends including each page itself in its alternate set. 범위: Google Search hreflang rules shared by all delivery methods. 신뢰도: 높음 · 검증일: Google: Hreflang guidelines방법 1 — <head> 안의 HTML <link> 태그
Google에 나온 그대로의 문법은 다음과 같습니다.
<link rel="alternate" hreflang="lang_code" href="url_of_page" />대체 경로가 있는 다언어·다지역 클러스터의 완전한 예입니다.
<link rel="alternate" hreflang="en-us" href="https://example.com/us/" />
<link rel="alternate" hreflang="en-gb" href="https://example.com/uk/" />
<link rel="alternate" hreflang="de" href="https://example.com/de/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/" />그 블록을 클러스터의 모든 페이지, 즉 미국·영국·독일어·홈페이지에 그대로 넣습니다. 각 페이지가 자신의 자기 참조 줄을 포함하며 이것이 상호 참조를 충족합니다.
배치 위치는 엄격한 규칙입니다. Google은 “The <link> tags must be inside a
well-formed <head> section of the HTML.” (번역) 「<link> 태그는 올바르게 구성된 HTML <head> 안에 있어야 합니다.」라고 합니다. 문제 해결 조언도 “If in doubt, paste code from your rendered page into an HTML validator to ensure
that the links are inside the <head> element.” (번역) 「확실하지 않다면 렌더링된 페이지의 코드를 HTML 검증기에 붙여 넣어 링크가 <head> 요소 안에 있는지 확인하세요.」입니다.
대부분의 가이드가 빠뜨리는 실패 유형 때문에 생각보다 중요합니다. hreflang 태그가 <head>에서 밀려나 <body> 안에 들어가면 유효하지 않습니다. 저는 Pubcon Vegas 2019 발표 에서 이를 직접 지적했습니다. 태그가 body에 유효하게 존재할 수 있다면 다른 사이트의 대체 버전을 탈취할 수 있습니다. 잘못되거나 삽입된 <p> 태그 또는 iframe이 <head>를 조기에 닫으면 이후 hreflang을 포함한 모든 내용이 <body> 안에 렌더링됩니다. 소스에는 태그가 있지만 조용히 무효화됩니다. 가장 빠른 디버깅은 브라우저 DOM 중단점입니다. 렌더링된 DOM에서 태그가 실제 어디에 놓이는지 보고 <head>를 깨뜨린 마크업을 역추적하세요.
HTML 태그가 적합한 경우는 로케일 수를 관리할 수 있고 페이지별 <link> 블록이 커지지 않는 중소 사이트입니다. 로케일이 수십 개면 모든 페이지에 큰 마크업 블록이 붙습니다. 대형 사이트가 사이트맵 방식을 선호하는 이유 중 하나입니다.
같은 <link> 요소에서 hreflang과 다른 alternate 속성을 혼용하지 마세요. Google 지침은 hreflang을 담은 <link rel="alternate">에 media처럼 무관한 대체 속성을 같이 넣지 말라고 명시합니다. 같은 URL에 언어/지역 대체 버전과 미디어 쿼리 대체 버전이 모두 필요하다면 하나로 결합하지 말고 별도의 <link> 요소 두 개를 사용하세요. 섞으면 Google이 어느 쪽으로도 파싱하지 못하는 태그가 되기 쉽습니다.
방법 2 — HTTP Link: 헤더
같은 정보를 HTML 대신 HTTP 응답으로 보냅니다. 문법은 다음과 같습니다.
Link: <https://example.com/file.pdf>; rel="alternate"; hreflang="en",
<https://de-ch.example.com/file.pdf>; rel="alternate"; hreflang="de-ch"각 URL의 꺾쇠 괄호, 세미콜론으로 구분된 속성, 대체 버전 사이의 쉼표에 주의하세요. 헤더의 모든 URL은 쉼표로 이어 붙입니다.
필요한 경우: 비HTML 리소스입니다. PDF, .doc, 직접 제공하는 이미지에는 <link> 태그를 담을 <head>가 없으므로 hreflang을 붙이는 유일한 방법은 헤더입니다.
설정 시 고려 사항: 헤더는 서버/CDN 계층에서 설정합니다. Apache Header 지시어, Nginx add_header, Cloudflare/Fastly/CloudFront 응답 헤더 규칙 또는 애플리케이션 응답입니다. 문서별 마크업이 아닌 인프라에서 설정하므로 상호 참조가 깨지기 쉽습니다. 영어 PDF와 독일어 PDF 헤더는 보통 별도로 설정하므로 각각 자신을 포함한 전체를 나열하는지 직접 확인해야 합니다. HTML/사이트맵 방식과 같은 로케일 테이블에서 헤더를 생성하세요.
유지할 불변 조건: 모든 대체 버전 응답은 매번 동일한 전체 집합을 담아야 합니다. 영어 PDF 헤더가 독일어 버전을 나열하는 것만으로는 부족합니다. 독일어 PDF 응답도 자신과 다른 모든 대체 버전의 정확히 같은 집합을 반환해야 합니다. 크롤러가 처음 접하는 응답만이 아니라 매번 그래야 합니다. 헤더는 한 번 설정하고 잊는 것이 아니라 생성 산출물로 취급하세요.
방법 3 — XML 사이트맵 <xhtml:link> 주석
대규모에서는 보통 올바른 선택입니다. 클러스터 전체가 자동 생성 파일 하나 또는 몇 개에 있고 각 페이지의 <head>를 부풀리지 않습니다. 관계 그래프 전체가 한곳에 있으므로 QA하기도 가장 쉽습니다. 문법은 다음과 같습니다.
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://www.example.com/english/page.html</loc>
<xhtml:link rel="alternate" hreflang="de"
href="https://www.example.de/deutsch/page.html"/>
<xhtml:link rel="alternate" hreflang="en"
href="https://www.example.com/english/page.html"/>
</url>
<url>
<loc>https://www.example.de/deutsch/page.html</loc>
<xhtml:link rel="alternate" hreflang="de"
href="https://www.example.de/deutsch/page.html"/>
<xhtml:link rel="alternate" hreflang="en"
href="https://www.example.com/english/page.html"/>
</url>
</urlset>사이트맵 방식에서 실수하는 두 가지:
- 네임스페이스 선언은 필수입니다.
<urlset>의xmlns:xhtml="http://www.w3.org/1999/xhtml"은 선택적인 장식이 아닙니다. 빠지면 파일의 모든<xhtml:link>가 유효하지 않습니다. - 각
<url>블록은 완결되어야 합니다. 위의 두<url>블록 모두 자신의<loc>를 포함해 두 대체 버전을 나열합니다. 각 항목은 자기 참조와 모든 대체 버전의 전체 집합을 담습니다. 사이트맵의 상호 참조는 “각 URL 블록이 자신을 포함한 클러스터의 모든 URL을 나열한다”는 뜻입니다.
생성기를 과하게 설계하지 않도록 두 동작을 알아 두세요. <url> 안의 <xhtml:link> 자식 요소 순서는 Google에 중요하지 않으므로 정렬에 시간을 낭비하지 마세요. 또 이 주석들은 독립된 <url> 항목이 아니라 자식이므로 파일당 50,000개 URL 제한에 포함되지 않습니다.
프로그래밍 방식의 생성. 사이트맵 방식의 핵심은 CMS 번역 데이터의 부산물이라는 점입니다. CMS가 /english/page.html과 /deutsch/page.html의 번역 관계를 안다면 생성기가 그 관계 테이블을 순회해 빌드 또는 사이트맵 요청 시 <xhtml:link> 블록을 출력해야 합니다. 매번 기준 데이터에서 재생성하므로 hreflang이 실제 상황과 어긋날 수 없고, 로케일 추가도 수백 페이지의 수작업이 아닌 데이터 변경이 됩니다.
개발 인력이 없는 팀을 위해 제 Ahrefs hreflang 가이드에 간단한 Google Sheets 템플릿 을 만들었습니다. Setup 탭에서 기본 언어와 최대 네 변형을 선택하고, URLs 탭의 열에 각 언어 URL을 붙여 넣으면 Results 탭이 사이트맵 XML 블록을 자동 생성합니다. 실제 CMS 통합이 과한 작은 사이트를 위한 하나의 기준 데이터 원칙의 구체적 구현입니다.
어떤 방식이든 적용되는 규칙
방식과 무관하며 타협할 수 없는 규칙입니다.
- 자기 참조. 모든 페이지,
<url>블록 또는 헤더는 자신을 나열합니다. Mueller는 선택적이지만 좋은 관행이라고 설명합니다. 제 연구에서는 18.0%가 빠뜨렸지만 자동화하면 비용이 들지 않습니다. - 상호 참조. “Each language version must list itself as well as all other language versions.” (번역) 「각 언어 버전은 자신과 다른 모든 언어 버전을 나열해야 합니다.」 적용 규칙은 “If two pages don’t both point to each other, the tags will be ignored. This is so that someone on another site can’t arbitrarily create a tag naming itself as an alternative version of one of your pages.” (번역) 「두 페이지가 서로를 가리키지 않으면 태그는 무시됩니다. 다른 사이트의 누군가가 임의로 자신을 여러분 페이지의 대체 버전으로 지정하지 못하게 하기 위해서입니다.」 반환 링크 하나가 없으면 그 쌍이 제외됩니다.
- 완전한 절대 URL. “Alternate URLs must be fully-qualified,
including the transport method (http/https)” (번역) 「대체 URL은 전송 방식(http/https)을 포함한 완전한 형식이어야 합니다.」 따라서
https://example.com/foo이며//example.com/foo나/foo가 아닙니다. Google이 색인하는 정확한 형식과 프로토콜·www·끝 슬래시·대소문자가 모두 맞아야 반환 링크가 일치합니다.
정확한 코드 사용
“The first code of the hreflang attribute is the language code (in ISO 639-1
format) followed by an optional second code that represents the region code (in ISO
3166-1 Alpha 2 format).” (번역) 「hreflang 속성의 첫 코드는 ISO 639-1 언어 코드이며, 선택적인 두 번째 코드는 ISO 3166-1 Alpha 2 지역 코드입니다.」 en-US처럼 하이픈으로 결합합니다. 언어만 타기팅할 수는 있지만(es = 전 세계 스페인어) 지역만 타기팅할 수는 없습니다. 항상 언어가 먼저입니다.
제가 가장 자주 보고 연구 데이터에서도 발견한 실수는 다음과 같습니다.
en-GB대신en-UK—uk는 우크라이나어이고 영국 지역 코드는gb입니다.- 일본어
ja대신jp, 중국어zh대신cn. - 두 글자 ISO 639-1이 필요한 곳에 세 글자 코드(
ger,eng) 사용. EU,UN,UK를 지역 코드로 사용 — 유효한 ISO 3166-1 alpha-2 대상이 아닙니다.
**x-default**는 명시된 어느 로케일에도 맞지 않는 사용자를 위한 대체 경로의 예약 값입니다. 언어 선택기나 자동 리디렉션 홈페이지가 그 예입니다.
<link rel="alternate" href="https://example.com/" hreflang="x-default" />필수는 아닙니다. 제 연구에서 56.3%가 빠뜨린 가장 흔한 누락 항목이지만 x-default 누락은 상호 태그 누락처럼 클러스터를 깨뜨리지 않습니다. 일치하지 않는 사용자에게 Google이 자체 언어/지역 감지를 사용합니다. 그래도 추가하세요. 클러스터를 깨뜨리는 요소가 아닌 점검 항목입니다. 이 클러스터에는 별도의 x-default 세부 주제가 있습니다.
대규모 구현: CMS와 플랫폼 접근법
WordPress. Yoast SEO는 단독으로 hreflang을 생성하지 않습니다. 실제 태그 출력에는 WPML이나 Polylang 같은 다국어 플러그인이 필요합니다. WPML은 번역이 있는 모든 페이지의 hreflang을 자동 생성하고 기본 언어 버전의 x-default를 추가하며 기본적으로 XML 사이트맵에 주석을 삽입합니다. 사이트맵 대신 또는 추가로 head 태그를 출력하려면 WPML → Languages → SEO Options의 “Display alternative languages in the HEAD section” (번역) 「HEAD 섹션에 대체 언어 표시」 설정을 사용합니다. WPML의 Yoast 연동 문서 를 보세요.
Shopify. Shopify Markets는 시장/언어를 설정하고 콘텐츠를 게시해 탐색 메뉴에 연결하면 상호 hreflang 태그를 자동 생성합니다. 설계상 가장 흔한 반환 링크 누락을 없앱니다. 다만 자동 태그는 fr-FR, fr-CA 같은 언어·지역이 아니라 fr, de 같은 언어 전용인 경우가 많아 프랑스·캐나다·벨기에의 프랑스어를 구별해야 하는 브랜드에는 부족합니다. 이 경우 theme.liquid의 수동 <link> 태그나 앱을 사용합니다. Shopify의 테마 hreflang 문서 에 패턴이 있습니다. 자동 Markets 태그와 수동/앱 태그의 혼용은 문서화된 충돌 원인이므로 하나만 선택하세요.
맞춤형 / headless / 엔터프라이즈. 위 사이트맵 설명처럼 빌드 또는 응답 시 번역 관계 테이블에서 주석을 생성하세요. 같은 하나의 기준 데이터 원칙입니다. hreflang은 시간이 지나면 어긋나는 수동 산출물이 아니라 CMS에 이미 있는 데이터의 계산 결과가 됩니다.
클러스터를 깨뜨리는 구현 실수
지역/IP 자동 리디렉션. 문법 오류와 별개이며 더 나쁜 실패입니다. 추정 위치에 따라 방문자, 특히 크롤러를 리디렉션하면 Googlebot이 주로 미국에서 크롤링하므로 지역 클러스터 전체가 색인에서 빠질 수 있습니다. 제 Pubcon 발표에서는 “would redirect search engines to where they crawl from. Google for instance mostly crawls from the US so we would effectively de-index all geo pages.” (번역) 「검색엔진을 크롤링 출발지로 리디렉션할 것입니다. Google은 주로 미국에서 크롤링하므로 사실상 모든 지역 페이지의 색인을 제거하게 됩니다.」라고 했습니다. EU의 부당한 지역 차단 금지 규정에 따른 노출 위험이라는 규제 측면도 있습니다. 올바른 패턴은 사용자는 리디렉션하되 크롤러는 하지 않는 것입니다. 사람을 감지해 선택적으로 이동시키되 봇은 모든 URL에 직접 접근하게 하고 실제 연결 신호는 hreflang에 맡깁니다. Google의 다지역 지침 도 이런 이유로 자동 이동보다 방해하지 않는 제안 배너를 권장합니다.
비canonical·리디렉션·noindex URL을 hreflang 대상으로 지정. 로케일 URL이 바뀌어 리디렉션을 걸었는데 hreflang은 이전 주소라면 클러스터가 301 또는 404를 참조하게 됩니다. 제 연구의 16.9%가 깨지거나 리디렉션된 페이지를 참조했습니다. 각 버전은 자신을 canonical로 지정해야 합니다. 다른 곳을 canonical로 지정하거나 noindex인 페이지를 대상으로 하면 반환 링크가 깨집니다. 8.0%는 비canonical URL을 가리켰습니다.
URL 형식 불일치. hreflang URL과 색인된 URL은 끝 슬래시·www·프로토콜·대소문자까지 바이트 단위로 같아야 합니다. 불일치는 조용한 상호 참조 실패입니다.
출시 후 구현 검증
원시 소스만이 아닌 렌더링된 소스를 보세요. 클라이언트 JavaScript로 넣은 hreflang은 curl이나 Ctrl+U(“페이지 소스 보기”)에는 아무것도 없지만 렌더링된 DOM에는 있습니다. GSC URL 검사 → “Test Live
URL” (번역) 「실제 URL 테스트」 → “View Tested Page” (번역) 「테스트된 페이지 보기」 또는 렌더링 크롤러로 확인하세요. 실제로는 정상인데 “태그가 없다”고 생각하거나, 반대로 소스에는 있지만 <body>에 렌더링되어 깨진 것을 놓치는 가장 흔한 이유입니다.
URL 하나만 표본 검사하지 말고 클러스터 전체를 크롤링하세요. 상호 참조는 페이지 간 관계이므로 한 페이지는 거의 아무것도 알려 주지 못합니다. Screaming Frog의 hreflang 감사 나 Ahrefs Site Audit으로 전체를 크롤링해 반환 누락, 비canonical 대상과 깨진 참조를 대규모로 찾으세요. Ahrefs의 Hreflangs 탭은 깨진 링크를 빨갛게 표시하는 클러스터 그래프를 그려 CSV보다 이해하기 쉽습니다.
&hl=와 &gl=로 실제 SERP를 검증하세요. Google 검색 URL에 호스트 언어(&hl=)와 지리 위치(&gl=) 매개변수를 붙여 자신의 위치에서 추측하는 대신 해당 로케일 결과를 미리 보세요.
검증은 일회성 단계가 아닙니다. 새 로케일, URL/리디렉션 변경과 개발·스테이징 설정의 운영 유입이 출시 후 장애의 반복 원인입니다. 출시일 QA뿐 아니라 회귀 테스트와 정기 크롤링에 hreflang 검사를 넣으세요. 제 발표의 표현은 “any number of things can break from masking to things carrying over from dev/test/staging environments.” (번역) 「마스킹부터 개발/테스트/스테이징 환경에서 넘어오는 것까지 수많은 원인으로 문제가 생길 수 있습니다.」입니다.
버려야 할 오해
- “Sitemaps process faster than HTML tags.” (번역) 「사이트맵이 HTML 태그보다 빨리 처리된다.」 틀렸습니다. 둘 다 크롤링 시 처리된다고 제가 직접 반박했습니다. 사이트맵의 이점은 속도가 아닌 관리와 QA입니다.
- “Yandex doesn’t support hreflang in sitemaps.” (번역) 「Yandex는 사이트맵 hreflang을 지원하지 않는다.」 틀렸습니다. Yandex 문서는 지원을 확인합니다.
- “Use all three methods for extra signal.” (번역) 「추가 신호를 위해 세 방식 모두 사용하라.」 Google에 따르면 이점이 없고 불일치 위험만 늘립니다.
- “A missing
x-defaultbreaks the cluster.” (번역) 「x-default누락은 클러스터를 깨뜨린다.」 틀렸습니다. 선택 사항이며 Google은 자체 감지를 사용합니다. - “Wrong hreflang gets you penalized.” (번역) 「잘못된 hreflang은 페널티를 받는다.」 틀렸습니다. 명령이 아닌 힌트입니다. 깨진 hreflang은 페널티가 아니라 무시됩니다.
다음으로 볼 곳
이 글은 hreflang 허브 아래의 상세 구현 가이드입니다. 허브는 개념, 상호 참조의 중요성과 Bing이 대신 하는 일을 다룹니다. x-default는 대체 경로 값을 자세히 설명합니다. 구현의 바탕 전략은 국제 SEO 영역을 보세요. hreflang은 기술 계층이지 진정한 현지화를 대신하지 않습니다.
AI 요약
고급 버전의 핵심을 압축했습니다.
- 세 방식 중 정확히 하나를 선택하세요. Google은 동등하게 취급하며 결합해도 이점이 없습니다.
- HTML
<link>태그를<head>에 사용 — 중소 사이트용입니다. 올바른<head>안에 있어야 하며<body>는 안 됩니다. 같은<link>에hreflang과media같은 다른 대체 속성을 섞지 마세요. - HTTP
Link:헤더 — PDF 같은 비HTML 파일의 유일한 방법입니다. 서버/CDN에서 설정하고 모든 대체 버전 응답이 매번 동일한 전체 집합을 담아야 합니다. - XML 사이트맵
<xhtml:link>— 대규모에 가장 좋습니다.<urlset>에xmlns:xhtml="http://www.w3.org/1999/xhtml"네임스페이스가 필요합니다. 그래프 전체가 한 파일에 있어 QA가 가장 쉽고, 자식 순서는 중요하지 않으며 자식은 사이트맵의 50,000개 URL 제한에 포함되지 않습니다.
- HTML
- 두 공통 규칙: 자기 참조와 상호 참조입니다. A→B이면 B→A가 있어야 하며 아니면 그 쌍이 무시됩니다. 색인된 정확한 형식과 같은 완전한 절대 URL을 사용하세요.
- 코드: ISO 639-1 언어 + 선택적 ISO 3166-1 alpha-2 지역입니다(
en-UK가 아닌en-GB,jp가 아닌ja).x-default는 선택적인 예약 대체 경로이지만 제 연구의 56.3%가 놓친 가장 흔한 누락입니다. - 하나의 기준 데이터로 자동화하세요. WordPress는 WPML/Polylang이 필요하며 Yoast만으로는 안 됩니다. Shopify Markets는 상호 태그를 자동 생성하지만 흔히 언어만 지정합니다. 맞춤형/headless는 번역 테이블에서 출력해야 합니다.
- 지역에 따라 크롤러를 자동 리디렉션하지 마세요. Googlebot은 주로 미국에서 크롤링하므로 지역 클러스터가 색인에서 빠질 수 있습니다. 사용자는 이동시키되 봇은 하지 마세요.
- 렌더링된 head를 검증하세요. JavaScript 태그는 소스 보기에 없을 수 있습니다. 클러스터 전체 상호 참조를 크롤링하고
&hl=/&gl=로 로케일을 검사하며 URL 변경 후마다 재검사하세요.
공식 문서
hreflang 구현을 위한 1차 출처 문서입니다.
- Localized versions of your pages — 페이지의 현지화 버전에 관한 주요 구현 문서입니다. 세 방식의 정확한 문법, 상호 참조, 유효 코드, 절대 URL 규칙과
x-default를 다룹니다. - Managing multi-regional and multilingual sites — 다지역·다국어 사이트의 URL 구조와 자동 리디렉션/클로킹 경고를 다룹니다. 크롤러를 지역별로 이동시키면 안 되는 이유입니다.
- Tell Google about localized versions (x-default blog, 2013) — 2013년
x-default를 처음 소개한 현지화 버전 안내입니다. - International Targeting report deprecation (Sept 2022) — 2022년 9월 International Targeting 보고서 지원 중단 안내입니다. 보고서는 사라졌지만 hreflang 태그는 작동합니다.
Bing / Microsoft
- Bing Webmaster Guidelines — Bing 웹마스터 지침입니다. Bing은 hreflang보다
content-language와<html lang>에 의존합니다. - Bingbot Series: Maximizing Crawl Efficiency — Bingbot의 크롤링 효율 극대화에 관한 글로, 국제·다국어 사이트 처리 맥락을 제공합니다.
CMS / 플랫폼
- WPML — Using WordPress SEO (Yoast) with WPML — WPML과 Yoast를 함께 사용하는 방법 및 head/사이트맵 hreflang 출력 설정입니다.
- Shopify — Add hreflang tags in your theme — Shopify 테마의 수동
theme.liquid<link>패턴입니다.
출처의 인용문
구현과 관련된 공개 발언입니다. Google 문서 링크는 실제 페이지의 인용 위치로 바로 이동합니다.
Google — 세 방식
- “The three methods are equivalent from Google’s perspective and you can choose the method that’s the most convenient for your site.” (번역) 「Google 관점에서 세 방식은 동등하므로 사이트에 가장 편리한 방식을 선택할 수 있습니다.」 — Google Search Central 문서. 인용 위치로 이동
Google — 배치 위치
- “The
<link>tags must be inside a well-formed<head>section of the HTML.” (번역) 「<link>태그는 올바르게 구성된 HTML<head>안에 있어야 합니다.」 — Google Search Central 문서. 인용 위치로 이동
Google — 두 규칙
- “Each language version must list itself as well as all other language versions.” (번역) 「각 언어 버전은 자신과 다른 모든 언어 버전을 나열해야 합니다.」 — Google Search Central 문서. 인용 위치로 이동
- “If two pages don’t both point to each other, the tags will be ignored.” (번역) 「두 페이지가 서로를 가리키지 않으면 태그가 무시됩니다.」 — Google Search Central 문서. 인용 위치로 이동
- “Alternate URLs must be fully-qualified, including the transport method (http/https).” (번역) 「대체 URL은 전송 방식(http/https)을 포함한 완전한 형식이어야 합니다.」 — Google Search Central 문서. 인용 위치로 이동
Google — 코드
- “The first code of the hreflang attribute is the language code (in ISO 639-1 format) followed by an optional second code that represents the region code (in ISO 3166-1 Alpha 2 format).” (번역) 「hreflang 속성의 첫 코드는 ISO 639-1 언어 코드이며, 선택적인 두 번째 코드는 ISO 3166-1 Alpha 2 지역 코드입니다.」 — Google Search Central 문서. 인용 위치로 이동
John Mueller, Google — 명령이 아닌 힌트
- 자기 참조 태그에 관해: hreflang 자기 참조는 선택적이지만 좋은 관행으로 보도되었습니다. — Google의 John Mueller 발언을 제 Ahrefs hreflang 가이드 에서 전했습니다.
- 정확성이 결과를 보장하지 않는다는 점에 관해(2025년 5월, Bluesky): Mueller는 hreflang이 색인을 보장하지 않아 어떤 버전은 색인되지 않을 수 있고,
fr-fr와fr-be같은 동일 언어 변형은 흔히 통합된다고 설명했습니다. — Search Engine Journal 보도 를 통해 전해진 내용입니다.
어떤 구현 방식을 사용해야 하나요?
위에서 아래로 판단하고 처음 해당하는 곳에서 멈추세요.
1. 페이지가 PDF·문서·직접 제공되는 이미지 같은 비HTML 파일인가요?
→ 예 → HTTP Link: 헤더. <head>가 없으므로 유일한 선택지입니다. 서버/CDN에서 각 파일의 헤더에 전체 묶음을 나열하세요.
→ 아니요 → 계속 진행.
2. 로케일이 몇 개보다 많거나, 사이트맵 파이프라인이 있거나, headless/JAMstack 빌드인가요?
→ 예 → XML 사이트맵 <xhtml:link>. 번역 테이블에서 프로그래밍 방식으로 생성하세요. 자동 파일 하나이며 페이지별 마크업이 없고 QA가 가장 쉽습니다.
→ 아니요 → 계속 진행.
3. 작고 단순하며 로케일이 적고 페이지에서 모든 것을 볼 수 있기를 원하나요?
→ <head>의 HTML <link> 태그. 하나의 기준 데이터로 생성한 블록이 올바르게 구성된 <head> 안에 배치되는지 확인하세요.
무엇을 선택하든: 단독으로 사용하세요. Google은 결합해도 이점이 없다고 하며 추가 사본마다 불일치할 곳이 늘어납니다.
x-default가 필요한가요?
명시한 어느 로케일에도 맞지 않는 사용자를 위한 국가/언어 선택기나 글로벌 홈페이지가 있나요?
→ 예 → 해당 대체 페이지의 x-default를 추가하세요.
→ 아니요 → 생략할 수 있습니다. 선택 사항이며 Google이 자체 감지를 사용합니다. 상호 태그 누락과 달리 클러스터가 깨지지는 않습니다. 그래도 좋은 관행입니다. 제 연구에서 가장 많이 빠뜨린 항목이었습니다(56.3%).
사용자를 위치에 따라 자동 리디렉션해야 하나요?
IP/지역 기반 리디렉션을 고려하고 있나요? → 사람에게만 적용하고 강제 이동보다 방해하지 않는 배너를 선호하세요. → 크롤러는 지역별로 리디렉션하지 마세요. Googlebot은 주로 미국에서 크롤링하므로 다른 지역 버전이 색인에서 빠질 수 있고, 클로킹 분류 및 EU 지역 차단 금지 규정 관련 위험도 있습니다. 봇이 모든 URL 버전에 직접 접근하게 하며 연결 신호는 hreflang에 맡기세요.
내 CMS에 맞는 방법은 무엇인가요?
- WordPress? → Yoast만으로는 안 됩니다. WPML이나 Polylang을 설치하면 hreflang을 출력합니다. WPML SEO 설정에서 head와 사이트맵 출력을 선택하세요.
- Shopify? → Markets가 상호 태그를 자동 생성하지만 흔히 언어만 지정합니다.
fr-FR와fr-CA를 구별해야 한다면 수동theme.liquid태그나 앱을 추가하되 충돌 위험 때문에 둘을 섞지 마세요. - 맞춤형 / headless? → 빌드/응답 시 번역 관계 테이블에서
<xhtml:link>또는 head 태그를 출력하세요.
SOP: hreflang 클러스터를 처음부터 배포하기
새 클러스터 또는 기존 클러스터에 새 로케일을 추가하는 반복 가능한 절차입니다. 위에서 아래로 진행하세요.
1. 로케일 행렬을 만드세요: 하나의 기준 데이터. 모든 URL과 언어·지역 코드를 데이터베이스 테이블, CMS 번역 필드 또는 스프레드시트 한곳에 나열하세요. 프로토콜·www·끝 슬래시·대소문자가 올바른 canonical·색인된 형식인지 확인하세요. 아래 모든 작업의 입력은 이 표이며 후속 단계에서 직접 입력하지 않습니다.
2. 의사결정 트리 탭으로 방식 하나를 선택하세요. 결합하지 마세요.
3. 행렬에서 주석을 생성하세요.
- HTML: 각 페이지의
<head>에 행렬의<link>블록을 출력합니다. - 사이트맵:
<urlset>에xmlns:xhtml네임스페이스를 선언해 각<url>블록을 출력합니다. - 헤더: 서버/CDN에서 행렬로
Link:헤더를 출력합니다.
4. 게시 전에 두 규칙을 프로그래밍 방식으로 검증하세요. 모든 항목은 (a) 자기 참조를 포함하고 (b) 클러스터의 다른 모든 항목을 나열해야 합니다. A→B마다 B→A가 있는지 상호 참조를 확인하세요.
5. 선택기나 글로벌 대체 페이지가 있다면 x-default를 추가하세요.
6. 게시 후 렌더링된 출력을 검증하세요. 상세 절차는 플레이북 탭을 보세요. 소스 보기가 아닌 렌더링된 head, 전체 클러스터 상호 참조 크롤링, &hl=/&gl= SERP 표본 검사를 진행합니다.
7. 지속적인 검사에 연결하세요. 향후 URL 변경이나 새 로케일 때문에 반환 태그가 조용히 어긋나지 않도록 정기 크롤링/회귀 테스트를 추가하세요. 검증은 일회성 작업이 아닙니다.
나중에 로케일을 추가할 때: 1단계 행렬만 수정하고 3–6단계를 반복합니다. 로케일 추가를 위해 개별 페이지를 손으로 수정하고 있다면 기준 데이터가 잘못된 것이므로 그것부터 고치세요.
플레이북: “hreflang이 작동하지 않아요” 검증 절차
순서대로 진행하세요. 각 단계가 문제를 찾거나 의심 대상을 제외합니다.
1단계 — 태그가 실제 렌더링되는지 확인. 페이지의 렌더링된 DOM을 GSC URL 검사 → Test Live URL → View Tested Page 또는 렌더링 크롤러로 보세요. JavaScript로 삽입한 hreflang은 실제 존재해도 Ctrl+U 소스 보기에 없으므로 의존하지 마세요.
- 렌더링된 head에 있음 → 3단계.
- 렌더링된 head에 없음 → 2단계.
2단계 — 태그가 <head>에 있나요, <body>에 있나요? 소스에 있지만 <body> 안이면 유효하지 않습니다. 잘못되거나 삽입된 <p> 또는 iframe이 <head>를 조기에 닫았을 가능성이 큽니다. DOM 중단점으로 깨지는 지점을 찾아 마크업을 수정하고 재확인하세요.
3단계 — 절대·canonical URL인지 확인. 모든 href는 완전한 https://… 형식이며 프로토콜·www·끝 슬래시·대소문자까지 색인된 것과 같아야 합니다. 301, 404, noindex 또는 다른 곳으로 canonical을 지정한 URL을 가리키지 않는지 확인하세요.
4단계 — 클러스터 전체 상호 참조 확인. Screaming Frog/Ahrefs Site Audit으로 전체를 크롤링하세요. A→B마다 B→A가 있고 각 페이지가 자기 참조하는지 확인합니다. 대부분의 문제가 여기에 있으며 반환 태그 하나가 없으면 그 쌍이 제외됩니다.
5단계 — 코드 검증. ISO 639-1 언어 + ISO 3166-1 alpha-2 지역을 확인하세요. 특히 en-UK(→ en-GB), jp(→ ja), 세 글자와 지역 전용 코드를 살펴보세요.
6단계 — 지역 리디렉션 배제. 크롤러가 지역별로 리디렉션되지 않는지 확인하세요. 미국에서 크롤링하는 Googlebot이 미국 버전으로 이동되면 다른 지역 URL에 도달하지 못할 수 있습니다.
7단계 — 기술적으로 정상이라면 기대를 조정. 모두 통과했는데 fr-fr/fr-be 같은 동일 언어 변형이 보고에서 통합되어도 예상 가능한 일입니다. Google은 구현과 무관하게 거의 동일한 언어 변형을 통합할 수 있습니다. 명령이 아닌 힌트이며 잘못되거나 무시되는 hreflang은 페널티가 아닙니다. 버그로 간주해 계속 쫓지 마세요.
구현 안티패턴
구체적인 실수, 틀린 이유와 대안을 설명합니다.
1. 페이지별 hreflang 수동 유지. 틀린 이유: 템플릿이나 로케일 하나가 어긋나면 반환 태그가 빠지고 쌍이 제외됩니다. 대규모 상호 참조의 노후화입니다. 대신 할 일: 번역 테이블, CMS 필드 또는 작은 사이트의 Sheets 템플릿이라는 한 기준 데이터에서 전체 주석을 생성해 클러스터를 편집하지 않고 재생성하세요.
2. “추가 신호”를 위해 세 방식 모두 사용. 틀린 이유: Google은 이점이 없다고 하며 사본 세 개는 불일치 기회 세 개입니다. 대신 할 일: 하나만 선택해 단독으로 사용하세요.
3. 크롤러를 지역/IP로 자동 리디렉션. 틀린 이유: 주로 미국에서 크롤링하는 Googlebot을 지역별로 이동시키면 다른 지역 클러스터 전체가 색인에서 빠질 수 있고 클로킹 및 EU 지역 차단 금지 규정 관련 위험도 있습니다. 대신 할 일: 사용자에게만 리디렉션이나 더 나은 대안인 배너 제안을 사용하세요. 크롤러는 모든 URL에 직접 접근하게 하고 신호는 hreflang에 맡기세요.
4. 비canonical·리디렉션·noindex URL 대상. 틀린 이유: 반환 링크가 301/404/noindex 페이지로 연결되어 쌍이 깨집니다. 연구에서 16.9%는 깨지거나 리디렉션된 페이지, 8.0%는 비canonical을 참조했습니다. 대신 할 일: 각 버전이 자신을 canonical로 지정하고 살아 있는 canonical·색인 가능 URL만 참조하며 URL 변경마다 재생성하세요.
5. 상대 또는 프로토콜 상대 URL. 틀린 이유: Google은 완전한 URL을 요구하므로 /foo와 //example.com/foo는 유효하지 않습니다. 절대 URL도 슬래시/www/대소문자가 다르면 상호 참조가 일치하지 않습니다. 대신 할 일: 색인된 정확한 형식과 같은 https://example.com/foo를 사용하세요.
6. “페이지 소스 보기”를 검증으로 신뢰. 틀린 이유: JavaScript hreflang이 원시 소스에 없어서 누락으로 착각하거나, 유효하지 않은 <body>에 렌더링되는 것을 놓칩니다. 대신 할 일: GSC URL 검사나 렌더링 크롤러로 렌더링된 DOM을 검증하세요.
7. 잘못되거나 임의의 로케일 코드. 틀린 이유: en-UK, jp, ger와 지역 전용 코드는 유효하지 않아 무시됩니다. 대신 할 일: ISO 639-1 언어 + 선택적 ISO 3166-1 alpha-2 지역인 en-GB, ja, de, es-MX를 사용하세요.
수정 전후
1. 상호 태그 누락: 전형적 사례. 수정 전: 미국 페이지는 US + UK + DE를 나열하지만 독일어 템플릿은 DE + US만 나열해 영국 반환 링크를 빠뜨렸습니다. Google은 DE↔UK 쌍을 제외합니다. 수정 후: 독일어 블록에 DE + US + UK가 있어 모두 자기 참조와 상호 참조합니다. 로케일 테이블에서 재생성해 다시 어긋나지 않게 합니다.
2. 상대 URL. 수정 전: <link rel="alternate" hreflang="de" href="/de/" /> — 상대 URL이라 유효하지 않고 무시됩니다. 수정 후: <link rel="alternate" hreflang="de" href="https://example.com/de/" /> — 완전하며 색인된 형식과 같습니다.
3. 잘못된 영국 코드. 수정 전: <link rel="alternate" hreflang="en-uk" href="https://example.com/uk/" /> — uk는 우크라이나어이므로 주석이 유효하지 않습니다. 수정 후: <link rel="alternate" hreflang="en-gb" href="https://example.com/uk/" />.
4. 사이트맵 네임스페이스 누락. 수정 전: <xhtml:link>를 사용하지만 <urlset>에 기본 사이트맵 네임스페이스만 선언해 모든 주석이 유효하지 않습니다. 수정 후: <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"> — xhtml이 선언되어 주석을 검증할 수 있습니다.
복사해서 사용할 AI 프롬프트
자리표시자를 바꿔 원하는 어시스턴트에 붙여 넣으세요. LLM은 그럴듯하지만 틀린 코드를 만들거나 반환 링크를 빠뜨릴 수 있으므로 항상 실제 크롤링과 대조해 검증하세요.
로케일 행렬에서 HTML <head> 블록 생성
I have these language/region page variants:
- en-US: https://example.com/us/
- en-GB: https://example.com/uk/
- de: https://example.com/de/
- global fallback / selector: https://example.com/
For EACH page above, output the complete hreflang <link> block that belongs in its
<head>. Every block must (a) self-reference, (b) list all other variants, and
(c) include an x-default pointing at the fallback. Use fully-qualified https URLs
exactly as given. Validate the codes as ISO 639-1 language + ISO 3166-1 alpha-2
region and flag any that look wrong.같은 행렬을 XML 사이트맵 블록으로 변환
Using the same variant list, output an XML sitemap that uses <xhtml:link> hreflang
annotations. Requirements: declare xmlns:xhtml="http://www.w3.org/1999/xhtml" on
<urlset>; give every <url> block a full self-referencing + all-alternates set; use
the exact URLs provided. Do not add any URL not in my list.붙여 넣은 클러스터의 상호 참조와 코드 오류 감사
Here are the hreflang tags from each page in my cluster: [paste each page's URL and
its hreflang tags]. Check for: missing self-reference, missing reciprocal (A->B
without B->A), invalid ISO codes, relative/protocol-relative URLs, and any URL that
appears with inconsistent formatting (trailing slash / www / case). List each issue
with the exact page and tag it's on. Do not assume tags I didn't paste.
추출·콘솔·생성 코드
hreflang을 만들고 검사하는 실용적인 짧은 코드입니다. 실행 전에 URL을 조정하세요.
Chrome DevTools Console — 현재 페이지 hreflang 태그 목록 아무 페이지에서 Console(F12 → Console)에 붙여 넣어 브라우저가 실제 렌더링한 것을 보세요. 소스 보기가 놓치는 JavaScript 삽입 태그도 포함됩니다.
[...document.querySelectorAll('link[rel="alternate"][hreflang]')]
.map(l => ({ hreflang: l.hreflang, href: l.href,
inHead: !!l.closest('head') }));inHead는 <head> 손상 버그를 알려 줍니다. inHead: false인 태그는 <body> 안에 렌더링되어 유효하지 않습니다.
북마클릿 — 같은 검사, 한 번의 클릭 이 URL로 북마크를 저장한 뒤 원하는 페이지에서 클릭하세요.
javascript:(()=>{const t=[...document.querySelectorAll('link[rel="alternate"][hreflang]')].map(l=>`${l.hreflang} ${l.href} ${l.closest('head')?'(head)':'(BODY - INVALID)'}`);alert(t.length?t.join('\n'):'No hreflang tags found');})();XPath — head 안의 hreflang 링크 선택: 크롤러/브라우저 검사기용
//head/link[@rel='alternate' and @hreflang]크롤러가 link[@hreflang]를 //body 아래에서 찾으면 head 손상 버그입니다.
정규식 — 원시 HTML의 hreflang 코드와 URL 추출: 빠른 grep용이지 실제 파서가 아님
<link[^>]*rel=["']alternate["'][^>]*hreflang=["']([^"']+)["'][^>]*href=["']([^"']+)["']캡처 그룹 1은 코드, 그룹 2는 URL입니다. 빠른 확인용 grep으로만 쓰고 실제 HTML은 정규식이 아닌 DOM 라이브러리로 파싱하세요.
curl — HTTP Link: 응답 헤더의 hreflang 확인: PDF/비HTML용
curl -sI https://example.com/file.pdf | grep -i '^link:'Python — 행렬에서 일관된 hreflang <head> 블록 생성
variants = {
"en-us": "https://example.com/us/",
"en-gb": "https://example.com/uk/",
"de": "https://example.com/de/",
"x-default": "https://example.com/",
}
# Every page gets the SAME full block (self-reference + all alternates),
# which is exactly what satisfies reciprocity.
block = "\n".join(
f'<link rel="alternate" hreflang="{code}" href="{url}" />'
for code, url in variants.items()
)
print(block)
실력 점검: hreflang 구현
클러스터를 올바르게 만드는 방법에 관한 짧은 질문 다섯 개입니다. 각각 답을 고르고 확인하세요.
살펴볼 만한 자료
제가 쓴 관련 글
- Hreflang: The Easy Guide for Beginners — 세 방식, 흔한 구현 문제 아홉 가지와 수정법, 대규모 반자동 생성을 위한 Google Sheets 템플릿을 담은 제 Ahrefs 입문 가이드입니다.
- Over 67% of Domains Using Hreflang Have Issues — hreflang 사용 도메인의 67% 이상에 문제가 있다는 제 374,756개 도메인 연구입니다. 역대 최대 규모이며 오류 분포의 출처입니다. x-default 누락 56.3%, 자기 참조 18.0%, 깨진/리디렉션 대상 16.9%, 상호 참조 15.3%, 비canonical 8.0%, 잘못된 코드 4.6%입니다.
제 발표
- International SEO: The Weird Technical Parts — Pubcon Vegas 2019 — 국제 SEO의 특이한 기술 영역을 다룬 가장 풍부한 구현 자료입니다. iframe/잘못된 마크업으로 태그가
<head>에서<body>로 밀리는 버그와 DOM 중단점 디버깅, “사이트맵이 더 빠르다”는 오해, 지역 리디렉션의 색인 제거 위험,&hl=/&gl=SERP 검사법을 다룹니다. - Hreflang Study and Interesting Issues — Brighton SEO 2023 — 연구의 바탕 슬라이드입니다. Google의 구체성 우선 일치 순서(언어+국가 → 언어 → x-default)와 데이터에서 가장 흔한 코드 실수도 다룹니다.
- You’re Going To Screw Up International SEO — Pubcon Vegas 2017 — 국제 SEO 구현의 혼란을 다룹니다. 잘못된 도구 정보, 색인된 주소와 다른 URL에서 제공되는 콘텐츠와 중복 페이지 함정입니다.
업계의 다른 자료
- Google의 Localized versions of your pages — 현지화 버전의 주요 구현 문서입니다. 세 방식의 정확한 문법, 상호/자기 참조, 유효 코드와 절대 URL 요구 사항을 다룹니다. 구현 전에 전부 읽으세요.
- Google의 Managing multi-regional and multilingual sites — 다지역·다국어 URL 구조와 “사용자만 이동시키고 크롤러는 하지 말라”는 배경의 자동 리디렉션/클로킹 경고입니다.
- WPML — Using WordPress SEO (Yoast) with WPML — Yoast 단독으로는 되지 않는 WordPress hreflang 출력법 및 head/사이트맵 설정입니다.
- Shopify — Add hreflang tags in your theme — Markets의 언어 전용 태그가 충분히 구체적이지 않을 때의 수동
theme.liquid<link>패턴입니다. - Screaming Frog — How To Audit & Test Hreflang — URL 하나의 표본 검사 대신 전체 클러스터 상호 참조를 확인하는 크롤링 절차입니다.
- Google Reminds That Hreflang Tags Are Hints, Not Directives — 2025년 5월 Search Engine Journal의 보도입니다. hreflang은 명령이 아닌 힌트이며 기술적으로 완벽해도 동일 언어 버전이 통합될 수 있다는 Mueller의 설명을 다룹니다.
- r/TechSEO — 깨진 hreflang 클러스터를 디버깅하는 커뮤니티입니다.
hreflang 클러스터가 실제 배포되었는지 입증하기
Hreflang은 조용히 실패합니다. 태그가 있고 형식이 올바르더라도 반환 연결이 없으면 여전히 무시될 수 있습니다. 검사는 “코드에 있다”가 아닌 클러스터 전체 상호 참조입니다. 언어/지역 묶음을 배포한 뒤 실행하세요.
테스트 1 — 모든 쌍이 태그를 반환하는가: 상호 참조
- 실행할 테스트 — A가 가리키는 모든 페이지가 A를 다시 가리키는지 검사하는 returntag 로 전체 클러스터를 크롤링하거나 Screaming Frog hreflang 보고서를 실행하세요.
- 예상 결과 — 비상호 쌍 0개이며 모든 URL이 자기 참조합니다. “몇 개”가 아닌 오류 0개입니다.
- 실패 해석 — A → B지만 B가 A로 돌아오지 않는 단방향 쌍은 Google이 그 쌍을 제외한다는 뜻입니다. 실제로 가장 흔한 실패이며 URL 하나의 소스만 보면 보이지 않습니다.
- 관찰 시점 — 렌더링된 태그는 즉시 확인합니다. 검사기는 현재 실제 상태를 읽습니다.
- 롤백 조건 — 비상호 쌍이 하나라도 있거나 태그가 301 또는 404 URL을 가리키는 경우. Google을 기다리기 전에 기준 데이터를 고치고 재배포하세요.
테스트 2 — Google이 정상 처리하는가
- 실행할 테스트 — Google은 2022년 9월 옛 International Targeting 보고서를 폐지했으므로 의존하지 마세요. 클러스터의 각 로케일을 페이지 색인 생성에서 확인하고, 표본 페이지의 URL 검사로 “Google-selected canonical”(Google이 선택한 canonical)과 색인 상태가 해당 로케일의 예상과 맞는지 확인하세요.
- 예상 결과 — 의도한 각 로케일 페이지가 색인되고, 서로 다른 언어를 하나로 합치는 “Duplicate, Google chose different canonical”(중복, Google이 다른 canonical 선택)이 아니며, URL 검사에 예상한 대체 버전이 표시됩니다.
- 실패 해석 — 다른 로케일의 canonical 중복으로 나타나거나 색인이 통합되는 경우는 보통 hreflang 자체보다 반환 연결 손상에서 비롯되므로 테스트 1을 다시 보세요. 다만 hreflang은 명령이 아닌 힌트이므로 기술적으로 완벽한 클러스터도 Google이 거의 중복이라고 판단하면 통합될 수 있습니다.
- 관찰 기간 — 2–4주. Search Console은 시간이 지나며 다시 크롤링하고 보고하므로 즉시 반영되지 않습니다.
- 롤백 조건 — 로케일 페이지가 계속 잘못된 canonical 아래 색인되거나 검색어에 잘못된 지역 URL이 노출되는 경우. 상호 참조부터 다시 감사하세요. 실제 빈틈이 반환 연결인데 태그가 “작동하지 않는다”고 가정하지 마세요.
변경 내역
2026년 9월 8일에 업데이트됨.
편집 요약 및 기록된 변경 세부 정보입니다.요약
hreflang 구현 규칙과 검증 절차에 관한 원문 변경 이력을 한국어로 복원했습니다.
변경 세부 정보
-
도구 이름 및 세 가지 구현 방식의 검증 수정 기록을 복원하고 원문 개정 번호를 한국어 개정 번호와 분리했습니다. 기존 한국어 기록과 본문은 유지했습니다.
전체 비교를 사용할 수 없음 — 이 수정에 대한 이전 스냅샷이 보관되지 않았습니다.
2026년 9월 8일에 업데이트됨.
편집 요약 및 기록된 변경 세부 정보입니다.요약
일반적인 임시 문구를 단계별 hreflang 구현 원문에 충실한 한국어 번역으로 교체했습니다.
변경 세부 정보
-
본문 서술 165개, 메타데이터 9개 값과 컴포넌트 39개 필드를 복원했습니다. 기술 주석 하나, 보호 블록 39개, 프롬프트를 포함한 코드 블록 15개, 유효한 컴포넌트 2개 및 기존 로컬 3·4·5와 원문 2·1 이력은 보존했습니다. 원문 내부의 주장 차이는 조정하지 않고 별도 기록했습니다.
전체 비교를 사용할 수 없음 — 이 수정에 대한 이전 스냅샷이 보관되지 않았습니다.
2026년 8월 8일에 업데이트됨.
편집 요약 및 기록된 변경 세부 정보입니다.요약
한국어 소스 잠금 초안을 생성했으며 감사가 끝날 때까지 격리했습니다.
변경 세부 정보
-
한국어 초안, TM, 컴포넌트 사이드카를 생성했습니다.
전체 비교를 사용할 수 없음 — 이 수정에 대한 이전 스냅샷이 보관되지 않았습니다.
2026년 8월 8일에 업데이트됨.
편집 요약 및 기록된 변경 세부 정보입니다.요약
한국어 소스 잠금 초안을 생성했으며 감사가 끝날 때까지 격리했습니다.
변경 세부 정보
-
한국어 초안, TM, 컴포넌트 사이드카를 생성했습니다.
전체 비교를 사용할 수 없음 — 이 수정에 대한 이전 스냅샷이 보관되지 않았습니다.
2026년 7월 25일에 업데이트됨.
편집 요약 및 기록된 변경 세부 정보입니다.요약
기존 도구 표시 이름을 returntag 및 Scout Site Audit Free에 맞췄습니다.
변경 세부 정보
-
링크된 도구 이름을 당시 공개 표시 이름과 일치하도록 갱신했습니다.
전체 비교를 사용할 수 없음 — 이 수정에 대한 이전 스냅샷이 보관되지 않았습니다.
2026년 7월 18일에 업데이트됨.
편집 요약 및 기록된 변경 세부 정보입니다.요약
검증 절차가 Search Console의 폐지된 International Targeting 보고서에 의존하던 문제를 수정했습니다. Google의 hreflang 문서에 비춰 확인한 HTML 속성 혼용 규칙, 모든 HTTP 응답의 전체 집합 불변 조건, 사이트맵 xhtml:link 순서 및 URL 제한 동작의 세 가지 누락도 보완했습니다.
변경 세부 정보
-
Validation Tests의 테스트 2에서 제거된 Legacy tools & reports → International Targeting 보고서를 더 이상 안내하지 않도록 했습니다. 대신 Page Indexing과 URL Inspection으로 각 지역·언어 버전이 자신의 canonical 아래 색인되는지 확인하도록 바꿨습니다.
-
방법 1인 HTML 링크 태그에 같은 link 요소에서 hreflang과 media 같은 다른 대체 속성을 혼용하지 말라는 Google의 규칙을 명시했습니다.
-
방법 2인 HTTP 헤더에 모든 응답이 전체 집합을 포함해야 한다는 불변 조건을 명시했습니다.
-
방법 3인 XML 사이트맵에 xhtml:link 자식 요소의 순서는 중요하지 않으며 해당 자식 요소는 사이트맵의 URL 50,000개 제한에 포함되지 않는다고 명시했습니다.
전체 비교를 사용할 수 없음 — 이 수정에 대한 이전 스냅샷이 보관되지 않았습니다.