본문으로 건너뛰기

광고 유닛 전면 재도입 (RES-004)

· 약 3분
jangsungyu
Frontend Developer
Claude Code
AI Assistant

작업 날짜: 2026-07-29 브랜치: feature/1.54.0-ad-units

📋 작업 개요

작업 유형: 기능 추가 (광고 재도입) 담당: jsg3121 · claude

DS 반응형 개편(A~F 그룹) 과정에서 각 페이지의 UA 분기 2벌 구조를 반응형 단일로 통합하며 제거·보류했던 AdSense 광고를, 데이터 기반 우선순위에 따라 전 페이지에 다시 도입했다. 배치 전략 보고서는 .claude/research/reports/RES-004-ad-placement-strategy.md.

🎯 작업 목표

DS 개편으로 사라진 광고 수익을 회복하되, 단순 복원이 아니라 3지표(GA4 조회·서치콘솔 검색·애드센스 수익, 2026-04~07)를 종합해 트래픽·수익 기여가 큰 페이지부터 재도입한다. 배치는 실측 데이터에 근거하고, 반응형 단일 뷰 구조를 깨지 않으면서 기기별 성과를 분리 추적할 수 있게 한다.

✨ 주요 변경사항

배치 원칙 (전 페이지 공통)

  • UA별 슬롯 분리: 기기별 성과를 분리 추적하기 위해 모바일·데스크톱 슬롯을 나눈다. 각 광고 컴포넌트가 내부에서 useDevice(서버가 layout에서 주입한 isMobile)로 조건부 렌더한다. 미노출 유닛을 DOM에 넣고 CSS로 숨기는 것은 AdSense 정책 위반이므로, CSS 분기 대신 null 반환(조건부 렌더)을 쓴다. 서버 값 기반이라 CSR 전환이 없다.
  • 콘텐츠 반응형 단일 유지: 뷰 레이아웃은 반응형 단일 그대로 두고, 그 안의 광고 슬롯만 기기별로 갈라 렌더한다.
  • 미매칭 시 접힘: useAdSlotEffect 훅이 MutationObserverdata-ad-status="unfilled"를 감지해, 광고가 안 채워지면 컨테이너를 접어 빈 공간을 없앤다(고정 height 슬롯의 빈 영역 방지). 전역 적용.
  • 슬롯 상수 SSOT: 슬롯 ID를 src/constants/adSense.ts에 상수로 모아 관리한다(하드코딩 지양).

페이지별 배치

페이지위치형식
상세(detail)능력치 후 / 기술표 후 / 최하단 3지점320×100·728×90 / 반응형
상성계산기(type-effectiveness)타입 선택↔결과 사이 1개PC 인아티클 / 모바일 320×100
기술도감 목록(moves)페이지 헤더 아래PC 970×250 / 모바일 320×100
기술도감 상세(moves/[id])설명 아래 상단(디스플레이) + 그리드 뒤 하단(인아티클)
상세 기술탭(detail/[id]/moves)히어로 아래·탭 위970×250 / 320×100
챔피언스(홈·도감·티어·상세·대회)각 콘텐츠 소비 지점(상단 재배치)PC 인아티클/300×250 / 모바일 320×100
도감 리스트(list)필터바 아래PC 인피드 / 모바일 320×100
특성 도감(ability 목록·상세)페이지 헤더 아래PC 970×250 / 모바일 320×100
퀴즈(quiz 허브·4종 결과)허브 헤더 아래 / 결과 상단가로형 / 320×100

데이터 기반 판단 사례

  • 상단 vs 하단: 상세 페이지 실측에서 모바일 하단 배너 CTR 2.02%(수익 1위) vs 상단 배너 CTR 0.06%로 34배 차이가 났다. 이를 근거로 detail은 "콘텐츠 소비 후 섹션 사이"에 배치했다. 다만 챔피언스처럼 노출 절대량이 부족한 페이지는 노출×RPM 관점에서 상단 조기 노출로 재배치해 개선을 시도했다(CTR 저조 원인이 위치인지 유입 부족인지 단정할 수 없으므로 배포 후 데이터로 검증).
  • 인피드 제외: moves·list의 카드 사이 인피드는 과거 커버리지·CTR이 붕괴(PC $0.08·모바일 $0.17)해 재도입하지 않고 상단 배너로 대체했다.
  • 상성계산기 하단 제거: 도구성 페이지라 표 끝까지 스크롤해 하단에 도달하는 사용자가 거의 없어(PC 하단 클릭 0) 상단 1개만 유지했다.

🔧 기술적 세부사항

  • 신규 광고 컴포넌트: 페이지별 통합 컴포넌트(DetailStatsBanner·TypeEffectivenessTopBanner·MovesListTopBanner·ChampionsInContentBanner·ListTopBanner·AbilityListTopBanner·QuizResultTopBanner 등) — 내부 useDevice 분기.
  • 슬롯 상수: DETAIL_INCONTENT_SLOTS·MOVES_DETAIL_TOP/BOTTOM_SLOTS·DETAIL_MOVES_SLOTS·CHAMPIONS_SLOTS·QUIZ_RESULT_SLOTS 등을 adSense.ts에 정의.
  • : useAdSlotEffect에 unfilled 컨테이너 접힘 로직 추가(전역).
  • 레거시 정리: 각 페이지 재도입 시 사용처 없이 남아있던 기존 adSlot 컴포넌트(Desktop/Mobile 2벌)를 삭제하고 통합 컴포넌트로 대체.
  • layout.tsx: AdSense 스크립트를 다른 스크립트보다 먼저 로드하도록 순서 조정.

📌 참고 사항

  • 개발 환경(NODE_ENV !== production)에서는 AdSense 스크립트가 로드되지 않아 실제 광고가 표시되지 않는다. 배치 위치·규격 확인은 각 페이지에 대응하는 콘솔 미리보기 스니펫으로 수행했다.
  • 신규 슬롯은 발급 완료 후 상수에 반영했으며, 미발급 슬롯('')은 컴포넌트가 null을 반환해 렌더되지 않는다(빈 광고 요청 방지).
  • ads.txt는 CloudFront에서 이미 정상 서빙 중(publisher ca-pub-6481622724376761)이라 별도 조치하지 않았다.