Field guide / crawler-eye-check
크롤러의 눈으로 5분 점검: curl로 보는 색인 준비 상태
브라우저 대신 curl로 초기 HTML, 응답 헤더, robots.txt, 사이트맵, 없는 URL의 응답을 확인하는 8가지 점검법과 판독 기준, 검사기가 자동으로 해 주는 범위를 정리합니다.
- 작성
- 수정
- 작성자
- 검토
- 애드브랜치 편집팀
왜 브라우저 화면만 보면 안 되나
배포가 끝나면 대개 브라우저로 페이지를 열어 보고 “잘 나온다”로 확인을 마칩니다. 그런데 브라우저가 보여 주는 화면과 크롤러가 처음 받아 가는 문서는 같지 않습니다. 브라우저는 서버가 보낸 HTML을 받은 뒤 JavaScript를 실행하고, 그 결과로 제목과 본문을 그려 넣습니다. 크롤러가 가장 먼저 읽는 것은 그 실행 전의 초기 HTML과 함께 도착한 응답 헤더입니다.
여기에 두 종류의 사고가 숨어 있습니다. 하나는 초기 HTML에 본문이 없는 경우입니다. <div id="root"></div>와 스크립트 한 줄만 있는 문서는 사람 눈에는 완성된 페이지지만, 첫 응답만 놓고 보면 내용이 없는 페이지입니다. 다른 하나는 화면에 전혀 드러나지 않는 신호입니다. X-Robots-Tag: noindex 헤더, <meta name="robots" content="noindex"> 태그, robots.txt의 Disallow 줄은 화면을 바꾸지 않습니다. 페이지가 멀쩡히 보여도 이 보이지 않는 층에서 색인 문제가 생길 수 있습니다.
그래서 점검 도구를 바꿔야 합니다. curl은 JavaScript를 실행하지 않고, 서버가 보낸 바이트를 그대로 돌려줍니다. 크롤러가 받는 첫 응답에 가장 가까운 시야입니다. 아래 8가지 명령은 macOS와 Linux 터미널에서 바로 실행할 수 있고, Windows에서는 PowerShell의 curl.exe로 같은 옵션을 쓰면 됩니다.
점검 전에 알아 둘 옵션 5개
| 옵션 | 하는 일 | 쓰는 이유 |
|---|---|---|
-s | 진행 표시를 끕니다 | 출력에 본문과 헤더만 남깁니다 |
-I 또는 -D - | 헤더만 요청하거나 헤더를 본문과 함께 출력합니다 | 상태 코드와 X-Robots-Tag를 읽습니다 |
-o /dev/null -w … | 본문을 버리고 지정한 값만 출력합니다 | 상태 코드나 최종 URL 한 줄만 볼 때 씁니다 |
-L | 리디렉션을 따라갑니다 | 최종 목적지를 확인할 때만 켭니다 |
-A "..." | User-Agent를 바꿉니다 | 크롤러 이름에 따라 응답이 달라지는지 비교합니다 |
-I는 HEAD 요청을 보내므로 일부 서버가 GET과 다르게 응답할 수 있습니다. 헤더와 본문을 한 번에 보려면 -D -가 더 정확합니다.
curl 점검 8가지
아래 예시는 https://example.com/guides/sample을 점검한다고 가정합니다. 각 항목마다 명령어, 정상으로 볼 기준, 문제로 볼 기준을 적었습니다.
1. 상태 코드와 리디렉션
curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" https://example.com/guides/sample
curl -s -o /dev/null -L -w "%{num_redirects} hops -> %{url_effective} (%{http_code})\n" https://example.com/guides/sample
첫 줄은 리디렉션을 따라가지 않고 첫 응답만 봅니다. 공개 페이지라면 200이 나와야 합니다. 301이나 308이 나오면 옆에 찍힌 목적지가 의도한 canonical 주소인지 확인하세요. 둘째 줄은 끝까지 따라가 홉 수와 최종 URL을 보여 줍니다. Google 크롤러는 최대 10번의 리디렉션 홉을 따라가며, 301과 308은 강한 신호로, 302와 307은 약한 신호로 다룹니다. 원문은 Google의 HTTP 상태 코드 안내에 있습니다. 홉이 2개 이상이면 중간 단계를 없애고 한 번에 최종 URL로 보내는 편이 안전합니다.
2. 초기 HTML에 본문이 있는가
curl -s https://example.com/guides/sample | wc -c
curl -s https://example.com/guides/sample | tr '\n' ' ' | grep -oiE '<p([[:space:]>])' | wc -l
curl -s https://example.com/guides/sample | grep -o "<h1[^>]*>[^<]*</h1>"
첫 줄은 문서 크기, 둘째 줄은 <p> 태그 개수, 셋째 줄은 H1 내용을 뽑습니다. H1이나 <p>를 찾지 못했다고 JavaScript 의존으로 단정할 수는 없습니다. <div> 위주 구조이거나 중첩 태그 때문에 간이 명령이 놓칠 수도 있으므로 원본 본문 텍스트와 브라우저를 함께 확인하세요. 이 명령은 HTML 문자열의 시작 태그를 세는 간이 점검이며, 주석이나 스크립트 안의 태그 문자열을 완전히 구분하는 HTML 파서는 아닙니다. 애드브랜치 검사기의 initial-html-content는 초기 HTML의 가시 텍스트가 200자 이상이거나 제목과 문단을 합쳐 3개 이상이면 통과로 봅니다. 그 기준에 못 미치면서 스크립트만 있는 껍데기 문서로 판단되면 unknown, 그렇지 않으면 warning을 냅니다. 핵심 본문과 제목은 서버 렌더링이나 정적 생성으로 초기 HTML에 넣는 것이 근본 해결책입니다.
3. meta robots와 X-Robots-Tag의 noindex
curl -s -D - -o /tmp/page.html https://example.com/guides/sample | grep -i "x-robots-tag"
grep -io '<meta name="robots"[^>]*>' /tmp/page.html
첫 줄은 응답 헤더에서 X-Robots-Tag를, 둘째 줄은 저장한 HTML에서 meta robots 태그를 찾습니다. 아무것도 나오지 않으면 기본값인 색인 허용으로 해석됩니다. noindex나 none이 한 곳에라도 있으면 그 페이지는 검색 결과에서 빠집니다. 검사기는 meta-robots-indexability와 x-robots-tag-indexability에서 이 두 위치를 각각 보고, noindex가 있으면 critical을 냅니다. nosnippet처럼 색인은 허용하되 표현을 제한하는 토큰만 있으면 warning입니다.
nosnippet은 단순한 표시 제한이 아닙니다. Google 문서는 nosnippet이 AI 개요와 AI 모드의 직접 입력으로 쓰이는 것도 막고, max-snippet은 그 길이를 제한하며, data-nosnippet은 JSON-LD를 숨기지 않는다고 설명합니다. 원문은 Google의 robots meta 태그 안내입니다. 검색에는 나오되 AI 기능에는 쓰이지 않도록 하려는 의도가 아니라면 이 토큰을 무심코 두지 마세요.
4. title, description, OG, JSON-LD가 초기 HTML에 있는가
grep -io '<title>[^<]*</title>' /tmp/page.html
grep -io '<meta name="description"[^>]*>' /tmp/page.html
grep -io '<meta property="og:[a-z:]*"[^>]*>' /tmp/page.html
tr '\n' ' ' < /tmp/page.html | grep -oiE '<script[^>]*application/ld\+json[^>]*>' | wc -l
각 목적에 필요한 항목을 확인하세요. 예를 들어 description은 Google이 스니펫에 쓸 수 있고 구조화 데이터는 특정 리치 결과 기능의 자격에 쓰이지만, 모든 페이지에 네 가지가 다 필요한 것은 아닙니다(Google의 스니펫 안내). 브라우저 개발자 도구의 “요소” 탭에는 JavaScript가 나중에 넣은 태그도 보이기 때문에, 이 확인은 반드시 저장해 둔 원본 파일을 대상으로 해야 합니다. JSON-LD 개수가 0인데 화면 소스에는 있다면 스크립트가 런타임에 삽입하는 구조이고, 이 경우 첫 응답만 읽는 수집기는 구조화 데이터를 보지 못합니다.
5. robots.txt
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/robots.txt
curl -s https://example.com/robots.txt
상태 코드가 200이면 내용을 읽고, 404면 파일이 없다는 뜻이므로 전체 허용으로 해석됩니다. 문제는 5xx입니다. 네이버 서치어드바이저 문서는 robots.txt가 4xx면 전체 허용, 5xx면 전체 차단으로 처리하며 리디렉션은 최대 5번까지 따라간다고 안내합니다. 원문은 네이버 robots.txt 설정 안내에 있습니다. 서버 장애로 robots.txt가 500을 내면 사이트 전체가 잠시 차단된 것과 같은 효과가 나므로, 파일 내용보다 상태 코드를 먼저 봐야 합니다.
내용에서는 점검하려는 경로가 Disallow에 걸리는지, Sitemap: 줄이 절대 URL인지 확인합니다. 일부 CDN이 관리형 robots.txt로 넣는 Content-Signal: 줄이 보일 수 있는데, Cloudflare 문서에 따르면 이 줄은 search, ai-input, ai-train 세 가지 용도에 대한 선호를 표현하는 것이고 기술적인 차단 수단은 아닙니다. 원문은 Cloudflare Content Signals 정책입니다. 자세한 해석은 AI 크롤러 접근 제어 가이드를 보세요.
6. sitemap
curl -s https://example.com/robots.txt | grep -i "^sitemap:"
curl -s -o /dev/null -w "%{http_code} %{content_type}\n" https://example.com/sitemap.xml
curl -s https://example.com/sitemap.xml | tr '\n' ' ' | grep -oE '<loc([[:space:]>])' | wc -l
curl -s https://example.com/sitemap.xml | grep -A2 "guides/sample"
첫 줄로 선언 위치를 찾고, 둘째 줄로 그 파일이 실제로 열리는지와 XML로 응답하는지 봅니다. 셋째 줄은 <loc> 요소 수, 넷째 줄은 점검 대상 URL이 들어 있는 줄과 뒤의 문맥을 보여 줍니다. 사이트맵 인덱스라면 <loc>는 페이지가 아니라 하위 사이트맵을 가리킵니다. 압축된 한 줄 XML에서는 넷째 명령이 긴 한 줄을 그대로 보여 줄 수 있으므로 실제 URL 항목과 날짜의 짝을 확인하세요. Google은 lastmod가 일관되고 검증 가능한 정확한 값일 때만 사용하고 priority와 changefreq는 무시하며, 파일 하나의 한도는 압축 전 50MB 또는 URL 50,000개입니다. 원문은 Google의 사이트맵 작성 안내입니다. 검사기의 sitemap-discovery는 robots.txt 선언 또는 /sitemap.xml 관례로 찾은 파일이 XML로 열리면 통과, 선언은 있는데 못 가져오면 warning, 요청 자체가 실패해 응답 상태를 받지 못하면 unknown, 그 밖에 파일을 찾지 못하면(예: /sitemap.xml이 404) info를 냅니다. 형식과 분할은 sitemap.xml 가이드에서 다룹니다.
7. 없는 URL이 정말 404를 내는가
curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" https://example.com/this-page-does-not-exist-2f9a
존재하지 않는 경로를 하나 지어서 요청합니다. 기대하는 답은 404 또는 410입니다. Google은 429를 뺀 모든 4xx를 “콘텐츠가 없다”는 뜻으로 똑같이 처리하고, 404와 410을 동등하게 다룹니다. 원문은 Google의 HTTP 상태 코드 안내입니다. 여기서 200이 나오면 “페이지를 찾을 수 없습니다”라는 화면을 정상 응답으로 보내는 soft 404이고, Google 문서는 이런 상태를 “찾을 수 없다는 메시지가 있지만 404 코드가 없는 페이지”로 정의합니다. 원문은 Search Console 페이지 색인 생성 보고서 도움말입니다. 홈으로 301이 나오는 것도 흔한 잘못된 설정입니다. 대응 방법은 soft 404 가이드에 있습니다.
검사기의 site-404-probe가 이 확인을 대신합니다. 같은 출처(origin)에 /adbranch-404-check- 뒤에 무작위 16진수 12자리를 붙인 경로를 리디렉션을 따라가지 않고 한 번 GET 요청합니다. 404와 410은 통과, 429를 뺀 다른 4xx는 info, 429는 unknown, 5xx는 warning입니다. 3xx 중 홈이나 점검 중인 페이지로 보내는 것은 warning, 다른 곳으로 보내는 것은 info이며 최종 도착지의 상태 코드는 확인하지 않습니다. 2xx는 soft 404 가능성으로 warning입니다.
8. llms.txt는 참고 항목
curl -s -o /dev/null -w "%{http_code} %{content_type}\n" https://example.com/llms.txt
curl -s https://example.com/llms.txt | head -3
이 파일은 있어도 되고 없어도 됩니다. Google은 검색에 나오기 위해 새 기계 판독 파일이나 AI용 텍스트 파일을 만들 필요가 없으며, Google 검색 자체가 그런 파일을 쓰지 않는다고 밝혔습니다. 원문은 Google의 생성형 AI 검색 최적화 안내입니다. Chrome Lighthouse의 에이전트 브라우징 감사도 이 파일을 선택 사항으로 두고, 없으면 해당 없음으로 처리하며 서버 오류만 지적합니다. 원문은 Lighthouse llms.txt 감사 문서입니다.
다만 만들어 두었다면 깨진 채로 두지는 마세요. 검사기의 geo-a10-llms-txt는 점수에 반영되지 않는 진단 규칙으로, /llms.txt를 리디렉션 없이 한 번(64KB까지) 가져옵니다. 3xx와 4xx는 info, 5xx나 요청 실패는 unknown, 200인데 본문이 HTML이면 warning, 200인데 첫 줄이 # 이름 형식이 아니면 warning, 나머지는 통과입니다. 작성법은 llms.txt 가이드를 보세요.
배포 직후 noindex 사고가 가장 치명적인 이유
8가지 중 하나만 고른다면 3번입니다. 스테이징 환경은 검색에 잡히면 안 되므로 대개 사이트 전체에 noindex를 걸어 둡니다. 그 설정이 환경 변수, 빌드 플래그, CDN 규칙 어딘가에 남은 채 프로덕션으로 올라가는 일이 반복됩니다. 화면은 완벽하게 보이고, 기능 테스트도 통과하고, 아무 오류 로그도 없습니다. 검색 유입이 줄어드는 것을 몇 주 뒤 그래프로 발견할 때까지 아무도 모릅니다.
noindex를 발견하면 공개 의도와 맞는지 바로 확인하세요. 공개 페이지에서 실수로 남은 값이라면 제거한 뒤 다시 크롤링될 시간을 감안해야 합니다. Google 문서는 재크롤링에 며칠에서 몇 주가 걸릴 수 있다고 안내합니다. 원문은 Google에 재크롤링 요청하기입니다.
배포 파이프라인에 아래 한 줄을 넣어 두면 이 사고를 배포 직후에 잡을 수 있습니다.
URL="https://example.com/"
if curl -s -D - -o /tmp/deploy-check.html "$URL" | grep -qi "x-robots-tag:.*noindex" \
|| grep -qi '<meta name="robots"[^>]*noindex' /tmp/deploy-check.html; then
echo "noindex detected on $URL" && exit 1
fi
curl로도 안 보이는 것: WAF와 봇 차단
curl 점검에는 한계가 하나 있습니다. 봇 전용 조건이 붙은 CDN이나 WAF 규칙은 일반 터미널 요청만으로 재현되지 않을 수 있습니다.
Cloudflare는 2026년 9월 15일 공지에서 “Block” 및 광고 페이지 차단 설정이 Applebot, Bingbot, Googlebot 같은 혼합 용도 크롤러에도 적용되며, 기존 설정은 그대로 이어진다고 밝혔습니다. 원문은 Cloudflare의 혼합 용도 AI 크롤러 공지입니다. 즉 설정에 따라 Googlebot도 막힐 수 있습니다. 다만 기존의 AI 학습 차단 설정은 별도 항목으로 이관되므로, 이미 운영 중인 사이트가 일괄적으로 검색 차단을 받는 것은 아닙니다. 자기 사이트가 어느 쪽인지는 curl이 아니라 Cloudflare 대시보드의 봇 설정에서 직접 확인해야 합니다.
-A 옵션으로 User-Agent만 바꿔 보는 것은 참고가 될 뿐 결정적이지 않습니다. 많은 차단 규칙이 User-Agent와 IP 대역을 함께 보기 때문에, User-Agent를 흉내 낸 요청이 통과해도 실제 크롤러는 막힐 수 있고 그 반대일 수도 있습니다.
curl -s -o /dev/null -w "%{http_code}\n" -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://example.com/
이 명령의 결과가 일반 요청과 다르면 그 자체가 단서입니다. 같더라도 안심할 근거는 아닙니다. 최종 확인은 Search Console의 URL 검사 도구와 크롤링 통계, 그리고 서버 접근 로그에서 실제 크롤러 요청의 상태 코드를 보는 것입니다. 색인 여부와 관련해서는 페이지가 색인되고 스니펫 표시가 가능해야 Google의 생성형 AI 기능에 나올 자격이 생긴다는 점도 기억해 두세요. 원문은 앞서 인용한 Google의 생성형 AI 검색 최적화 안내입니다.
애드브랜치 검사기가 대신해 주는 것과 못 하는 것
위 8가지 대부분은 애드브랜치 검사기에 URL을 넣으면 자동으로 확인됩니다. 검사기는 리디렉션 이동을 포함해 한 번의 검사에서 외부 요청을 최대 6회까지 보냅니다. 이 한도 안에서 점검 대상 페이지, robots.txt, 사이트맵, /llms.txt, 404 탐침을 확인합니다. 읽는 페이지는 입력한 한 페이지뿐이며 사이트를 순회하지 않습니다.
| 이 글의 항목 | 검사기 규칙 | 자동 확인 범위 |
|---|---|---|
| 1. 상태 코드와 리디렉션 | http-status-success | 최종 응답 코드, 리디렉션 체인 |
| 2. 초기 HTML 본문 | initial-html-content | 가시 텍스트 길이, 제목·문단 수 |
| 3. noindex | meta-robots-indexability, x-robots-tag-indexability | 두 위치의 토큰 |
| 4. 메타·OG·JSON-LD 존재 | metadata, social-sharing, structured-data 카테고리 규칙 | 초기 HTML 기준 |
| 5. robots.txt | robots-txt-path-allowed 등 | 현재 경로 허용 여부, Sitemap 선언 |
| 6. sitemap | sitemap-discovery, sitemap-lastmod | 파일 접근, urlset일 때 현재 URL과 lastmod |
| 7. 없는 URL 404 | site-404-probe | 무작위 경로 1회 요청 |
| 8. llms.txt | geo-a10-llms-txt | 존재와 형식(점수 미반영) |
규칙 전체 목록과 배점은 규칙 카탈로그에, 판정 원칙은 방법론에 있습니다.
검사기가 못 하는 것도 분명합니다. 첫째, 크롤러 IP에서 보내는 요청이 아니므로 WAF나 봇 관리 규칙의 차단은 알 수 없습니다. 둘째, 한 페이지만 읽으므로 사이트맵이 index 형식이면 하위 파일을 열지 않고, 다른 페이지의 noindex나 리디렉션은 보지 못합니다. 셋째, 로그인이 필요한 페이지는 로그인 화면이나 리디렉션 응답을 그대로 점검하게 됩니다. 넷째, 실제로 색인되었는지는 검사기가 아니라 Search Console에서 확인해야 합니다. 검사기는 “색인될 준비가 되었는가”를 보는 도구이지 “색인되었는가”를 알려 주는 도구가 아닙니다.
5분 점검 순서 요약
- 상태 코드 한 줄:
200인지, 리디렉션이면 목적지가 맞는지. -D -로 헤더와 본문을 저장하고X-Robots-Tag와meta robots에서noindex검색.- 저장한 파일에서
<title>, description,og:,ld+json존재 확인. <h1>과<p>개수로 초기 HTML 본문 확인.- robots.txt 상태 코드와
Disallow,Sitemap:줄. - 사이트맵 파일 접근과 현재 URL 포함 여부.
- 지어낸 경로로 404 확인.
- 시간이 남으면 llms.txt.
이 순서를 셸 스크립트로 묶어 두면 배포 때마다 같은 결과를 얻을 수 있습니다. 결과가 이상할 때 어느 층의 문제인지 구분하는 방법은 SEO와 GEO의 차이와 SEO 기본 점검 체크리스트에 정리돼 있습니다.
자주 묻는 질문
curl 결과와 브라우저 화면이 다른 이유는 무엇인가요
브라우저는 서버가 보낸 HTML을 받은 뒤 JavaScript를 실행해 화면을 완성하지만, curl은 실행 전의 원본 응답만 보여 주기 때문입니다. 본문이 클라이언트에서 그려지는 사이트일수록 두 결과의 차이가 큽니다. 차이가 크다면 크롤러의 첫 응답에도 본문이 없다는 뜻이므로, 핵심 내용을 서버 렌더링이나 정적 생성으로 초기 HTML에 넣는 것을 검토하세요. 서버가 User-Agent나 쿠키에 따라 다른 응답을 내는 경우에도 차이가 생길 수 있으니, -A 옵션으로 몇 가지 값을 바꿔 가며 비교해 보면 원인을 좁힐 수 있습니다.
noindex를 찾았는데 Search Console에는 색인돼 있다면
관측 시점이 다를 수 있기 때문입니다. curl은 현재 응답을 보여 주므로 지금 noindex가 있다면 공개 의도와 맞는지 바로 확인하세요. 제거한 뒤에도 보고서 반영에는 시간이 걸릴 수 있습니다. URL 검사 도구에서 현재 상태를 다시 확인하고, 재크롤링에 며칠에서 몇 주가 걸릴 수 있다는 점을 감안하세요.
로그인 뒤 페이지는 어떻게 점검하나요
크롤러는 로그인하지 않으므로, 로그인 뒤에만 보이는 페이지는 애초에 색인 대상이 아닙니다. 그런 페이지에 noindex가 있어도 사고가 아니며, 사이트맵에 넣지 않는 것이 맞습니다. 점검이 필요한 경우는 “로그인 없이도 일부가 보여야 하는 페이지”입니다. 이때는 curl에 쿠키를 넘기지 않은 상태로 요청해서, 크롤러가 받을 응답이 로그인 화면으로의 리디렉션인지 아니면 공개용 미리보기 본문인지 확인하세요. 상태 코드가 302로 로그인 페이지를 가리킨다면 그 URL은 검색에 나올 수 없습니다. 검사기도 같은 이유로 로그인 뒤 내용은 읽지 못하고, 리디렉션 응답을 그대로 판정합니다.
관련 가이드
변경 이력
- title, description, OG, JSON-LD 네 가지가 모든 페이지에 필요하다는 표현을 각 목적에 필요한 항목을 확인하는 표현으로 바로잡았습니다.
Check the evidence
이 페이지를 지금 검사해보기
읽고 있는 페이지나 운영 중인 URL을 넣으면 이 가이드와 연결된 SEO·GEO 항목을 바로 확인할 수 있습니다.
Next reading
관련 가이드
soft 404 해결하기: 없는 페이지의 응답과 오류 캐시 함정
존재하지 않는 URL에 200을 돌려주는 soft 404의 정의와 원인, 404와 410의 차이, 일시 장애 응답이 캐시되는 함정, 서버 설정 예시와 애드브랜치 site-404-probe 판정 기준을 정리합니다.
가이드 읽기
robots.txt 작성법과 흔한 실수
크롤러 접근 제어 파일의 문법과 User-agent 그룹, Allow와 Disallow 우선순위 규칙, 사이트를 통째로 막아버리는 실수와 noindex와의 차이를 다룹니다.
가이드 읽기
sitemap.xml 만들기와 제출하기
사이트맵의 XML 형식과 URL 개수·용량 제한, sitemap index 분할, robots.txt 선언, Search Console 제출, lastmod의 올바른 사용법을 정리합니다.
가이드 읽기
AI 크롤러 접근 설정
GPTBot, OAI-SearchBot, ClaudeBot, PerplexityBot, Google-Extended 등 AI 크롤러를 학습·검색·사용자 요청·통제 토큰으로 나누고 robots.txt로 선택 허용하거나 차단하는 방법을 다룹니다.
가이드 읽기