
AI 크롤러에게 본문이 전달되고 있는가? curl로 가시성을 CI 체크하는 구현
요약
AI 크롤러(GPTBot, ClaudeBot 등)가 JS를 실행하지 않을 가능성에 대비하여, 초기 HTML에 본문이 포함되었는지 curl로 검증하는 CI 구현 방법을 소개합니다. Next.js 환경에서 SSR/SSG를 통해 크롤러 가시성을 확보하고, GitHub Actions로 이를 자동화하는 가이드를 제공합니다.
핵심 포인트
- AI 크롤러의 JS 실행 여부가 불투명하므로 초기 HTML 본문 확보가 중요함
- curl을 이용해 User-Agent별 초기 HTML의 텍스트 양과 H1 유무를 판정
- GitHub Actions에 통합하여 SSR 퇴행 발생 시 CI를 실패하도록 구현
- Next.js App Router에서 서버 컴포넌트를 활용해 데이터 노출 보장
CSR (Client Side Rendering) 방식의 SPA는 서버가 반환하는 초기 HTML의 <body>가 비어 있는 경우가 많습니다. Googlebot은 JS를 실행하여 최종적으로 본문을 읽지만, GPTBot / ClaudeBot / PerplexityBot은 JS를 실행하는지 공식적으로 명시하지 않았습니다. 즉, "JS 실행 전의 HTML"에 본문이 없으면 AI 크롤러에게 본문이 전달되지 않을 가능성이 있습니다.
이 기사는 읽을거리가 아니라 구현입니다.
- AI 크롤러 관점에서 "초기 HTML에 본문이 있는지"를 판정하는 재사용 스크립트
- 이를 GitHub Actions에 통합하여, 본문이 사라지면 CI를 실패하게 함
- Next.js (App Router)에서 초기 HTML에 본문 및 JSON-LD를 확실하게 포함하는 작성법
배경 검증(왜 AI 크롤러가 의심스러운지, 3사의 공식 문서 비교)은 별도로 정리해 두었으므로 이론적인 부분은 그쪽을 참고해 주세요. 여기서는 코드에 집중하겠습니다.
"크롤러가 보는 초기 HTML"을 가져와서, <body>의 가시 텍스트 양과 H1의 유무를 판정합니다. User-Agent를 각 크롤러로 위장하는 것이 포인트입니다.
#!/usr/bin/env bash
# check-crawler-visibility.sh
# 사용법: ./check-crawler-visibility.sh https://example.com/ 500
...
CSR 방식의 SPA에 실행하면, 3사 모두 body_text가 수십 자, h1=no가 됩니다 (서버가 동일한 빈 HTML을 반환하기 때문). SSR/SSG라면 수천 자, h1=yes가 되어야 합니다.
$ ./check-crawler-visibility.sh https://your-spa.example/ 500
[Googlebot] body_text=38chars h1=no
⚠️ Googlebot 관점에서 보면 본문이 거의 비어 있습니다
...
curl이 보는 것은 JS 실행 전의 HTML입니다. 여기에 본문이 있는가 하는 문제는 "JS를 실행하지 않는 크롤러에게 본문이 전달되는가"와 거의 동의어가 됩니다.
리팩터링이나 라이브러리 업데이트로 인해 어느 날 갑자기 SSR이 깨져 CSR로 퇴행하는 경우가 있습니다. 배포 후의 운영 URL에 대해 체크를 돌리고, 초기 HTML에서 본문이 사라지면 CI를 실패하게 만듭니다.
# .github/workflows/crawler-visibility.yml
name: crawler-visibility
on:
...
set -euo pipefail과 exit "$fail" 덕분에 본문이 임계값 아래로 떨어지면 job이 빨간색(실패)으로 변합니다. "브라우저에서는 보이지만 운영 환경의 초기 HTML은 비어 있는" 퇴행 현상을 사람이 알아차리기 전에 감지할 수 있습니다.
대책은 간단합니다. "본문·제목·JSON-LD를 JS 실행 전의 HTML에 노출하는 것"뿐입니다. App Router라면 기본값이 서버 컴포넌트(Server Component)이므로, "use client"를 붙이지 않고 데이터 취득도 서버 측에서 완결시킵니다.
// app/articles/[slug]/page.tsx —— Server Component ("use client"를 붙이지 않음)
import type { Metadata } from "next"
export async function generateMetadata(
...
안티 패턴은 "본문을 Client Component의 useEffect 내에서 fetch하여 렌더링하는" 구성입니다. 이렇게 하면 초기 HTML이 비게 되고, curl로도 비어 있게 되어 = JS 비실행 크롤러에게 보이지 않게 됩니다. 인터랙션이 필요한 부분만 작은 Client Component로 분리하고, 본문 자체는 서버에서 내보내는 것이 안전합니다.
검증하고 싶다면, 빌드된 자신의 페이지에 1번의 스크립트를 실행하면 초기 HTML에 본문과 H1이 포함되어 있는지 즉시 알 수 있습니다.
- AI 크롤러의 JS 실행 여부는 공식적으로 불명. 초기 HTML에 본문이 없으면 전달되지 않을 가능성이 있음 -
curl -A
기본 스크립트를 통해 "크롤러 관점의 초기 HTML"을 판별할 수 있으며, 이를 CI에 통합하면 퇴행 (Regression)을 자동으로 감지할 수 있습니다. - 대책은 "본문·제목·JSON-LD를 SSR/SSG를 통해 초기 HTML에 포함하는 것"입니다. 이는 Google과 AI 모두에게 효과적입니다.
3개사 크롤러의 공식 성명 비교 및 CSR 사이트를 SEO 진단했을 때의 동작 등, 배경 검증 내용은 관측 리포트에 정리해 두었습니다.
자신의 사이트 초기 HTML을 한꺼번에 진단하고 싶다면, CodeQuest.work의 SEO 진단(URL 입력만으로 가능·등록 불필요·3회 무료)을 통해서도 동일한 관점에서 체크할 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기