AI 에이전트로 GEO/SEO를 실행한 기록 — 측정된 것과 무너진 가정
앱 추천 유입의 93%가 ChatGPT인데, robots.txt가 그 크롤러를 막고 있었습니다.
목차
자사 iOS 앱 사이트에 GEO(생성형 엔진 최적화)를 적용하며 측정한 값들입니다. 가장 크게 빗나간 가정은 “대규모 언어 모델(LLM)을 통한 유입은 아직 이르다”였습니다. 이미 앱 추천 유입의 93%가 ChatGPT였고, 정작 사이트의 robots.txt는 그 크롤러를 막고 있었습니다.
1. 핵심 요약
출시된 iOS 앱의 공식 사이트에 GEO/SEO를 적용했습니다. 작업 자체보다 작업 전에 측정한 값이 더 중요했습니다. 가정 대부분이 데이터 앞에서 무너졌기 때문입니다.
세 숫자가 한 방향을 가리켰습니다. LLM 유입은 이미 일어나고 있는데, 사이트는 LLM이 읽을 수 없는 상태였다는 것입니다.
2. 데이터가 먼저 말한 것
App Store Connect에서 집계한 90일간(2026-06-02~08-30)의 최초 다운로드 유입 경로입니다.
| 소스 | 다운로드 | 비중 |
|---|---|---|
| App Store 검색 | 374 | 62% |
| 앱 추천 방문 | 192 | 32% |
| 웹 추천 방문 | 20 | 3% |
| App Store 탐색 | 18 | 3% |
| 합계 | 606 | — |
여기서 “앱 추천 방문”을 앱별로 쪼개면 ChatGPT 179건, Google Chrome 4건입니다. 즉 앱 추천 방문의 93%, 전체 다운로드의 30%가 ChatGPT의 추천을 거쳐 유입된 것입니다. 6월과 7월은 거의 0에 가깝다가 8월 초부터 급격히 올라간 형태였습니다.
여기서 배운 것. “LLM 최적화는 미래 준비”라고 생각하고 있었는데, 이미 주력 유입 채널이었습니다. GEO를 가설이 아니라 이미 작동 중인 채널의 보강으로 다뤘어야 했습니다. 측정을 먼저 하지 않았다면 우선순위를 완전히 잘못 잡았을 겁니다.
반대로 웹 추천 20건은 비정상적으로 낮았습니다. 이유는 뒤에서 다룹니다.
3. 코드를 쓰기 전에 사실 계약을 먼저 만들었다
마케팅 페이지를 AI에게 쓰게 할 때 가장 큰 리스크는 코드 품질이 아니라 그럴듯한 허위 사실입니다. 없는 기능을 홍보하거나, 검증되지 않은 최상급 표현을 쓰거나, 경쟁사에 대해 지어낸 사실을 적는 것 말입니다.
그래서 페이지를 한 줄도 쓰기 전에, 에이전트에게 저장소 전체를 읽고 사실 계약(fact contract)부터 만들게 했습니다. 무엇을 사실로 주장해도 되는지 미리 못 박아 두는 문서라는 뜻입니다. 산출물은 세 가지 목록입니다.
파일과 줄 번호로 근거가 확인되는 주장. 그대로 써도 되는 것.
저장소가 답하지 않는 주제. 보수적으로 쓰거나 아예 빼는 것.
쓰면 안 되는 구체적 표현. 근거와 함께 명시.
이 과정에서 저장소 안의 모순이 먼저 드러났습니다. 예를 들어 마케팅 페이지의 JSX 코드에는 미션이 3종으로 적혀 있었지만, 앱 1.3.0 사용 가이드에는 8종이 문서화돼 있었습니다. 커밋 제목과 실제 코드 변경 내역(diff)이 다른 경우도 있었습니다. 제목은 연락처를 A로 바꿨다고 했는데 diff는 B로 바꾸고 있었습니다.
일반화할 수 있는 규칙. AI에게 마케팅 카피를 맡길 때는 “거짓말하지 마”라고 지시하는 것으로 부족합니다. 무엇이 참인지 판정하는 단일 출처를 지정해야 합니다. 여기서는 “버전이 명시된 사용 가이드가 최우선, 마케팅 코드는 신뢰하지 않음”이 그 규칙이었습니다.
4. 에이전트가 찾아낸 것들
SEO 작업으로 시작했지만, 실제로 나온 것은 대부분 사람이 몇 달간 못 보고 지나간 버그였습니다.
홈페이지가 JS 없이 단어 0개
홈은 React를 브라우저에서 Babel로 변환해 렌더링하는 구조였습니다. 즉 <body>에는 빈 <div id="root"> 하나뿐입니다. 크롤러가 렌더링 전에 처음 받는 HTML에는 본문 0단어, 내부 링크 0개였습니다. 나머지 페이지는 오직 사이트맵에만 의존하고 있었습니다.
법적 문서 3종이 사실상 빈 문서
가이드·개인정보·약관 페이지는 한 URL에 3개 언어를 넣고 CSS로 감추는 구조였는데, 서버가 내려주는 HTML에 현재 언어 표시가 없었습니다. 결과적으로 JS를 실행하지 않는 클라이언트에게는 15~35단어만 보였습니다. 사이트맵에는 등록돼 있는데 내용이 없는 상태였습니다.
| 페이지 | 수정 전 | 수정 후 |
|---|---|---|
| 사용 가이드 | 35 단어 | 2,106 단어 |
| 개인정보 처리방침 | 15 단어 | 591 단어 |
| 서비스 약관 | 15 단어 | 275 단어 |
존재하지 않는 기능을 파는 요금제
코드에 완성돼 있지만 렌더링만 꺼둔 요금제 컴포넌트가 있었습니다. 기능 항목 13개를 문서와 대조한 결과, 실제로 존재하면서 유료로만 제공되는 항목은 0개였습니다. 6개는 이미 무료, 4개는 아예 존재하지 않았고(그중 하나는 OS가 지원하지 않아 구현 자체가 불가능), 3개는 문서에 없었습니다. 주석은 “나중에 한 줄만 되살리면 됨”이라고 적혀 있었습니다.
하지 않는 수집을 공개한 개인정보 문구
이건 에이전트가 만든 오류를 에이전트가 잡은 경우입니다. 개인정보 문구에 “웹 분석 도구를 사용합니다”라고 3개 언어로 썼는데, 실제로는 비콘이 주입되지 않고 있었습니다. 실제로 하지 않는 수집을 한다고 고지한 것이라, 수집 사실을 빠뜨린 경우보다는 덜 위험하지만 여전히 실제 동작과 다릅니다.
여기서 배운 것. 에이전트 산출물은 배포 후 실제 응답으로 재검증해야 합니다. 소스만 보면 “CSP에 허용돼 있으니 켜져 있겠지”로 넘어갑니다. curl 한 번이 그 가정을 깼습니다.
요청의 59%가 4xx
Cloudflare 지표를 보면 7일 동안 오류 응답(4xx)이 7,060건, 정상 응답(2xx)이 5,000건이었습니다. 원인은 가이드의 이미지 30개가 존재하지 않는 평면 경로를 가리키고 JS가 런타임에 고쳐 쓰는 구조였습니다. 브라우저는 JS가 고치기 전에 원래 경로를 먼저 요청합니다. 게다가 앞서 “빈 문서” 문제를 고치면서 그 이미지들이 화면에 드러나 상황이 악화됐습니다.
5. robots.txt가 LLM 크롤러를 막고 있었다
가장 아이러니한 발견입니다. 배포 후 robots.txt를 확인하니 CDN이 관리형 블록을 앞에 주입하고 있었고, 그 안에서 다음이 전부 Disallow: /였습니다.
GPTBot · ClaudeBot · Google-Extended · CCBot · Bytespider Applebot-Extended · meta-externalagent · Amazonbot Content-Signal: search=yes, ai-train=no, use=reference
전체 작업의 목적이 “LLM이 사이트를 이해하게 만들기”였는데, 정작 ChatGPT와 Claude가 robots.txt 단계에서 차단돼 있었습니다. 저장소의 파일이 아니라 CDN 대시보드 설정이라 코드를 아무리 고쳐도 사라지지 않습니다.
주목할 모순. Content-Signal은 use=reference(인용 허용)인데 같은 파일이 Disallow: /(읽기 금지)입니다. “학습엔 쓰지 말되 인용은 해도 된다”는 의도였겠지만, 읽지 못하면 인용도 불가능합니다. 기본값이 의도와 어긋나 있는 전형적인 사례입니다.
한 가지 더 구분이 필요했습니다. 대시보드의 “크롤러 차단” 토글은 전부 꺼져 있었고 로그상 실패도 0이었습니다. 즉 엣지에서 강제로 막지는 않지만 robots.txt로는 금지를 선언하고 있던 상태입니다. 준수형 크롤러는 선언을 따르므로 결과는 같습니다. 차단 레이어가 둘이고 설정 위치가 다르다는 점을 아는 것이 중요했습니다.
6. 측정 도구를 고르는 기준
이벤트 추적 도구를 검토하면서 Google Analytics 4(GA4)를 후보로 놓고 전송량을 실측했습니다.
| 항목 | gzip 전송량 |
|---|---|
| 랜딩 페이지 전체 | 6.5 KB |
| gtag.js | 151 KB |
| 경량 분석 스크립트 | 1.5 KB |
측정 대상 페이지보다 측정 스크립트가 23배 무겁습니다. 게다가 그 페이지들은 SEO를 위해 JS를 0바이트로 만든 정적 페이지였습니다. 측정 행위가 측정 대상을 훼손하는 구조입니다.
결정적이었던 건 다른 사실입니다. iPhone 앱 사이트라 방문자 대부분이 Safari인데, Safari는 스크립트가 설정한 퍼스트파티 쿠키를 7일로 제한합니다. GA4가 내세우는 재방문자·사용자 수 지표가 정확히 이 오디언스에서 구조적으로 틀리게 나옵니다.
결론. 도구를 고르기 전에 답이 필요한 질문이 무엇인지 먼저 적어야 합니다. 여기서 필요했던 건 “페이지별 조회수와 CTA 클릭수” 두 개였습니다. 그 두 정수를 위해 151 KB와 동의 배너를 사는 건 과합니다.
7. App Store 귀속의 함정
App Store 링크에 utm_*를 붙이려던 계획은 실측으로 폐기했습니다.
?utm_source=… → 301 → 파라미터 소실 ?pt=…&ct=… → 301 → pt·ct 유지
App Store의 리다이렉트가 utm_*를 버립니다. 애플의 캠페인 귀속은 별도 토큰 체계를 씁니다.
더 중요한 발견은 따로 있었습니다. 사이트의 모든 App Store 링크에 rel="noopener noreferrer"가 붙어 있었는데, noreferrer는 Referer 헤더를 보내지 말라는 지시입니다. App Store Connect가 파라미터 없이도 제공하는 웹 유입 통계를 사이트가 스스로 막고 있었던 것입니다. 앞서 “웹 추천 20건”이 낮았던 이유입니다.
8. 아직 결론이 아닌 것
이 글은 성공 사례가 아닙니다. 작업 시점 기준으로 색인은 아직 1페이지이고, 색인 요청을 넣은 페이지들은 “발견됨 – 현재 색인이 생성되지 않음” 상태입니다.
이 상태를 진단하면서 확인한 것들입니다. 응답 코드 200, 첫 바이트 응답 시간(TTFB) 약 0.5초, 대표 URL(canonical) 정상, index, follow 허용, 콘텐츠도 충분합니다. 기술적 차단 요소가 없다면 남는 것은 크롤 예산이고, 신규 도메인에서 그것을 결정하는 것은 외부 링크와 시간입니다. 현재 외부 백링크는 0입니다.
정직하게 말하면. GEO/SEO 작업의 효과는 며칠로 판정할 수 없습니다. 이 글에 쓴 숫자들은 작업 이전의 베이스라인이며, 작업의 결과가 아닙니다. 결과는 몇 주 뒤에나 말할 수 있습니다. 사례 연구에서 이 구분을 흐리는 글이 많아 명시해 둡니다.
9. 체크리스트
다른 팀이 같은 작업을 한다면 이 순서로 확인하시길 권합니다.
- 측정을 먼저 한다. App Store Connect나 유입 통계에서 LLM 추천 유입이 이미 있는지 확인하세요. 가정으로 우선순위를 잡지 마세요.
curl로 크롤러 시점을 재현한다. JS 없이 몇 단어가 보이는지, 내부 링크가 몇 개인지 세보세요. SPA라면 0일 가능성이 높습니다.robots.txt를 실제로 열어본다. 저장소 파일이 아니라 배포된 응답을 보세요. CDN이 주입하는 블록이 있을 수 있습니다.- AI 크롤러 정책이 의도와 맞는지 본다. 차단 레이어가 둘(선언 vs 강제)이고 설정 위치가 다릅니다.
- 사실 계약을 먼저 만든다. AI에게 카피를 맡기기 전에 무엇이 참인지 판정하는 단일 출처를 지정하세요.
- 배포 후 다시 검증한다. 소스가 아니라 라이브 응답으로. 에이전트가 만든 문서 오류를 여기서 잡았습니다.
- 아웃바운드 링크의
rel을 확인한다.noreferrer가 유입 귀속을 지우고 있을 수 있습니다. - 측정 도구는 질문을 정한 뒤에 고른다. 페이지 무게와 오디언스의 브라우저 특성을 함께 보세요.
이 사례의 대상은 AlarmK(iPhone 미션 알람 앱)의 공식 사이트입니다. 권한별 동작을 정리한 문서는 AlarmKit 페이지에 있습니다.
10. 참고자료
| 자료 | 핵심 내용 | 링크 |
|---|---|---|
| Apple — App Analytics 소스 유형 | App Store 검색·앱 추천·웹 추천 등 유입 소스 구분과 Web Referrer 정의 | developer.apple.com |
| Apple — 캠페인 링크 | pt·ct·mt 파라미터 정의와 캠페인 링크 생성 조건 | developer.apple.com |
| MDN — rel=noreferrer | Referer 헤더를 생략하도록 지시하는 링크 관계 속성 | developer.mozilla.org |
| Google — 쿠키 수명 제한 | 스크립트가 설정한 퍼스트파티 쿠키가 Chrome 400일·Safari 7일로 제한됨 | support.google.com |
| Google — 태그 플랫폼 CSP | Google 태그 동작에 필요한 CSP 지시문 목록 | developers.google.com |
| Cloudflare — Web Analytics FAQ | 커스텀 이벤트 미지원, 쿼리스트링 미기록, 엣지 분석과의 차이 | developers.cloudflare.com |
| AlarmK — AlarmKit과 iOS 26 | 사례 대상 사이트. 권한 조합별 알람 발사 경로 정리 | alarmk.com/alarmkit |
이 글의 수치는 2026-09-05 기준으로 App Store Connect·Cloudflare·Google Search Console에서 직접 측정한 값입니다. 색인 상태와 유입 구성은 이후 달라질 수 있습니다.