Google Search Console 0/119 미색인 복구 — 자동 모니터와 실제 진단 과정

@JavaPark · 2026년 4월 22일 · 25 min read · 👁 23

2026년 8월 14일, 블로그의 URL Inspection API 결과를 다시 수집했습니다. 결과는 119개 중 색인 0개였습니다.

이번에는 단순히 "색인이 안 된다"에서 멈추지 않고 상태를 세 그룹으로 나눠 확인했습니다.

Search Console 상태 URL 수
발견됨 - 현재 색인이 생성되지 않음 81
Google에는 아직 알려지지 않은 URL 30
크롤링됨 - 현재 색인이 생성되지 않음 8
색인됨 0

여기서 중요한 사실은 오류가 0개이고 canonical 불일치도 0개였다는 점입니다. Googlebot이 실제로 가져간 페이지는 응답에 성공했고, robots.txt와 noindex에도 막히지 않았습니다. 기술적으로 접근할 수 있다는 사실과 Google이 색인을 선택한다는 사실은 별개였습니다.

이 글은 2026년 4월에 만들었던 자동 모니터 구축기에, 4개월 뒤 실제로 발생한 모니터 중단과 0/119 미색인 복구 과정을 추가한 기록입니다. 결과가 좋아 보이는 부분만 남기지 않고, 무엇이 실패했고 어떤 신호까지 회복됐는지 그대로 정리합니다.


왜 "자동 모니터링"인가 — 수동 GSC의 한계

Google Search Console을 수동으로 여는 방식은 몇 가지 치명적 한계가 있습니다.

수동 체크의 한계 영향
자발적 로그인이 필요 바쁘면 2~3주씩 안 들어감
전체 URL 일괄 조회가 불편 보통 문제 있는 URL 하나 찍어서 확인, 나머지는 모른 채
알림 기능이 제한적 이메일 알림은 큰 이슈만, "천천히 밀린 인덱싱"은 놓침
추이 추적이 어려움 지난달 대비 인덱싱 비율 변화 같은 건 수동 기록해야 함
여러 속성 관리가 번거로움 블로그·쇼핑몰·랜딩 각각 따로 체크

자동화의 핵심: "없어도 되는 작업"은 자동화하고, 사람은 결과만 확인하는 흐름으로 전환.


전체 아키텍처 — 주간 5단계 파이프라인

시스템의 흐름은 단순합니다.

[GitHub Actions cron]
         ↓
  1. sitemap-index.xml fetch → URL 전체 추출
         ↓
  2. URL마다 GSC URL Inspection API 호출 (서비스 계정 인증)
         ↓
  3. 이전 상태(data/indexing-status.json)와 diff 계산
         ↓
  4. 변화가 있으면 Telegram HTML 메시지 전송
         ↓
  5. 새 상태를 JSON에 저장하고 자동 커밋

각 단계는 독립된 모듈로 분리해서, 하나만 바꿔도 나머지에 영향 없게 설계합니다.

GSC 인덱싱 모니터 주간 5단계 파이프라인 — sitemap fetch → URL Inspection API → Diff → Telegram → 자동 커밋
GSC 인덱싱 모니터 주간 5단계 파이프라인 — sitemap fetch → URL Inspection API → Diff → Telegram → 자동 커밋


2026년 8월 실제 복구 — 성공한 워크플로가 색인 성공은 아니다

1. 먼저 크롤링 차단 여부를 분리했다

원인을 추측하기 전에 다음 항목을 실제 응답과 Search Console에서 확인했습니다.

  • robots.txt에서 Googlebot을 차단하지 않는가
  • 페이지가 HTTP 200으로 응답하는가
  • HTML에 noindex가 없는가
  • 페이지 canonical이 자기 자신을 가리키는가
  • sitemap에 canonical과 동일한 URL이 들어 있는가
  • Search Console 수동 라이브 테스트에서 색인 가능 판정이 나오는가

대표 글인 /helm-package-management/는 Googlebot 스마트폰으로 가져오기 성공, 크롤링 허용, 색인 허용, self-canonical까지 모두 확인됐습니다. 그런데도 상태는 크롤링됨 - 현재 색인이 생성되지 않음이었습니다. 이 시점부터 서버 장애보다 Google의 색인 선택과 사이트 신호를 봐야 한다고 판단했습니다.

2. live sitemap과 Search Console의 기록이 달랐다

