검색 색인 생성 자동화 - IndexNow

힘센캥거루
2025년 12월 11일(수정됨)
4
nextjs

Bing에 검색등록을 하다가 알게 되었는데, Bing에서는 IndexNow라는 기능을 제공한다.

핵심은 API 키를 이용해서 글을 쓰자마자 바로 색인 요청을 날릴 수 있다는 것.

검색 색인 생성 자동화 - IndexNow-1

아래와 같은 요청을 fetch로 만들고, 글쓰기에 연동해 놓으면 글을 DB에 저장함과 동시에 색인 생성 요청이 가능하다.

POST /IndexNow HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: api.indexnow.org
{
  "host": "www.example.org",
  "key": "f9ee84af58564dacb6bfe55d808a252c",
  "keyLocation": "https://www.example.org/f9ee84af58564dacb6bfe55d808a252c.txt",
  "urlList": [
      "https://www.example.org/url1",
      "https://www.example.org/folder/url2",
      "https://www.example.org/url3"
      ]
}

그래서 다른 사이트들의 API도 살펴보았더니 네이버와 구글에 api가 있었다.

네이버는 웹마스터가 indexNow를 지원하고 있었다.

host만 다를 뿐, 나머지 요소들은 모두 같았다.

그래서 IndexNow를 이용해보기로 했다.

검색 색인 생성 자동화 - IndexNow-2

1. IndexNow란?

검색 색인 생성 자동화 - IndexNow-3

기존 검색 방식은 검색엔진이 알아서 내 사이트를 크롤링 한 뒤 업데이트를 확인하고 인덱싱을 진행한다.

크롤링이 일어나지 않는다면 하염없이 기다리는 방법 뿐.

이 문제를 해결하기 위해 등장한 기술이 바로 IndexNow다.

검색 색인 생성 자동화 - IndexNow-4

사이트의 글을 생성, 삭제, 수정할 때 마다 서버에 push를 주는 것이다.

웹사이트가 직접 요청을 날리면, 검색엔진은 url을 색인하도록 예약을 건다.

2. 검색엔진 지원

현재 아래와 같은 검색엔진들이 IndexNow를 지원한다.

참고로 사이트마다 API 호스트가 조금씩 다르다.

검색 색인 생성 자동화 - IndexNow-5

네이버에서 안내하는 내용은 아래 링크를 확인해보자.

3. 구현방볍

1) Key 파일 생성

사이트 루트에 <key>.txt 파일을 놓아사이트 소유자를 인증한다.

이 메모장 안에는 key 문자열만 들어가야 한다.

https://example.com/1234567890ABCDEF.txt

2) URL 변경을 검색엔진에 전송

POST로 다음과 같은 JSON을 전달한다

검색엔진은 요청을 받으면 해당 URL들을 빠르게 재크롤링하도록 예약한다.

{
  "host": "example.com",
  "key": "1234567890ABCDEF",
  "keyLocation": "https://example.com/1234567890ABCDEF.txt",
  "urlList": [
    "https://example.com/post/123",
    "https://example.com/about"
  ]
}

4. Nextjs에서 이용하기

IndexNow에 대한 npm 라이브러리도 있지만, 코드 자체가 간단하기에 그냥 함수를 하나 만들어주기로 하자.

자기가 만들어도 괜찮은데, gpt나 claude 형님이 기깔나게 만든다.

별로 중요한거 아니니 그냥 만들어달라고 하고 정독이나 해보자.

type IndexNowPayload = {
  host: string;
  key: string;
  keyLocation: string;
  urlList: string[];
};

const INDEXNOW_ENDPOINT = "https://api.indexnow.org/indexnow"; // Bing/공용용

export async function submitToIndexNow(
  urls: string[],
  options?: {
    host?: string;
    key?: string;
    keyLocation?: string;
    endpoint?: string; // 필요하면 네이버용 endpoint 등으로 바꿔 쓰기
  }
): Promise<void> {
  if (!urls.length) return;

  const host =
    options?.host ??
    process.env.INDEXNOW_HOST ?? // 예: "earthscience.kr"
    new URL(urls[0]).host;

  const key = options?.key ?? process.env.INDEXNOW_KEY;
  const keyLocation =
    options?.keyLocation ??
    process.env.INDEXNOW_KEY_LOCATION ?? // 예: "https://earthscience.kr/1234567890ABCDEF.txt"
    `https://${host}/${key}.txt`;

  const endpoint = options?.endpoint ?? INDEXNOW_ENDPOINT;

  if (!key) {
    throw new Error("IndexNow key가 설정되지 않았습니다. 환경변수 INDEXNOW_KEY를 확인하세요.");
  }

  const payload: IndexNowPayload = {
    host,
    key,
    keyLocation,
    urlList: urls,
  };

  const res = await fetch(endpoint, {
    method: "POST",
    headers: {
      "Content-Type": "application/json; charset=utf-8",
    },
    body: JSON.stringify(payload),
  });

  if (!res.ok) {
    const text = await res.text().catch(() => "");
    throw new Error(
      `IndexNow 요청 실패: ${res.status} ${res.statusText} ${text ? `- ${text}` : ""}`
    );
  }
}

참고로 네이버는 앤드포인트가 다르니, 네이버까지 해주려면 2번의 fetch를 해주어야 한다.

이제 이걸 글쓰기, 글수정, 글삭제 api에다가 살포시 얹어주면 된다.

export async function Post(request: NextRequest){
    
	...

    const post = await createPost({
      title,
      excerpt: excerpt || "",
      content,
      category: category || "기타",
      categoryId: categoryId || null,
      thumbnail: thumbnail || null,
      published: published || false,
    });

    // IndexNow에 새 글 알림 (published인 경우만)
    if (post.published && post.slug) {
      try {
        const postUrl = `${process.env.NEXT_PUBLIC_URL}/post/${post.slug}`;
        await submitToIndexNow([postUrl]);
        console.log('IndexNow 제출 성공:', postUrl);
      } catch (indexError) {
        console.error('IndexNow 제출 실패:', indexError);
        // IndexNow 실패해도 글 발행은 성공으로 처리
      }
    }
	
	...

}

5. trouble shooting

bing에서는 등록이 잘 되는데, 네이버는 등록이 잘 안되는 현상이 생겼다.

검색해보니, 네이버는 host를 넣을 때 https:// 를 제외하고 해야 하는 것.

아래와 같은 과정을 통해 실제 호스트만 뽑아내야 한다.

options?.origin ??
process.env.NEXT_PUBLIC_URL ?? // 보통 https://도메인
new URL(urls[0]).origin;

const originUrl = new URL(origin);
const host = options?.host ?? originUrl.host; // ✅ 도메인만

예를들어 아래와 같이 바꿔줘야 함.

{
  "host": "https://earthscience.kr"  // 422 오류 발생!
  "host": "earthscience.kr"		 // 이건 통과함
}

6. 후기

검색 색인 생성 자동화 - IndexNow-6

지금 쓰고 있는 글을 테스트용으로 한번 발행, 수정해 보니 잘 작동하는 듯 하다.

앞으로는 bing이나 naver는 따로 들어갈 필요 없이 자동으로 크롤링이 된다고 생각하니 한결 편하다.

한동안 어떻게 작동하는지 지켜봐야겠다.

댓글을 불러오는 중...