IndexNow를 붙인 뒤, 효과를 단정하지 않은 이유

정적 블로그 배포 뒤 변경된 글 URL만 IndexNow에 알리도록 구현한 기록입니다. 변경 알림, 크롤링, 색인, 검색 유입을 분리해 적용 범위와 확인 방법을 정리했습니다.

정적 블로그에서 글이 바뀔 때마다 변경 URL을 검색엔진에 알리는 일은 작지만 반복된다. 이 저장소에는 sitemap이 이미 있었고, 배포 뒤 참여 검색엔진에 변경 사실을 보내는 작업만 자동화할 필요가 있었다.

그래서 .github/workflows/deploy.ymldeploy 다음에 indexnow 작업을 두고, scripts/submit-indexnow.mjs가 콘텐츠 파일의 diff를 읽도록 했다. URL 추출 규칙은 tests/indexnow.test.ts에 고정했다. 이 구현의 결과는 변경 URL을 전송하는 데서 끝난다. 크롤링, 색인, 순위, 클릭은 따로 관찰해야 한다.

이 글은 색인이 빨라졌다는 성과 보고서가 아니다. 실제로 재현할 수 있는 배포 순서, URL 추출 기준, 실패 정책을 남긴 운영 기록이다. 당시에는 검색엔진별 수신 결과와 색인까지 걸린 시간의 로그가 없었으므로 그 부분은 결론에 넣지 않았다.

구현 전에 분리한 네 단계

검색 유입을 한 덩어리로 보면 자동화의 효과를 과장하기 쉽다. 이 사이트에서는 발행 뒤의 흐름을 네 단계로 나눴다.

단계 여기서 확인할 질문 이 사이트의 처리
변경 알림 검색엔진이 새 URL 또는 수정 URL을 알 수 있는가 배포 후 변경된 글 URL을 IndexNow에 보낸다
발견·크롤링 bot이 실제 URL을 방문했는가 sitemap, 내부 링크, Search Console URL 검사를 함께 본다
색인 검색 결과 후보에 포함됐는가 Search Console의 색인 상태를 확인한다
노출·클릭 사용자가 검색 결과에서 봤고 클릭했는가 Performance 보고서에서 기간·페이지·검색어를 분리해 본다

IndexNow는 첫 줄에만 직접 관여한다. IndexNow 공식 문서도 추가·수정·삭제된 URL을 알리는 방식으로 설명하며, 제출한 URL이 자동으로 참여 검색엔진에 공유된다고 밝힌다. IndexNow FAQ는 URL 제출이 콘텐츠 변경을 알리지만 색인을 보장하지는 않는다고 명시한다. HTTP 200도 URL 목록을 받았다는 뜻이지, 크롤링이나 색인 완료를 뜻하지는 않는다.

Google도 같은 경계를 둔다. 재크롤링 요청 안내는 요청이 즉시 또는 반드시 검색 결과 포함으로 이어지지 않는다고 설명한다. 따라서 IndexNow를 넣은 뒤 “색인이 빨라졌다”고 말하려면, 적어도 같은 조건의 URL 여러 개에 대한 크롤링·색인 시점 기록이 있어야 한다. 지금은 그 자료가 없다.

배포가 끝난 뒤에만 보낸다

변경 알림은 배포 이전에 보내지 않았다. 빌드는 통과했지만 실제 발행이 실패할 수 있고, 아직 공개되지 않은 URL을 먼저 알릴 이유도 없기 때문이다.

배포 워크플로는 main 브랜치 push에서 검증, 배포, IndexNow 순서로 이어진다.

verify  →  deploy  →  indexnow

IndexNow 작업에는 needs: deploy가 있다. 즉 배포 작업이 끝난 다음에만 시작한다. 또 제출 단계는 continue-on-error: true로 설정했다.

indexnow:
  needs: deploy
  # ...
  - name: Submit changed URLs to IndexNow
    continue-on-error: true
    run: node scripts/submit-indexnow.mjs

이 선택에는 두 가지 이유가 있다.

첫째, IndexNow 제출은 발행의 필수 조건이 아니다. 제출 엔드포인트의 일시 장애, 네트워크 오류, 키 파일 탐색 실패가 글 배포 전체를 실패로 만들어서는 안 된다.

둘째, 실패를 숨기려는 설정도 아니다. GitHub Actions 작업 결과에는 실패가 남지만, 공개 사이트는 이미 배포된 상태로 유지한다. 검색엔진 변경 알림은 재시도할 수 있는 보조 작업이고, 독자가 URL을 열 수 있는 상태가 먼저다.