실제 sitemap-0.xml에는 119개 URL이 있었지만 Search Console에는 과거에 읽은 75개가 표시되고 있었습니다. 제출 기록도 몇 달 전 상태에 머물러 있었습니다.

따라서 다음 순서로 처리했습니다.

  1. 배포 산출물에서 sitemap URL 119개와 canonical을 대조했습니다.
  2. 쿼리 문자열이 붙은 canonical과 trailing slash 불일치를 정규화했습니다.
  3. 홈을 canonical로 가리키던 404 페이지를 /404/ + noindex로 분리했습니다.
  4. 수정 사항을 배포한 뒤 실제 HTML 응답을 다시 확인했습니다.
  5. Search Console에 sitemap-0.xml을 재제출했습니다.

사이트 구조 수정과 함께 Gatsby SEO 최적화Netlify 마이그레이션 기록도 다시 점검했습니다. 도메인·배포 플랫폼을 바꾼 적이 있다면 과거 sitemap 제출 성공 기록만 믿지 말고 현재 live URL과 다시 비교하는 편이 안전합니다.

3. 자동 모니터는 인증 정보 누락으로 멈춰 있었다

주간 모니터가 몇 달 동안 실패한 직접 원인은 GitHub Actions의 GSC_SERVICE_ACCOUNT_KEY 누락이었습니다. 실패 로그가 의존성 설치 뒤에야 나타나 원인을 찾기도 불편했습니다.

이번에는 워크플로 시작 단계에서 필수 Secret을 먼저 검사하고, 서비스 계정 키를 JSON 원문과 Base64 두 형식으로 모두 읽도록 변경했습니다. package-lock.json도 추가하고 설치 명령을 npm ci로 바꿔 실행 환경을 고정했습니다.

- name: Check required GSC credential
  env:
    GSC_SERVICE_ACCOUNT_KEY: ${{ secrets.GSC_SERVICE_ACCOUNT_KEY }}
  run: |
    if [ -z "$GSC_SERVICE_ACCOUNT_KEY" ]; then
      echo "::error title=Missing GSC credential::Add GSC_SERVICE_ACCOUNT_KEY"
      exit 1
    fi

- name: Install dependencies
  working-directory: scripts/gsc-monitor
  run: npm ci --no-audit --no-fund

4. 우선 URL 5개는 같은 날 다시 크롤링됐다

sitemap 재제출 후 다음 URL 5개만 우선순위 크롤링 대기열에 넣었습니다.

  • Paseo 코딩 에이전트 오케스트레이션
  • Meta Astryx 디자인 시스템
  • VS Code 로컬 LLM
  • Helm 패키지 관리

그날 다시 실행한 모니터에서 다섯 URL 모두 최근 크롤링 시간이 생겼고 페이지 가져오기는 성공했습니다. 홈과 대표 글은 canonical도 동일하게 잡혔습니다. 하지만 색인 수는 여전히 0이었습니다.

이 결과가 이번 진단의 핵심입니다.

색인 요청 성공은 크롤링 대기열에 들어갔다는 뜻이지, 검색 노출을 보장한다는 뜻이 아닙니다.

이후에는 같은 URL을 반복 제출하지 않고, 주간 모니터에서 indexed, newlyIndexed, stillPending 변화를 관찰하기로 했습니다. 동시에 크롤링됐지만 미색인된 글부터 직접 경험, 내부 링크, 중복 도입부를 보강하는 쪽으로 작업 우선순위를 바꿨습니다.


사전 준비 3종 — 총 20분

1) GCP 서비스 계정 (15분)

  1. Google Cloud Console에서 프로젝트 생성 (예: gsc-monitor)
  2. APIs & Services → Library → Google Search Console API 활성화
  3. IAM & Admin → Service Accounts → 서비스 계정 생성 (역할 없이도 OK)
  4. 서비스 계정 → Keys 탭 → Add Key → JSON → 다운로드
  5. 다운로드한 JSON을 GitHub Secret GSC_SERVICE_ACCOUNT_KEY전체 내용 붙여넣기

2) Search Console 권한 부여 (2분)

  1. Search Console → 대상 속성 선택
  2. Settings → Users and permissions → Add User
  3. 서비스 계정 이메일(xxx@yyy.iam.gserviceaccount.com) 추가, Restricted 권한이면 충분

