검색 등록·색인·노출·유입을 관측하기
소유 확인과 사이트맵 제출 뒤 URL별 색인 상태를 읽는다. 검색 노출·클릭·도착 페이지를 같은 조건으로 비교하고 수집 로그와 방문 기록을 함께 살핀다.
검색 도구가 관리할 사이트 범위를 정한다
운영 URL에서 새 안내가 열려도 Google이 아직 이전 문서를 갖고 있을 수 있다. 검색 도구를 사용하는 목적은 서버에서 고친 내용과 검색이 실제 처리한 내용을 비교하는 데 있다. 색인 여부와 대표 주소는 자료 처리 상태를, 노출과 클릭은 어떤 질문에서 발견되고 선택됐는지를 보여준다. 서로 다른 값이므로 필요한 수정도 달라진다.
Search Console의 도메인 속성은 프로토콜과 하위 도메인을 포함하는 범위를 관리하며 DNS 소유 확인을 사용한다. URL 접두어 속성은 지정한 프로토콜·호스트·경로 접두어의 범위를 관리한다. 실제 운영 주소를 포함하는 속성을 선택하고 안내받은 소유 확인 값을 적용한다.
소유 확인은 사이트 관리 권한의 확인이다. 이후 사이트맵을 제출하고 URL 검사에서 실제 색인 상태를 읽는다. 도메인 연결, 소유 확인, 사이트맵 처리, 문서 색인을 각각 기록하면 어느 단계가 남았는지 알 수 있다. 속성 추가 안내를 기준으로 운영 범위를 정한다.
검색 도구에서 URL별 색인 상태를 확인한다
Google Search Console은 운영자가 검색 수집·색인·노출을 확인하는 도구다. 속성(property)은 이 도구에서 관리할 사이트 범위다. 소유 확인을 마친 도메인의 속성을 선택한다. 사이트맵을 제출하고 처리 상태와 마지막 읽은 시각을 확인한다. 중요 상세 URL을 URL 검사에 넣어 Google이 알고 있는 색인 상태, 선택한 대표 URL, 마지막 크롤 시각을 기록한다. 실시간 테스트는 현재 접근 상태를 확인하는 용도이며 저장된 색인 상태와 구분해 적는다.
수정한 중요 페이지는 필요한 경우 색인 생성을 요청한다. 제출·요청 완료와 실제 색인됨은 별도 값으로 기록한다. 페이지 색인 보고서의 제외 이유를 같은 템플릿별로 묶어 공통 문제를 찾는다. 예를 들어 robots 차단은 접근 설정, 중복 대표 선택은 canonical·리다이렉트·내용 중복을 조사한다. URL 검사 도구 안내를 기준으로 각 결과를 해석한다.
검색어 site:example.com의 결과 수는 전체 색인 수의 기준값으로 쓰지 않는다. 관리하는 공개 대표 URL 목록을 분모로 두고, 확인한 URL의 색인 상태를 집계한다. 전체를 확인하지 못했다면 “검사한 20개 중 15개”처럼 조사 범위를 표시한다. 다른 검색엔진은 그 엔진의 도구와 실제 결과를 따로 기록한다.
예를 들어 상세 canonical을 고친 뒤 Google이 선택한 대표 주소도 상세로 바뀌었다면 주소 처리의 변화를 확인한 것이다. 여전히 홈을 선택했다면 최근 수집일과 상세 본문, 내부 링크·사이트맵의 주소를 다시 대조한다. 인덱스에 들어간 뒤에도 목표 질문의 노출이 없으면 그 질문에 답할 내용과 실제 검색 수요를 살핀다.
검색 노출·클릭과 생성형 검색 보고서를 읽는다
노출은 검색 결과에 페이지가 표시된 횟수이고 클릭은 그 결과를 눌러 이동한 횟수다. 검색 실적에서는 같은 기간·검색 유형·국가·기기 조건으로 노출, 클릭, 검색어, 도착 페이지를 내보낸다. 페이지별 값과 질문 주제별 변화를 함께 본다. 노출이 늘고 클릭이 그대로라면 검색 결과에서 제공한 정보, 제목·요약, 검색 의도와의 관계를 살핀다. 같은 페이지의 노출·클릭·검색어를 함께 비교하면 어떤 질문에서 변화가 생겼는지 찾을 수 있다.
2026년 10월 기준 Google의 생성형 AI 성과 보고서는 AI Overviews와 AI Mode의 노출을 제공한다. 해당 보고서의 날짜·페이지·국가·기기 조건을 기록하고 일반 검색 보고서와 구분해 보관한다. 보고서가 없으면 제공 조건과 충분한 노출 여부, 생성형 기능 포함 설정을 확인한다. 메뉴 부재를 숫자 0으로 입력하지 않는다.
도구의 보고 범위를 함께 적는다. Google 검색의 생성형 노출, 다른 AI 서비스의 인용, 직접 실행한 질문의 답변 품질은 관측 대상이 다르다. 다운로드 값의 누락 기호가 0으로 변환되는 경우도 있으므로 원래 화면과 내보낸 자료의 의미를 대조한다. 생성형 검색 포함 설정은 속성의 적용·상속 범위까지 확인한다.
유입·봇 로그를 보조 자료로 읽는다
리퍼러(referrer)는 방문 직전에 있던 페이지나 서비스의 주소 정보다. 분석 도구에서는 검색과 AI 서비스에서 들어온 방문의 리퍼러, 도착 페이지, 이후 행동을 본다. 인용이 있어도 방문하지 않을 수 있고, referrer가 누락될 수도 있다. 방문 수는 분석 도구에서, 인용 수는 수집한 답변에서 각각 집계한다. 전환(conversion)은 문의·신청처럼 사이트가 목표로 하는 행동이다. 이벤트(event)는 그 행동을 분석 도구에 기록하는 항목이다. 어떤 동작에서 이벤트를 보낼지 정하고 실제 제출·완료와 대조한다.
서버 로그는 요청 시각·경로·상태·응답량·사용자 에이전트를 묶어 수집 문제를 찾는 데 쓴다. 봇 이름은 위조할 수 있으므로 운영자가 제공한 IP 범위나 검증 방식으로 대조한다. 봇 요청 성공은 수집 경로의 증거이며, 답변 인용 여부는 저장한 AI 응답에서 확인한다. OpenAI 봇 안내의 검색·학습·사용자 요청 용도를 구분해 로그를 읽는다.
CTR과 전환을 코드로 계산하고 같은 범위끼리 비교한다
다음 metrics.mjs를 Node.js 22에서 사용한다. ratio의 입력은 확정된 분자와 분모다. 비율은 0~1 값으로 반환하며 퍼센트 표시는 100을 곱한다. 분모가 0이면 측정값이 없어 null을 반환한다. 음수·소수·분모보다 큰 분자는 집계 오류로 거절한다.
// Node.js 22. 원문을 읽은 평가자가 입력한 판정을 집계한다.
export function ratio(numerator, denominator) {
if (![numerator, denominator].every(n => Number.isSafeInteger(n) && n >= 0)
|| numerator > denominator) throw new Error('Invalid counts');
return { numerator, denominator, rate: denominator === 0 ? null : numerator / denominator };
}
export const keys = ['cited', 'supported', 'accurate', 'timely', 'relevant', 'complete'];
function allClaims(values) {
return values.includes(false) ? false : values.includes(null) ? null : true;
}
export function evaluate(rows) {
const completed = rows.filter(r => r.status === 'complete');
for (const row of rows) {
if (!['complete', 'failed'].includes(row.status)) throw new Error('Invalid status');
for (const key of ['questionId', 'questionVersion', 'service', 'mode', 'rawPath'])
if (typeof row[key] !== 'string' || !row[key]) throw new Error('Missing context: ' + key);
if (row.status === 'failed' && !row.failure) throw new Error('Missing failure');
}
for (const row of completed) {
for (const key of keys) {
if (![true, false, null].includes(row[key])) throw new Error('Missing assessment: ' + key);
if (!row.reasons?.[key]) throw new Error('Missing reason: ' + key);
}
if (!row.claims?.length) throw new Error('Missing claims');
for (const claim of row.claims) {
if (!claim.text || !claim.reason) throw new Error('Missing claim evidence');
for (const key of ['supported', 'accurate'])
if (![true, false, null].includes(claim[key])) throw new Error('Invalid claim');
if (claim.supported === true && (!claim.sourceUrl || !claim.quote))
throw new Error('Supported claim needs source and quote');
}
for (const key of ['supported', 'accurate'])
if (row[key] !== allClaims(row.claims.map(c => c[key]))) throw new Error('Claim summary mismatch');
}
function metric(key) {
const assessed = completed.filter(r => r[key] !== null);
return { ...ratio(assessed.filter(r => r[key] === true).length, assessed.length),
unknown: completed.length - assessed.length };
}
return { attempts: rows.length, completed: completed.length,
failed: rows.length - completed.length,
metrics: Object.fromEntries(keys.map(key => [key, metric(key)])) };
}
export function grouped(rows) {
const groups = new Map();
for (const row of rows) {
const id = JSON.stringify([row.questionId, row.questionVersion, row.service, row.mode, row.model ?? null]);
groups.set(id, [...(groups.get(id) ?? []), row]);
}
return [...groups].map(([group, items]) => ({ group: JSON.parse(group), ...evaluate(items) }));
}
같은 폴더에서 node --input-type=module -e "import {ratio} from './metrics.mjs'; console.log(ratio(50,1000),ratio(4,40),ratio(0,0))"을 실행한다. 결과의 rate는 순서대로 0.05, 0.1, null이다. 앞의 두 수치는 가상 CTR과 세션 전환율이다. 신청 건수/방문 수처럼 100%를 넘을 수 있는 별도 지표에는 이 비율 함수를 그대로 쓰지 않는다.
evaluate와 grouped는 다음 AI 평가에서 사용한다. 가상 응답 examples는 그 장의 assessment-fixture.mjs에서 가져온다. status는 응답 완료 여부이고 여섯 판정은 인용·근거·정확성·최신성·적합성·충분성을 나타낸다. 실패 수와 판정별 미확인을 따로 출력한다.
분석 도구에서 같은 기간·국가·기기·도착 페이지를 맞춘 뒤 비교한다. referrer가 없는 방문, 동의하지 않아 추적되지 않은 방문, 검색 화면에서 답을 얻어 방문하지 않은 경우를 고려한다. 집계의 변화가 특정 코드 하나의 효과인지 판단하려면 계절성·광고·새 콘텐츠·외부 보도 같은 동시 변화를 확인한다.
ratio가 0분모를 null로 돌려주는 이유는 노출이 없던 페이지의 CTR을 0%로 표시하면 제목을 고쳐야 할 문제처럼 읽힐 수 있기 때문이다. 노출 0회는 먼저 발견·색인·수요를 조사할 상황이고, 노출 1,000회에 클릭 0회는 검색 결과의 제목·답변·질문 적합성을 읽을 상황이다. 계산에서 이 둘을 나눠야 다음 수정도 달라진다.
보고서의 날짜·대표 주소·집계 단위를 맞춘다
Search Console의 생성형 검색 성과 보고서는 AI Overviews·AI Mode의 노출을 다룬다. 페이지 차원은 대부분 canonical URL에 성과를 배정하고, 날짜는 Pacific Time(PT)을 사용한다. 서버 로그의 요청 주소와 한국 날짜를 그대로 합산하면 같은 방문을 다른 날이나 다른 URL에 배정할 수 있다. 보고서 정의
예를 들어 PT의 2026년 10월 24일은 일광절약시간인 UTC−07:00이다. 한국에서는 10월 24일 16:00부터 10월 25일 16:00 직전까지에 해당한다. PT의 겨울 표준시는 UTC−08:00이므로 한국과 17시간 차이가 난다. 고정 16시간을 모든 날짜에 더하지 말고 America/Los_Angeles 시간대의 해당 날짜 경계를 사용한다.
한 결과 화면에 같은 속성의 A·B 두 페이지 링크가 표시됐다고 하자. 속성 단위 차트는 1회, 페이지 단위 표는 A 1회와 B 1회로 셀 수 있다. 페이지 행의 합은 2회지만 속성 차트는 1회다. 두 값은 집계 단위가 다르므로 같은 단위로 맞춰 비교한다.
UTM이 붙은 주소가 서버 로그에 남고 검색 보고서는 대표 주소에 합산했다면 요청 주소와 대표 주소를 함께 보존한다. 캠페인별 전환은 로그의 캠페인 값으로, 검색 성과는 보고서의 canonical 기준으로 읽는다. 보고서에서 미확인 기호가 내보내기 과정에서 0이 되는 경우도 원래 표시와 대조한다.
10월 24일에 이미지 응답이 작아졌다면 그날의 파일 바이트와 로딩 결과를 먼저 남긴다. 이후 검색 보고서는 같은 페이지·검색어·기기·국가 범위로 비교한다. 사진 수정일 전후에 제목이나 캠페인까지 바뀌었다면 노출·클릭 변화에는 그 변경도 섞인다. 응답 파일의 변화, 페이지 경험의 변화, 검색 유입의 변화를 별도 열로 두면 다음 수정의 근거를 구체적으로 읽을 수 있다.