홍은표 · 넥스트티 대표 · SEO/GEO 컨설턴트 | 작성 2026-05-26
DEFINITION · 한 문장 정의
JavaScript SEO는 JS로 만들어진 페이지가 검색·AI 봇에게 어떻게 보이는지를 설계하는 일입니다. 같은 페이지라도 서버가 보낸 raw HTML과 JS 실행 후 DOM이 크게 다를 수 있으므로, 어떤 봇이 어떤 단계까지 보는지에 맞춰 렌더링 전략을 잡아야 합니다.
1분 요약 · KEY TAKEAWAYS
4 MODELS
서버는 거의 빈 HTML, 브라우저에서 JS가 콘텐츠를 그림. 대시보드·관리자에 적합. 공개 SEO엔 위험.
SEO/GEO 위험매 요청마다 서버가 최종 HTML 생성. 동적·개인화 콘텐츠에 강함. 봇이 JS 실행 없이도 콘텐츠를 본다.
SEO/GEO 안전빌드 시 HTML을 미리 생성. 정적 콘텐츠(블로그·랜딩)에 가장 빠르고 안전. CDN과 궁합 우수.
SEO/GEO 최적SSG + 주기적 재생성. 자주 갱신되는 정적 페이지(상품 목록·뉴스)에 적합. SSG의 안전성을 유지하며 동적성 확보.
SEO/GEO 안전BEYOND THE 4 BASICS · 2026 신규 패턴
위 4모델이 토대지만, 2024~2026년에 들어온 신규 패턴 3가지가 *SEO·GEO에 추가 옵션*을 제공합니다.
세 패턴 모두 서버 응답 HTML에 핵심을 담는다는 원칙은 그대로. 새 도구가 늘었을 뿐, 봇 시야의 안전 기준은 변하지 않습니다.
프레임워크 선택보다 페이지별 렌더링 모드가 더 중요합니다. Next.js·Nuxt·SvelteKit 모두 4가지 모드를 페이지 단위로 선택할 수 있습니다. 같은 사이트 안에서 마케팅 페이지는 SSG, 블로그는 ISR, 사용자 대시보드는 CSR로 나누는 것이 합리적입니다.
FLOW · 봇 관점에서
BOTS · JS 처리 능력 비교
| 봇 | 소유 | JS 렌더 | 실무 함의 |
|---|---|---|---|
Googlebot |
YES | Chromium 기반. 다만 2단계 렌더 큐로 지연 가능 — 무거운 JS는 SSR 권장 | |
Bingbot |
Microsoft | YES | 2018년부터 풀 JS 렌더링 공식 지원. Googlebot과 마찬가지로 무거운 JS는 SSR 권장 |
OAI-SearchBot / ChatGPT-User |
OpenAI | RAW 일반적 | 답변 시점 fetch — raw HTML로 봐도 콘텐츠가 보여야 안전 |
GPTBot |
OpenAI | RAW 일반적 | 학습 크롤 — JS 의존 페이지는 학습 데이터에서 누락 위험 |
Claude-User / ClaudeBot |
Anthropic | RAW 일반적 | raw HTML 기반이 일반적 — JSON-LD는 서버 응답에 포함 필수 |
PerplexityBot / Perplexity-User |
Perplexity | RAW 일반적 | 답변 인용 직결 — SSR/SSG로 첫 응답에 본문 노출 |
주의 — 각 사 정책·동작은 변할 수 있으므로 공식 문서로 주기적 확인이 권장됩니다. 표는 2026-05 시점 일반적 동작을 기준으로 작성됐습니다.
SOURCES — Google JavaScript SEO basics · OpenAI bots (GPTBot · OAI-SearchBot · ChatGPT-User) · Anthropic / Perplexity는 각 사 공식 docs 참고. AI 봇 분류·정책은 3종 크롤 거버넌스에서 정리합니다.
PATTERNS · 실제로 어디서 끊기나
"CSR이 위험하다"는 추상적 경고가 아니라, 실제 한국 사이트에서 자주 보이는 구체적인 누락 패턴 3가지를 정리합니다. 각 패턴마다 어떤 코드 구조 때문에 발생하는지·서버 응답에 포함되도록 어떻게 고치는지를 함께 봅니다.
운영 관점에서 — 클라이언트 사이트를 점검하다 보면 이 세 패턴은 거의 짝지어 나타납니다. 한 사이트만 봐도 셋 중 두 개는 동시에 발견되는 경우가 많고, 특히 Next.js·Nuxt 기반 한국 사이트에서는 JSON-LD JS 주입 패턴(아래 PATTERN 01)이 가장 빈번합니다. 그래서 단일 패턴만 고치기보다 서버 응답 HTML에 반드시 들어가야 하는 신호 목록을 한 번에 점검하는 편이 효율적입니다.
현상 — view-source로 본 HTML에 <script type="application/ld+json">가 비어 있거나 아예 없는데, DevTools Elements 탭에선 보입니다. react-helmet·next/head·vue-meta 같은 메타 관리 라이브러리가 클라이언트에서 DOM에 끼워 넣는 패턴.
왜 위험한가 — 구글 봇은 렌더 후 인식할 가능성이 있지만 지연·실패 위험이 있고, 대부분의 AI 봇은 raw 단계만 보므로 JSON-LD가 없는 페이지로 인식됩니다. 리치 결과·답변 인용 노출이 동시에 손실됩니다.
// ❌ 위험 — 클라이언트에서 주입 <Head> <script type="application/ld+json">{...}</script> </Head> // ✅ 안전 — 서버 응답 HTML에 raw로 출력 // Next.js: getServerSideProps · getStaticProps에서 props로 전달 후 // 페이지 컴포넌트 최상위에서 <script> dangerouslySetInnerHTML // Nuxt: asyncData/setup head 함수에서 정적 출력 // 또는 prerender / SSG 빌드 단계에서 정적 HTML로 굳히기
현상 — raw HTML이 <div id="root"></div> 정도만 들어있고 본문 글자 수가 거의 0. 데이터 fetch가 클라이언트에서만 일어나는 전형적 CSR 구조입니다.
왜 위험한가 — 봇이 본문 자체를 보지 못합니다. "이 페이지는 무엇에 관한가"를 판단할 텍스트 신호가 없으므로 색인 품질이 떨어지고, AI 답변에는 거의 잡히지 않습니다.
// ❌ 위험 — useEffect로 클라이언트에서만 데이터 fetch function Page() { const [post, setPost] = useState(null); useEffect(() => { fetch('/api/post').then(...) }, []); return <article>{post?.body}</article>; } // ✅ 안전 — 서버에서 데이터 주입 (Next.js App Router 예) export async function Page({ params }) { const post = await fetchPost(params.slug); // 서버에서 실행 return <article>{post.body}</article>; // 첫 응답에 본문 포함 }
<button>으로만 구현됐다현상 — "다음 페이지"·"카테고리 필터"가 <button onClick>으로 작동. 브라우저에선 작동하지만 raw HTML에 <a href="...">가 없어 봇이 다음 페이지로 따라갈 경로를 발견하지 못합니다.
왜 위험한가 — 같은 도메인 안 수천 개 페이지가 봇 입장에선 "고아 페이지"가 됩니다. 사이트맵에 등록해도 발견은 되지만, 내부 링크 신호가 없어 권위 분배가 안 됩니다.
// ❌ 위험 — 클릭 핸들러로만 이동 <button onClick={() => router.push('/posts/page/2')}>다음</button> // ✅ 안전 — 실제 href 출력 (Next.js Link · React Router Link 모두 internally 생성) <Link href="/posts/page/2">다음</Link> // → 렌더 결과: <a href="/posts/page/2">다음</a> (봇이 따라갈 수 있음)
세 패턴 모두 "JS를 쓰지 말자"가 아니라 "서버 응답 HTML에 핵심 신호가 들어가야 한다"는 같은 원칙으로 풀립니다. JS는 인터랙티브 강화·hydration 용도로 그대로 두되, 봇이 raw HTML 한 번만 봐도 페이지의 핵심을 파악할 수 있는 구조로 빌드 단계를 짜는 것이 핵심입니다.
우리 페이지는 raw HTML에 JSON-LD·본문·링크가 모두 들어 있는가?
브라우저에서 Ctrl+U(페이지 소스 보기)로 1분 안에 확인 가능합니다.
DIAGNOSE · 4 STEPS
브라우저에서 페이지를 열고 Ctrl+U(또는 우클릭 → 페이지 소스 보기). 여기 보이는 HTML이 서버가 봇에게 첫 응답으로 보낸 것입니다. 본문 텍스트·메타 태그·JSON-LD가 여기 보이는지 확인.
DevTools의 Elements 탭은 JS 실행이 끝난 뒤의 DOM입니다. STEP 01과 비교했을 때 본문·JSON-LD가 여기에만 있다면 그 콘텐츠는 JS 의존입니다.
터미널에서 curl -A "Mozilla/5.0" https://your-site.com을 실행해 본문·JSON-LD가 응답에 포함되어 있는지 확인. 대부분의 AI 봇은 이 단계만 보는 것에 가깝다는 가정이 안전합니다.
Puppeteer·Playwright 같은 헤드리스 브라우저로 같은 URL을 렌더해 결과 HTML을 저장합니다. STEP 03의 raw 응답과 길이·JSON-LD 개수·핵심 텍스트를 비교하면 그 격차가 곧 AI 봇이 놓치는 콘텐츠의 양입니다. diff 도구로 자동 비교하거나 글자 수만 빠르게 봐도 충분합니다.
FIELD DIAGNOSIS · 진단 현장에서 본 것
앞서 정리한 3패턴이 *코드 레벨 안티패턴*이라면, 아래는 실제 진단 현장에서 가장 자주 마주치는 사이트 레벨 증상입니다.
JS 프레임워크로 만든 한국 사이트를 점검할 때 거의 매번 보입니다.
CASE 01 · 가장 흔함
react-helmet·next/head 같은 헤드 관리 라이브러리가 클라이언트에서만 동작하도록 짜인 패턴. view-source로 열면 <title>·메타 디스크립션·JSON-LD가 다 비어 있고, DevTools Elements 탭에서만 채워져 있습니다.
증상 — 구글 색인은 가끔 잡히지만 AI 답변 인용은 거의 안 됨. 같은 페이지가 ChatGPT·Claude 답변에 안 잡히는 가장 흔한 이유.
CASE 02 · 검색 결과 페이지
상품 카테고리·블로그 태그·검색 결과 페이지에서 응답 HTML이 <div id="root"></div> 수준이고 본문 텍스트가 거의 0. 데이터 fetch가 클라이언트에서만 일어나는 전형 패턴.
증상 — 가장 트래픽이 들어와야 할 *결과 페이지군*이 전부 빈 페이지처럼 인식되어 색인 품질이 떨어짐. 이커머스에서 가장 비싼 실수.
CASE 03 · 무한 스크롤·필터
"다음 페이지"·카테고리 필터·정렬이 전부 <button onClick>으로만 동작. 같은 도메인 안에 수천 개 상품 페이지가 있어도 봇 입장에선 첫 페이지 외에는 발견 경로가 없습니다.
증상 — sitemap.xml로 알려줘도 내부 링크 신호가 없어 권위가 안 흐름. 카테고리 페이지만 인식되고 하위 상세 페이지는 정체.
원칙 — JS 프레임워크 사이트는 *기능은 화려한데 봇 시야에선 빈 페이지*인 경우가 많습니다. 진단의 출발점은 항상 view-source 한 번 — 본문·메타·JSON-LD가 거기 있는가입니다.
FAQ
DIAGNOSE · JS VISIBILITY
CSR 의존도 진단 · JSON-LD 서버 응답 포함 점검 · href 라우팅 정합 · 페이지 유형별 렌더링 전략 설계.
넥스트티가 사이트 구조와 빌드 단계를 점검해 봇 가시성에 맞춘 우선순위를 정리해드립니다.