모든 URL을 매번 보내지 않았다

이 사이트의 제출 스크립트는 Git diff에서 콘텐츠 파일만 찾는다.

src/content/posts/ko/<slug>.md
src/content/posts/en/<slug>.md

이 경로가 수정·추가·이름 변경된 경우에만 해당 글의 공개 URL을 만든다. 한국어 글이 바뀌면 다음 URL도 함께 넣는다.

https://2dayapp.com/
https://2dayapp.com/ko/posts/
https://2dayapp.com/ko/posts/<slug>/

영어 글도 같은 방식으로 영어 홈과 목록 페이지, 해당 글 URL을 추가한다. 컴포넌트나 배포 워크플로만 바뀐 경우에는 URL을 보내지 않는다.

src/components/HomePage.astro       → 제출하지 않음
.github/workflows/deploy.yml        → 제출하지 않음
src/content/posts/ko/new-post.md    → 글·한국어 홈·목록 제출

이 규칙은 “사이트 파일이 바뀌면 전 URL을 다시 보내자”보다 좁다. IndexNow 문서가 추가·수정·삭제 URL을 알리는 프로토콜로 정의한 범위에 맞추고, 실제 독자용 콘텐츠가 달라진 경우에만 알림을 만들기 위해서다.

한 번의 제출은 최대 10,000개 URL로 제한했다. 현재 블로그 규모에는 한참 남는 한도지만, 대량 변경을 넣는 방향으로 무심코 넓어지는 것을 막는 장치다.

키는 코드가 아니라 공개 검증 파일에 둔다

IndexNow는 사이트 소유권을 확인할 키 파일을 같은 호스트에 두도록 요구한다. 여기서는 public/ 아래의 무작위 키 이름 .txt 파일을 빌드 결과의 루트에 그대로 배포한다.

스크립트는 파일명과 내용이 같은 8~128자 영숫자·하이픈 형식의 파일만 찾아 키로 쓴다. IndexNow는 검색엔진이 확인할 수 있는 공개 경로에 이 파일을 두도록 요구하고, 제출 요청에는 같은 키와 파일 위치를 보낸다.

이 키는 계정 비밀번호와 같은 종류는 아니지만, 해당 호스트의 변경 알림 요청을 확인하는 서비스별 검증 값이다. 다른 서비스의 비밀값을 재사용하지 않고, 문서·스크린샷·로그에 불필요하게 노출하지 않는 편이 안전하다. 특히 다른 종류의 API 키나 credential을 이 공개 파일 방식으로 저장하면 안 된다.

URL을 보내기 전에 자동 테스트로 경계를 고정했다

IndexNow 연동이 작아 보여도 URL 하나를 잘못 만들면 다른 호스트를 알리거나, 아직 없는 경로를 반복해서 제출할 수 있다. 그래서 구현과 함께 다음 동작을 테스트로 고정했다.

확인 항목 고정한 동작
키 파일 배포 루트에 파일명과 같은 내용의 키 파일이 있다
한국어·영어 콘텐츠 변경 글 URL과 해당 언어의 홈·글 목록 URL을 만든다
콘텐츠 외 변경 제출 URL 목록을 비운다
실행 순서 배포 완료 뒤 실행하고, 실패가 배포를 막지 않는다

여기에 한 가지 방어를 더 뒀다. 수동 URL을 넣는 경우에도 https이고 운영 도메인과 같은 호스트인 URL만 통과시킨다. 환경 변수 입력이 실수로 다른 도메인이나 평문 HTTP URL을 포함해도 그대로 엔드포인트에 보내지 않는다.

이 테스트가 IndexNow 수신이나 검색엔진 색인을 증명하지는 않는다. 대신 이 사이트가 어떤 URL을, 어느 시점에, 어떤 실패 정책으로 알리는지는 재현 가능하게 만든다.

Google을 위해 넣은 기능은 아니다

여기서 가장 쉽게 섞이는 부분이 있다. IndexNow global endpoint는 참여 검색엔진에 변경 알림을 공유할 수 있지만, Google Search의 재크롤링 요청 수단은 아니다. 현재 IndexNow 문서의 참여 엔드포인트 목록에는 Naver와 Bing, Yandex 등이 있고 Google은 없다. 따라서 이 자동화는 Naver·Bing 같은 참여 엔진을 위한 변경 알림이며, Google 대응을 대신하지 않는다.

