news.hwmoon.com AdSense 승인 전 준비와 운영 전환 기록
news.hwmoon.com의 Google AdSense 승인 대기 상태에서 연결 코드, ads.txt, 수동 광고 슬롯, 빈 슬롯 제거, 승인 이후 slot ID 적용 절차를 나눠 정리한 운영 기록입니다.
- Google AdSense
- Site review flow
- Astro
- Static rendering
- Azure Static Web Apps
- Production deploy
이 글의 목차
이번 기록은 news.hwmoon.com에 Google AdSense를 붙이면서 정리한 승인 전 준비 사항과 운영 전환 기준이다.
처음에는 “AdSense 코드를 넣었는데 왜 광고가 안 보이지?”처럼 보였지만 실제 상태는 더 분리해서 봐야 했다. ads.txt가 승인되어도 사이트 승인 자체가 준비 중이면 광고는 아직 노출되지 않는다. 또 수동 광고 단위의 slot ID가 없는 상태에서 AdSense <ins> 영역만 미리 렌더링하면 사용자는 빈 광고 박스를 보게 된다.
그래서 이번 대응의 결론은 단순하다.
승인 검토에 필요한 신호는 남기고, 승인 전 빈 광고 슬롯은 공개 화면에서 제거한다.
이 글은 그 결정을 기술적으로 다시 재현할 수 있도록 남기는 runbook이다.
배경
news.hwmoon.com은 기사 자동 생성과 정적 배포가 연결된 미디어 사이트다. AdSense 승인 관점에서는 단순히 광고 스크립트를 넣는 것만으로 끝나지 않는다.
승인 검토 중인 사이트는 최소한 아래 조건을 안정적으로 만족해야 한다.
| 영역 | 필요한 상태 | 운영상 의미 |
|---|---|---|
| 사이트 연결 | AdSense account meta 또는 AdSense loader가 head에 있음 | Google이 사이트 소유와 연결 상태를 확인할 수 있어야 한다. |
ads.txt | root에서 Google publisher line을 200으로 반환 | authorized seller 정보가 공개되어야 한다. |
| 콘텐츠 | 충분한 공개 기사와 명확한 navigation | 검토자가 사이트 목적과 콘텐츠 품질을 판단할 수 있어야 한다. |
| 정책 페이지 | About, Privacy, Contact, Editorial Policy | 광고와 개인정보 처리 기준이 보여야 한다. |
| UX | 깨진 링크, 빈 광고 박스, 과도한 placeholder 없음 | 승인 전이라도 독자 경험이 완성된 사이트처럼 보여야 한다. |
| 배포 검증 | build, route smoke check, live HTML audit | 로컬 변경과 운영 반영 사이의 차이를 줄여야 한다. |
Google 공식 문서 기준으로도 사이트 승인이 완료되기 전에는 광고를 표시할 수 없다. 또한 Auto ads는 AdSense code만으로 동작할 수 있지만, 수동 ad unit은 AdSense code와 별도의 ad unit code가 필요하다.
문제가 헷갈렸던 이유
AdSense 콘솔에는 서로 다른 상태가 같은 화면에 가까이 붙어 나온다.
| 콘솔 상태 | 의미 | 흔한 오해 |
|---|---|---|
ads.txt 승인됨 | root ads.txt가 Google publisher line을 올바르게 반환함 | 사이트 광고 게재 승인까지 끝났다고 오해하기 쉽다. |
사이트 준비 중 | 사이트 검토가 아직 진행 중 | 코드가 잘못돼서 무조건 광고가 안 나오는 것으로 오해하기 쉽다. |
| 광고 단위 없음 | 수동 slot ID가 아직 없음 | <ins>를 미리 넣으면 곧 채워질 것처럼 기대하기 쉽다. |
| 보고서 0 | 승인 전이거나 노출이 없음 | 배포가 실패했다고 단정하기 쉽다. |
이번 상태에서는 ads.txt는 정상이었고, head 코드도 들어가 있었다. 하지만 사이트 승인은 아직 끝나지 않았고, AdSense 광고 단위도 만들어지지 않았다.
따라서 공개 페이지에 빈 광고 영역을 미리 보여주는 것은 운영적으로 맞지 않았다. 검토에는 도움이 되지 않고, 독자에게는 미완성 UI처럼 보이기 때문이다.
목표 상태
목표는 승인 전과 승인 후를 명확히 나누는 것이다.
승인 전에는 다음만 유지한다.
<meta name="google-adsense-account">- AdSense loader script
- root
/ads.txt - Privacy page의 광고 고지
- 충분한 공개 기사와 sitemap
- 빈 광고 슬롯 없는 화면
승인 후에는 아래를 추가한다.
- AdSense에서 Auto ads enable
- 필요한 경우 ad unit 생성
- 생성된 slot ID를 환경변수로 주입
- AdSense
<ins>slot 렌더링 - live 노출, CLS, 모바일 overflow 확인
운영 흐름 다이어그램
이 구조에서 중요한 점은 “AdSense script를 넣는다”와 “광고 슬롯을 화면에 만든다”를 분리한 것이다. 전자는 사이트 검토와 Auto ads 준비에 필요하다. 후자는 수동 광고 단위가 실제로 만들어졌을 때만 의미가 있다.
구현 기준
news.hwmoon.com의 공통 레이아웃은 AdSense account와 loader script를 head에 넣는다. 단, PUBLIC_ADSENSE_ENABLED가 꺼져 있거나 client ID가 유효하지 않으면 렌더링하지 않는다.
{adsenseEnabled && hasValidAdsenseClientId && (
<meta name="google-adsense-account" content={adsenseClientId} />
)}
{allowAdsenseOnPage && hasValidAdsenseClientId && (
<script
async
src={`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${adsenseClientId}`}
crossorigin="anonymous"
></script>
)}
수동 광고 위치는 별도 AdSenseSlot 컴포넌트로 제어한다. 이번 대응에서 가장 중요한 조건은 아래 한 줄이다.
const shouldRender = adsenseEnabled && hasValidClientId && hasValidSlotId;
이 조건 때문에 승인 전에는 slot ID가 없으므로 아무 광고 DOM도 만들지 않는다. 즉, 빈 dashed box, pending marker, placeholder, 빈 <ins>가 공개 HTML에 남지 않는다.
환경변수 설계
AdSense 관련 환경변수는 account 연결, root seller 선언, 수동 slot을 분리해서 다룬다.
| 변수 | 역할 | 승인 전 값 |
|---|---|---|
PUBLIC_ADSENSE_ENABLED | AdSense 기능 on/off | true |
PUBLIC_ADSENSE_CLIENT_ID | ca-pub-* account/client ID | 실제 publisher client |
PUBLIC_ADSENSE_PUBLISHER_ID | ads.txt에 들어갈 pub-* ID | 실제 publisher ID |
PUBLIC_ADSENSE_SLOT_NEWS_HOME_TOP | 홈 상단 수동 광고 slot | 비워둠 |
PUBLIC_ADSENSE_SLOT_NEWS_HOME_RAIL | 홈 rail 수동 광고 slot | 비워둠 |
PUBLIC_ADSENSE_SLOT_NEWS_ARTICLE_TOP | 기사 상단 수동 광고 slot | 비워둠 |
PUBLIC_ADSENSE_SLOT_NEWS_ARTICLE_MID | 기사 중간 수동 광고 slot | 비워둠 |
PUBLIC_ADSENSE_SLOT_NEWS_ARTICLE_BOTTOM | 기사 하단 수동 광고 slot | 비워둠 |
승인 전에는 account/client와 publisher만 실제 값이어야 한다. slot 변수는 비워두는 것이 맞다. slot ID가 없는 값을 억지로 넣거나 placeholder 문자열을 넣으면 오히려 잘못된 광고 DOM이 생성될 수 있다.
QA 체크리스트
이번 대응에서 로컬 build만 보는 것으로 끝내지 않았다. 정적 사이트는 build 산출물과 실제 운영 HTML이 다를 수 있기 때문에 live 확인까지 포함해야 한다.
| 단계 | 확인 |
|---|---|
| Build | Astro build가 성공하는지 확인 |
| AdSense audit | privacy disclosure, meta, loader, ads.txt, placeholder 부재 확인 |
| Route check | home, article, privacy, sitemap, ads.txt가 200인지 확인 |
| Live HTML | 운영 URL에서 pending marker, blank placement DOM, AdSense slot element가 없는지 확인 |
| Mobile | 400px 폭에서 빈 광고 박스나 horizontal overflow가 없는지 확인 |
| Pipeline | Azure Static Web Apps 배포 run이 성공했는지 확인 |
승인 전 live HTML의 기대값은 아래와 같다.
google-adsense-account: 1
pagead2 loader script: 1
ads.txt: 200
pending marker: 0
blank placement DOM: 0
AdSense slot elements: 0
승인 후 수동 slot ID를 넣으면 마지막 두 값은 바뀐다. 이때는 의도한 위치에만 placement marker와 AdSense slot element가 생기는지 봐야 한다.
news와 tech를 같은 정책으로 맞춘 이유
news.hwmoon.com과 tech.hwmoon.com은 성격이 다르지만 광고 준비 정책은 같아야 한다.
| 사이트 | 성격 | AdSense 정책 |
|---|---|---|
news.hwmoon.com | 자동 생성 기사 중심 미디어 | 승인 전 recovery mode와 콘텐츠 품질 관리가 중요 |
tech.hwmoon.com | 운영 기록과 runbook 중심 기술 블로그 | 코드 변경, 배포 검증, 근거 문서화가 중요 |
두 사이트 모두 승인 전에는 연결 신호만 남기고 빈 광고 슬롯은 숨긴다. 승인 후에는 Auto ads 또는 수동 slot ID를 통해 실제 광고 DOM을 렌더링한다.
이렇게 맞춰두면 한쪽 사이트에서 배운 검증 로직을 다른 쪽에도 적용할 수 있다.
승인 이후 전환 절차
AdSense 사이트 상태가 준비됨 또는 광고 게재 가능 상태로 바뀌면 다음 순서로 전환한다.
- AdSense의 사이트 기준 Auto ads 설정을 확인한다.
- 수동 위치가 필요하면 AdSense에서 display ad unit을 만든다.
- 생성된 slot ID를 Azure Static Web Apps 환경변수에 넣는다.
- staging 또는 local build에서 AdSense
<ins>element가 의도한 위치에만 생기는지 확인한다. - production 배포 후 live HTML과 모바일 화면을 다시 확인한다.
- 24~48시간 정도 보고서, Active View, CLS, 모바일 anchor ads 영향을 관찰한다.
수동 slot을 바로 많이 넣기보다 article middle 또는 bottom처럼 레이아웃 충격이 적은 위치부터 시작하는 편이 안전하다. 특히 news article page는 본문 읽기 흐름이 중요하므로 top, mid, bottom을 한 번에 모두 켜기보다 하나씩 켜고 지표를 보는 것이 낫다.
남은 리스크
승인 준비가 끝났다고 해서 운영 리스크가 사라지는 것은 아니다.
| 리스크 | 대응 |
|---|---|
| 사이트 승인 지연 | head code, ads.txt, sitemap, 충분한 공개 콘텐츠, 정책 페이지를 주기적으로 확인 |
| 자동 광고가 과도하게 삽입됨 | Auto ads format과 위치를 AdSense에서 제한 |
| 수동 slot이 모바일 레이아웃을 밀어냄 | responsive slot, width constraint, live mobile QA 필수 |
| 광고 스크립트가 noindex 페이지에 들어감 | robots가 noindex인 페이지에는 loader를 제외 |
| 잘못된 placeholder 값 배포 | slot ID 정규식과 audit script로 차단 |
참고 문서
- Google AdSense: Connect your site to AdSense
- Google AdSense: Where to place AdSense code in your HTML
- Google AdSense: Get and copy the AdSense code
- Google AdSense: Where to place ad unit code in your HTML
- Google AdSense: Ads.txt guide
정리하면 이번 작업은 “광고를 붙였다”가 아니라 “승인 전과 승인 후의 렌더링 경계를 만들었다”에 가깝다. AdSense가 아직 준비 중일 때는 사이트 검토에 필요한 신호만 유지한다. 독자에게 빈 광고 박스를 보여주지 않는다. 그리고 승인 후에는 slot ID와 Auto ads 정책을 통해 의도한 위치에서만 광고를 시작한다.
시리즈
Publisher Infrastructure
전체 8편 중 7편입니다. 관련 구축 기록을 순서대로 모아 전체 맥락을 쉽게 확인할 수 있습니다.
- 1. Azure DNS와 Zoho Mail로 도메인 이메일 만들기
- 2. Synology NAS로 Azure DevOps Self-hosted Agent 운영하기
- 3. Pipeline은 성공했는데 Static Web Apps가 404를 냈던 이유
- 4. Azure Repos를 운영 원본으로 두고 GitHub를 백업으로 쓰는 전략
- 5. Slack 기반 AIOps로 NAS Agent 운영 자동화하기
- 6. news.hwmoon.com 기사 자동 발행 중단 재발 방지 기록
- 7. news.hwmoon.com AdSense 승인 전 준비와 운영 전환 기록
- 8. news.hwmoon.com 배포 중단 원인과 Agent 자가복구 체계 구축 기록