3) Telegram Bot (3분)

  1. Telegram @BotFather에게 /newbot → HTTP API Token 수신 → TELEGRAM_BOT_TOKEN
  2. 생성한 봇에게 /start 아무 메시지 (봇이 먼저 말 못 걸기 때문)
  3. @userinfobot/start → 본인 chat_id → TELEGRAM_CHAT_ID

코드 구조 — 4개 모듈로 분리

scripts/gsc-monitor/
├── package.json              # googleapis + fast-xml-parser
├── run.js                    # 오케스트레이션 (40줄)
└── lib/
    ├── sitemap.js            # sitemap-index → URL 배열
    ├── gsc.js                # URL Inspection API 호출
    ├── diff.js               # 이전 결과와 비교, 요약 계산
    └── telegram.js           # HTML 메시지 빌더 + 전송

.github/workflows/gsc-monitor.yml    # cron + workflow_dispatch
data/indexing-status.json            # 상태 스냅샷 (봇이 자동 커밋)

lib/sitemap.js — sitemap-index 파싱

import { XMLParser } from "fast-xml-parser"

const parser = new XMLParser({ ignoreAttributes: false })

async function fetchXml(url) {
  const res = await fetch(url, { headers: { "User-Agent": "gsc-monitor/1.0" } })
  if (!res.ok) throw new Error(`${url} → HTTP ${res.status}`)
  return parser.parse(await res.text())
}

export async function extractAllUrls(indexUrl) {
  const index = await fetchXml(indexUrl)
  const children = [].concat(index.sitemapindex?.sitemap ?? [])
  const urlSets =
    children.length > 0
      ? await Promise.all(children.map(s => fetchXml(s.loc)))
      : [index]
  const urls = new Set()
  for (const doc of urlSets) {
    for (const entry of [].concat(doc.urlset?.url ?? [])) {
      if (entry.loc) urls.add(entry.loc)
    }
  }
  return Array.from(urls)
}

lib/gsc.js — URL Inspection API

핵심은 urlInspection.index.inspect 호출.

import { google } from "googleapis"

export function createClient(serviceAccountKey) {
  const raw = serviceAccountKey.trim()
  let credentials

  try {
    credentials = JSON.parse(raw)
  } catch {
    credentials = JSON.parse(Buffer.from(raw, "base64").toString("utf-8"))
  }

  const auth = new google.auth.GoogleAuth({
    credentials,
    scopes: ["https://www.googleapis.com/auth/webmasters.readonly"],
  })
  return google.searchconsole({ version: "v1", auth })
}

export async function inspectUrl(client, { siteUrl, inspectionUrl }) {
  const res = await client.urlInspection.index.inspect({
    requestBody: { siteUrl, inspectionUrl, languageCode: "ko" },
  })
  const idx = res.data.inspectionResult?.indexStatusResult ?? {}
  return {
    url: inspectionUrl,
    verdict: idx.verdict,
    coverageState: idx.coverageState,
    lastCrawlTime: idx.lastCrawlTime,
    googleCanonical: idx.googleCanonical,
    userCanonical: idx.userCanonical,
  }
}

중요: siteUrl 형식이 속성 유형에 따라 다릅니다.

  • Domain property: sc-domain:blog.javapark.kr (권장, 하위 모든 경로 자동 커버)
  • URL prefix property: https://blog.javapark.kr/ (프로토콜·www 구분됨)

lib/diff.js — 변화 감지

단순하지만 핵심 로직. 이전 실행의 URL별 상태와 비교해서 새로 인덱싱된 것, 인덱스에서 제거된 것, canonical 불일치를 찾습니다.

const INDEXED_STATES = new Set([
  "Submitted and indexed",
  "Indexed, not submitted in sitemap",
])

export function diffResults(previous = [], current = []) {
  const prev = new Map(previous.map(r => [r.url, r]))
  const newlyIndexed = []
  const newlyDeindexed = []
  const canonicalMismatch = []

  for (const curr of current) {
    const prevEntry = prev.get(curr.url)
    const currIndexed = INDEXED_STATES.has(curr.coverageState ?? "")
    const prevIndexed = prevEntry
      ? INDEXED_STATES.has(prevEntry.coverageState ?? "")
      : false

    if (currIndexed && !prevIndexed) newlyIndexed.push(curr)
    if (!currIndexed && prevIndexed) newlyDeindexed.push(curr)
    if (
      curr.googleCanonical &&
      curr.userCanonical &&
      curr.googleCanonical !== curr.userCanonical
    )
      canonicalMismatch.push(curr)
  }

  const indexed = current.filter(c =>
    INDEXED_STATES.has(c.coverageState ?? "")
  ).length
  return {
    newlyIndexed,
    newlyDeindexed,
    canonicalMismatch,
    total: current.length,
    indexed,
    rate:
      current.length === 0
        ? 0
        : Math.round((indexed / current.length) * 1000) / 10,
  }
}

