개발 slecs

사이트맵에서 결과 페이지 제외해 크롤 버짓 낭비 해소

목차

/r/ 경로의 결과 페이지를 사이트맵에서 제외하는 작업을 했다.

트리거는 간단했다. 누군가 SEO 감사를 돌렸고, 사이트맵에 noindex 태그가 붙은 페이지가 포함되어 있다는 게 걸렸다. 검색 엔진 입장에서 "이 페이지는 색인하지 마" 라고 해놓고 사이트맵에는 "이 페이지 있어요" 라고 제출하는 건 서로 모순된 신호다. Google Search Console 기준으로도 이건 명시적인 경고 항목이고, 장기적으로 크롤 버짓 낭비로 이어질 수 있다.

왜 사이트맵과 noindex가 충돌하면 안 되나

사이트맵은 크롤러에게 "여기 중요한 페이지 목록"을 전달하는 힌트다. 반면 noindex는 "이 페이지는 색인에 넣지 마"라는 명령이다. 둘이 동시에 걸려 있으면 크롤러는 일단 페이지를 방문하고, 방문해서 noindex를 확인한 다음에야 색인에서 제외한다. 즉 불필요한 크롤링이 발생하는 구조다.

규모가 작은 사이트라면 큰 문제가 아닐 수 있지만, 페이지 수가 늘어날수록 크롤 버짓 소모가 커진다. /r/ 하위의 결과 페이지가 동적으로 생성되는 구조라면 URL 패턴 수가 적지 않을 것이고, 그만큼 이 충돌의 파급도 컸다.

사이트맵 포함 + noindex = 크롤러 혼란 + 크롤 버짓 낭비
사이트맵 제외 + noindex = 의도 일치, 크롤러가 굳이 방문할 이유 없음
사이트맵 포함 + index  = 일반적인 색인 대상 페이지

이걸 정리하면 아래처럼 된다.

상태 사이트맵 포함 noindex 여부 권장 여부
색인 대상 ✅ 정상
색인 제외 의도 ❌ 충돌
색인 제외 의도 ✅ 일치
크롤 자체 차단 robots.txt 별도 판단 필요

astro.config.mjs 한 파일, 그래도 신경 쓴 이유

변경 파일이 astro.config.mjs 하나다. 라인 수도 명시되지 않았으니 아마 핀포인트 수정에 가까웠을 것이다. Astro의 사이트맵 통합(@astrojs/sitemap)은 기본적으로 빌드 시 전체 정적 경로를 수집해서 sitemap-index.xml을 생성한다. 특정 경로를 제외하려면 filter 옵션을 써야 한다.

// astro.config.mjs
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  integrations: [
    sitemap({
      filter: (page) => !page.includes('/r/'),
    }),
  ],
});

이런 형태로 /r/가 포함된 URL을 사이트맵 생성 단계에서 걸러내는 방식이다. 빌드 결과물에서 해당 URL이 아예 빠지니까, 이후 Search Console에 사이트맵을 재제출하면 충돌 경고도 해소된다.

작업 자체는 한 줄 수준의 변경이지만, 이걸 반영하지 않고 방치했을 때의 비용을 생각하면 우선순위를 올릴 이유는 충분했다.

회고

솔직히 이런 류의 SEO 정합성 이슈는 기능 개발에 치이다 보면 쉽게 후순위로 밀린다. "작동은 하잖아" 라는 인식이 팀 내에 깔리면, 사이트맵 충돌 같은 건 몇 달 묵히다가 Search Console 경고가 쌓인 다음에야 손대는 경우가 많다.

이번에 빠르게 처리할 수 있었던 건 SEO 감사를 주기적으로 돌리는 루틴이 있었기 때문이다. 자동화된 감사 결과가 티켓으로 들어오는 구조가 있으면 이런 이슈가 숙성되기 전에 잡힌다. 팀에 SEO를 전담하는 사람이 없더라도 이 정도 루틴은 가져가는 게 낫다.

그리고 noindex를 붙일 때는 사이트맵 필터링도 같이 챙기는 걸 체크리스트에 박아두는 편이 좋다. 둘은 항상 쌍으로 움직이는 설정이니까, 한쪽만 바꾸고 배포하는 실수를 구조적으로 막을 수 있다.


끝.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.