Google에 새 글을 알리는 기본 경로는 여전히 크롤링 가능한 링크와 sitemap이다. Google은 sitemap이 URL 발견에 도움이 되지만 크롤링과 색인을 보장하지는 않는다고 설명한다. sitemap 개요크롤링 오류 점검 문서는 새 URL의 sitemap 반영, robots 확인, 표준 링크를 우선 안내한다.

그래서 이 사이트의 운영 기준은 다음과 같다.

Google 새 글 확인: sitemap · 내부 링크 · URL 검사
IndexNow: 참여 검색엔진에 변경 사실 알림
검색 성과 판단: Search Console의 노출 · 클릭 · 검색어

이 구분이 없으면 실행 로그 한 줄이나 HTTP 성공 응답을 보고 “SEO가 개선됐다”고 오해하게 된다. 제출 성공은 제출 성공일 뿐이다.

llms.txt처럼 AI 검색과 연결해 보이는 파일도 이 경계를 흐리기 쉽다. llms.txt는 Google AI Overviews에 필요할까?에서 정리했듯, 발견·색인·스니펫·학습·문서 안내는 서로 다른 문제다. Google 검색 성과는 Search Console에 노출은 잡히는데 클릭이 없을 때 볼 것처럼 노출·클릭·검색어를 따로 읽어야 한다.

나중에 효과를 평가하려면 무엇을 남겨야 하나

IndexNow 도입 효과를 정말 비교하려면 감상이 아니라 관측 설계가 필요하다. 다음 발행부터는 최소한 아래 값을 URL별로 남겨야 한다.

항목 기록할 값 왜 필요한가
발행 시각 배포가 완료된 UTC 시각 관측 시작점을 고정한다
알림 결과 제출 URL 수, HTTP 상태, 재시도 여부 알림 자체가 성공했는지 분리한다
sitemap 반영 sitemap의 URL과 lastmod Google 발견 경로가 같은지 확인한다
크롤링·색인 Search Console URL 검사 시점과 상태 알림과 실제 처리 사이를 구분한다
검색 성과 2주·4주 단위 노출, 클릭, 검색어 색인과 독자 반응을 섞지 않는다

비교할 때도 “IndexNow를 쓴 글”과 “안 쓴 글”을 한두 개씩 놓고 결론 내리면 안 된다. 글 주제, 내부 링크 수, 발행 시점, 기존 도메인 신호가 모두 다르기 때문이다. 가장 먼저 말할 수 있는 결론은 검색엔진별 알림 수신과 발견·색인까지 걸린 시간의 기록이고, 순위나 유입의 인과관계는 그보다 훨씬 높은 증거 기준이 필요하다.

이 자동화가 맞는 경우와 아닌 경우

상황 판단
정적 사이트에서 새 글·수정 글을 배포한다 변경 URL만 알리는 보조 자동화로 적합하다
검색엔진별 업데이트 상태를 운영 화면에서 따로 본다 알림과 결과를 분리하기 좋다
Google 색인을 당장 늘리고 싶다 IndexNow만 추가하지 말고 sitemap·robots·내부 링크·콘텐츠 품질부터 점검한다
모든 파일 변경을 검색 신호로 취급한다 URL 생성 규칙을 먼저 좁힌다
제출 성공을 SEO 성과로 보고 싶다 관측 기간과 비교 기준을 만든 뒤에 판단한다

작은 사이트에서 IndexNow는 거대한 SEO 전략이 아니다. 배포 후 “이 URL이 바뀌었다”는 사실을 참여 검색엔진에 전달하는 작은 운영 작업이다. 이 범위 안에서 두면 유용하다. 그 바깥의 크롤링, 색인, 클릭까지 대신해 줄 것처럼 두면 확인할 수 없는 효과를 약속하게 된다.

지금 말할 수 있는 범위

이번 구현에서 중요했던 것은 IndexNow endpoint를 호출한 사실보다 경계를 정한 방식이다. 배포가 성공한 뒤에만, 실제 콘텐츠가 바뀐 URL만 보내고, 알림 실패가 발행을 막지 않게 했다. 그리고 제출 성공을 색인이나 검색 유입의 증거로 쓰지 않았다.

다음으로 필요한 것은 기능을 더 붙이는 일이 아니라 발행·제출·크롤링·색인·노출을 같은 형식으로 기록하는 일이다. 그 기록이 쌓이면 IndexNow가 이 사이트에서 어느 검색엔진의 발견 속도에 도움이 됐는지 검토할 수 있다. 그전까지는 “변경 알림을 자동화했다”까지만 말하는 편이 정확하다.

구현에 사용한 문서