lib/telegram.js — HTML 메시지

Telegram은 제한적 HTML을 지원합니다. <b>, <i>, <code>, <a> 정도.

export async function sendTelegram(token, chatId, text) {
  const url = `https://api.telegram.org/bot${token}/sendMessage`
  const res = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      chat_id: chatId,
      text,
      parse_mode: "HTML",
      disable_web_page_preview: true,
    }),
  })
  if (!res.ok) throw new Error(`Telegram ${res.status}: ${await res.text()}`)
}

GitHub Actions 워크플로우

cron으로 주간 실행 + 수동 트리거(workflow_dispatch) 지원.

name: GSC Indexing Monitor

on:
  schedule:
    - cron: "0 0 * * 1" # 매주 월요일 00:00 UTC (09:00 KST)
  workflow_dispatch:
    inputs:
      force_notify:
        description: "변경 없어도 Telegram 알림 전송"
        default: "false"
        type: choice
        options: ["false", "true"]

permissions:
  contents: write

jobs:
  monitor:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: "20" }

      - name: Check credential
        env:
          GSC_SERVICE_ACCOUNT_KEY: ${{ secrets.GSC_SERVICE_ACCOUNT_KEY }}
        run: test -n "$GSC_SERVICE_ACCOUNT_KEY"

      - name: Install
        working-directory: scripts/gsc-monitor
        run: npm ci --no-audit --no-fund

      - name: Run
        working-directory: scripts/gsc-monitor
        env:
          GSC_SERVICE_ACCOUNT_KEY: ${{ secrets.GSC_SERVICE_ACCOUNT_KEY }}
          TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
          TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
          GSC_SITE_URL: sc-domain:blog.javapark.kr
          SITE_ORIGIN: https://blog.javapark.kr
          FORCE_NOTIFY: ${{ inputs.force_notify }}
        run: node run.js

      - name: Commit status
        run: |
          git config user.name "gsc-monitor-bot"
          git config user.email "bot@users.noreply.github.com"
          git add data/indexing-status.json
          if git diff --staged --quiet; then
            echo "No changes"
          else
            git commit -m "chore(gsc): update $(date -u +%Y-%m-%d)"
            git push
          fi

2026년 4월 첫 실행 결과 — 57/0 사태

준비가 끝나고 수동 트리거로 첫 실행을 돌렸습니다. data/indexing-status.json에 저장된 결과:

{
  "generatedAt": "2026-04-20T16:06:00.795Z",
  "siteUrl": "sc-domain:blog.javapark.kr",
  "summary": {
    "total": 57,
    "indexed": 0,
    "rate": 0,
    "stillPending": 57
  }
}

57개 URL 전부 다음과 같은 상태:

{
  "verdict": "NEUTRAL",
  "coverageState": "Google에는 아직 알려지지 않은 URL입니다.",
  "indexingState": "INDEXING_STATE_UNSPECIFIED",
  "lastCrawlTime": null,
  "googleCanonical": null
}

충격이었습니다. 모니터링을 만들지 않았으면 이 상태를 몇 달 더 모른 채 글을 계속 올리고 있었을 겁니다.

이 상태의 의미

"Google에는 아직 알려지지 않은 URL입니다"는 구글 봇이 한 번도 이 URL을 방문하지 않았다는 뜻입니다. 이게 광범위하게 발생하면 보통 다음 4가지 중 하나입니다.

원인 후보 진단 방법
① sitemap이 GSC에 제출되지 않음 GSC → Sitemaps 메뉴에서 sitemap-index.xml 수동 등록 여부 확인
② 속성이 최근 추가되었고 아직 크롤링 미실행 GSC 속성 "추가 일자" 확인. 2주 이내면 정상 — 기다림
**③ 사이트가 최근 마이그레이션됨 도메인 변경, 플랫폼 이관(GitHub Pages → Netlify 등) 후 새 도메인의 크롤링 히스토리 부족**
④ robots.txt가 광범위 차단 https://blog.javapark.kr/robots.txt 확인. Disallow: /가 있으면 전면 차단

제 경우는 ①과 ③의 조합이었습니다.

  • 최근 javapark.github.ioblog.javapark.kr 도메인으로 Netlify 이관
  • 새 도메인 속성을 GSC에 추가는 했지만 sitemap 제출은 안 함

첫 실행 0/57 인덱싱 결과와 원인 진단 매트릭스 — sitemap 미제출·속성 신규·도메인 이관·robots.txt 4가지 후보
첫 실행 0/57 인덱싱 결과와 원인 진단 매트릭스 — sitemap 미제출·속성 신규·도메인 이관·robots.txt 4가지 후보

해결 순서

  1. robots.txtDisallow: / 없는지 확인 → 통과 (문제 없음)
  2. GSC에서 Sitemaps 메뉴 → https://blog.javapark.kr/sitemap-index.xml 수동 제출
  3. 주요 페이지 5~10개 선택해서 URL 검사색인 생성 요청
  4. 1~2주 기다리면서 이 모니터의 주간 리포트로 인덱싱 진행률 추적

모니터가 없었다면 이 진단 자체가 시작되지 않았을 겁니다. 자동화의 진짜 가치는 여기 있습니다.


Telegram 메시지 실제 모습

변화 발생 시 오는 메시지 예시:

🔔 GSC Indexing Monitor
2026-04-28 · https://blog.javapark.kr

✅ 신규 인덱싱: 3건
  • /devops/k8s-understanding/
  • /devops/kubectl-essential-commands/
  • /devops/k9s-essential-guide/

⚠️ 인덱싱 대기: 54건

📈 전체: 57개 중 3개 인덱싱 (5.3%)

한 화면에 현재 상태지난 주 대비 변화가 같이 잡힙니다. 주 1회 1분만 확인하면 블로그 SEO 건강 상태 파악 완료.


Claude Code 활용 회고 — 30분 구축의 비결

이 시스템을 Claude Code로 30분 만에 완성했습니다. 핵심 요인 3가지.

1) Subagent로 API 문서 조사

googleapis 라이브러리의 Search Console API 스펙을 Subagent에게 조사시키고, 주요 메서드·응답 구조만 요약받았습니다. 메인 세션은 그 결과를 받아 코드만 작성하면 됐습니다. Subagent 편의 "컨텍스트 격리" 가치가 여기서 직접 드러납니다.

2) 모듈 단위 병렬 생성

sitemap.js, gsc.js, diff.js, telegram.js를 각각 독립 모듈로 지정해 한 번에 4개 파일 생성. Claude Code가 파일 간 인터페이스만 맞춰주면 됩니다. 만약 하나의 긴 파일로 작성하다 에러 나면 전체 디버깅이 필요한데, 분리돼 있으면 해당 파일만 재작성하면 됩니다.

3) pre-commit 훅까지 자동 대응

레포의 husky + prettier + eslint가 자동 실행되는 환경이었는데, eslint의 Set/Map is not defined 같은 에러를 Claude Code가 즉시 파악하고 로컬 .eslintrc.json으로 Node ESM 환경 선언으로 해결했습니다. 사람이 직접 ESLint 설정을 뜯어보는 시간이 절약됐습니다.

"도구가 도구를 만든다"는 느낌이 강하게 드는 작업이었습니다.


확장 아이디어 5가지

기본 시스템이 안정되면 붙일 수 있는 것들.

확장 아이디어 가치
일 단위 cron으로 변경 이슈 감지 속도 7배 빨라짐 (API quota 여유 확인 필요)
블로그 내부 /insights 대시보드 indexing-status.json을 Gatsby 페이지로 시각화 (독자에게도 공개 가능)
Canonical 불일치 즉시 알림 중복 콘텐츠 판정으로 SEO 누수되기 전에 차단
**IndexNow 프로토콜 병행 Bing·Yandex에는 즉시 푸시** 가능 (Google은 미지원)
**배포 훅 연동 Netlify 배포 성공 시 30분 뒤 해당 URL만 타겟팅 체크**

가장 투자 대비 효과가 큰 건 "블로그 내부 대시보드"입니다. 본인 블로그의 SEO 현황을 공개하는 것 자체가 기술 블로그의 차별화 포인트가 됩니다.


한계와 현실

한계 대응 방법
API quota: 일당 2000, 분당 600 개인 블로그는 여유. URL 1000+ 넘어가면 배치 분할 고려
인덱싱 상태는 실시간 아님 구글 내부 캐시 — 몇 시간~며칠 지연 있을 수 있음
API는 읽기 전용 "지금 인덱싱해줘" 요청은 별도(Indexing API, 제한적) 필요
Telegram 메시지 4096자 제한 큰 이슈가 많으면 메시지 분할 필요 (현재는 미구현)

FAQ

Q. 이거 돌리는 데 돈이 드나요?

무료입니다. Google Search Console API는 무료 할당량(일 2000회) 내에서 사용, GitHub Actions는 public 레포는 무제한, Telegram Bot도 무료. 개인 블로그 규모에서는 0원으로 운영 가능합니다.

Q. sitemap을 여러 개 쓰거나 분할한 경우는?

코드에서 sitemap-index.xml을 먼저 fetch하고, 그 안의 <sitemap> 자식들을 모두 순회합니다. 대부분의 Gatsby/Hugo/Jekyll 기본 설정이 이 구조를 쓰므로 별도 작업 불필요.

Q. Google Indexing API로 "지금 인덱싱" 요청도 자동화할 수 있나요?

가능은 한데 공식적으로 JobPosting·BroadcastEvent 타입만 지원합니다. 일반 블로그 글은 ToS 위반이 됩니다. 많은 사이트가 편법으로 쓰지만 계정 제재 리스크가 있어 비권장. 대신 Bing의 IndexNow는 공식 지원하므로 그쪽으로 자동화하는 게 안전.

Q. Canonical 불일치가 뭔가요?

내가 선언한 canonical URL(<link rel="canonical">)과 Google이 실제로 선택한 canonical이 다른 경우입니다. 예: /post/ vs /post/index.html, http:// vs https://. 불일치가 있으면 내 URL 대신 Google 선택 URL이 노출되며, SEO 가치가 분산됩니다. 모니터가 이걸 자동 감지해 알려주는 게 실용적 가치 중 하나.

Q. Domain propertyURL prefix property 차이는요?

  • Domain property: sc-domain:blog.javapark.kr — DNS TXT 인증, 하위 모든 경로·프로토콜·www 자동 커버. 권장.
  • URL prefix property: https://blog.javapark.kr/ — HTML 파일 인증, 프로토콜·www 구분됨. 더 제약적.

신규 시작하면 Domain property로 가세요. 이미 URL prefix로 되어있으면 병행 등록 후 Domain으로 이관.


마무리 — 측정, 복구, 콘텐츠 개선을 분리하라

"구글에 내 글이 어떻게 보이는지"를 사람이 수동으로 확인하는 일은 이제 그만해도 됩니다. API와 Cron, 그리고 Telegram 봇 하나면 주간 자동 건강검진이 가능합니다.

이번 두 번의 0% 사례에서 확인한 핵심:

  • GSC URL Inspection API는 무료 + 강력, 개인 블로그는 quota 여유
  • GitHub Actions cron + JSON 상태 저장으로 추이 추적 가능
  • 첫 실행의 57/0과 4개월 뒤 119/0을 같은 기준으로 비교할 수 있었음
  • Secret 누락처럼 모니터 자체가 멈추는 실패도 먼저 감지해야 함
  • canonical·robots·가져오기 성공은 필요조건이지 색인 보장이 아님
  • 반복 제출보다 크롤링된 미색인 글의 독자적 가치와 내부 링크 개선이 다음 단계
  • 확장: 일 단위 cron, 블로그 내부 대시보드, IndexNow 연동까지

다음에 써볼 만한 주제

  • Gatsby 페이지로 SEO 대시보드 노출하기 (indexing-status.json 시각화)
  • IndexNow로 Bing·Yandex 즉시 인덱싱 요청
  • Netlify Deploy Hook과 연동해 "배포 후 30분 뒤 해당 URL만 체크"
  • Slack·Discord 다중 채널 동시 알림

관련 포스팅

여러분의 블로그는 구글에 얼마나 잘 잡히고 있으신가요? GSC를 "문제 생긴 후 확인하는 곳"에서 "주간 리포트로 받아보는 건강검진"으로 바꿔보세요. 구축은 30분, 효과는 몇 달치입니다.

@JavaPark
AI 시대의 개발자 도구, 실전 경험을 공유합니다