개인 블로그를 Astro 플랫폼으로 구축한 후, 수익화를 위해 Google AdSense를 연동하는 작업을 진행했다. AdSense 스크립트를 삽입하고 광고 단위를 설정하는 것은 어렵지 않았으나, 한 가지 치명적인 문제가 발생했다. 바로 페이지 전환 시 광고가 제대로 노출되지 않는 현상이다. 이 글에서는 해당 문제를 분석하고 해결한 과정을 기록했다.
1. AdSense 기본 연동 방식
AdSense를 웹사이트에 연동하는 가장 기본적인 방법은 다음과 같다.
<head>태그 내에 AdSense 스크립트 로더를 삽입한다.- 광고를 표시할 위치에
<ins>태그 형태의 광고 단위를 삽입한다.
예를 들어, Astro 프로젝트의 src/layouts/BaseLayout.astro 파일에 다음과 같이 스크립트를 추가했다.
---
// src/layouts/BaseLayout.astro
import '../styles/global.css'; // 예시
---
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>{frontmatter.title}</title>
<!-- AdSense 스크립트 -->
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-YOUR_ADSENSE_CLIENT_ID"
crossorigin="anonymous"></script>
</head>
<body>
<slot />
</body>
</html>
그리고 본문 콘텐츠(src/pages/posts/[slug].astro 등) 내에 광고 단위를 삽입했다.
<!-- src/pages/posts/[slug].astro (예시) -->
<article>
<h1>{frontmatter.title}</h1>
<!-- ... 본문 내용 ... -->
<div class="ad-container">
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-YOUR_ADSENSE_CLIENT_ID"
crossorigin="anonymous"></script>
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-YOUR_ADSENSE_CLIENT_ID"
data-ad-slot="YOUR_ADSENSE_AD_SLOT_ID"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(window.adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
<!-- ... 나머지 본문 내용 ... -->
</article>
이렇게 설정한 후 블로그를 배포했다. 첫 페이지 로드 시에는 광고가 정상적으로 나타났다.
2. 페이지 전환 시 광고 누락 문제 분석
문제는 Astro의 SPA(Single Page Application)와 유사한 페이지 전환 방식에서 발생했다. Astro는 View Transitions API를 활용하여 부드러운 페이지 전환을 구현한다. 이는 전체 페이지를 새로고침하는 대신, DOM의 일부만 교체하여 사용자 경험을 향상시킨다.
하지만 이러한 방식은 AdSense 스크립트가 예상하는 동작 방식과 충돌을 일으켰다. AdSense 스크립트는 일반적으로 페이지가 완전히 로드될 때 한 번 실행되어 광고를 배치한다. 페이지 전환 시 DOM은 업데이트되지만, 자바스크립트 스크립트가 다시 실행되지 않거나, 실행되더라도 이전에 로드된 광고 컨텍스트를 재사용하지 않아 새로운 광고 요청이 발생하지 않았던 것이다. 결과적으로, 한 페이지에서 다른 페이지로 이동하면 광고 영역은 비어있게 되었다.
개발자 도구로 네트워크 요청을 확인해보니, 첫 페이지 로드 시에는 AdSense 관련 요청이 있었지만, 이후 페이지 전환 시에는 광고 관련 스크립트 요청이 발생하지 않았다.
3. 해결 방안: astro:after-swap 이벤트와 수동 광고 요청
이 문제를 해결하기 위해 Astro의 뷰 트랜지션 라이프사이클 이벤트와 AdSense 스크립트의 수동 광고 요청 기능을 활용하기로 했다.
Astro는 뷰 트랜지션이 완료된 후 astro:after-swap 이벤트를 발생시킨다. 이 이벤트를 감지하여 광고 관련 스크립트를 다시 실행하도록 지시하면, 페이지 전환 후에도 광고가 정상적으로 로드될 것이라고 판단했다.
AdSense는 <script>(window.adsbygoogle = window.adsbygoogle || []).push({});</script> 구문을 통해 수동으로 광고를 요청할 수 있는 기능을 제공한다. 이 구문을 astro:after-swap 이벤트 발생 시 호출하면 된다.
4. 구현
다음과 같은 절차로 문제를 해결했다.
-
광고 리로더 스크립트 파일 생성:
src/scripts/adsense-reloader.js파일을 생성하고 아래 내용을 추가했다.// src/scripts/adsense-reloader.js document.addEventListener('astro:after-swap', () => { console.log('astro:after-swap 이벤트 감지. AdSense 재로딩 시도.'); // 기존 AdSense 광고 요소를 찾아 초기화 const adContainers = document.querySelectorAll('.adsbygoogle[data-ad-client]'); adContainers.forEach(ad => { // 광고 컨테이너 내부를 비움 ad.innerHTML = ''; // 기존 data-adsbygoogle-status 속성 제거 (새로운 광고 로드를 위해 필요) ad.removeAttribute('data-adsbygoogle-status'); }); // window.adsbygoogle가 정의되었는지 확인하고 광고를 다시 요청 if (typeof window.adsbygoogle !== 'undefined') { try { (window.adsbygoogle = window.adsbygoogle || []).push({}); console.log('AdSense 광고 재요청 성공.'); } catch (e) { console.error('AdSense 재요청 중 오류 발생:', e); } } else { console.warn('window.adsbygoogle 객체가 정의되지 않았습니다. AdSense 스크립트 로드 여부를 확인하세요.'); } });코드 설명:
document.addEventListener('astro:after-swap', ...): Astro의 페이지 전환이 완료된 후 발생하는 이벤트를 감지한다.document.querySelectorAll('.adsbygoogle[data-ad-client]'): 페이지 내의 모든 AdSense 광고 단위를 선택한다.ad.innerHTML = '';: 기존에 로드된 광고 콘텐츠를 제거하여 깨진 광고가 노출되지 않도록 한다.ad.removeAttribute('data-adsbygoogle-status');: AdSense 스크립트는 이 속성을 통해 광고의 상태를 관리한다. 이 속성을 제거해야 새로운 광고 요청으로 인식된다.(window.adsbygoogle = window.adsbygoogle || []).push({});: 이 핵심 구문을 통해 AdSense 스크립트에 “새로운 광고 단위를 발견했으니 처리하라”고 지시한다.
-
BaseLayout.astro에 스크립트 연결: 생성한 스크립트가 모든 페이지에서 작동하도록BaseLayout.astro파일에 연결한다.--- // src/layouts/BaseLayout.astro import '../styles/global.css'; // 예시 --- <html lang="ko"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <title>{frontmatter.title}</title> <!-- AdSense 스크립트 --> <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-YOUR_ADSENSE_CLIENT_ID" crossorigin="anonymous"></script> <!-- AdSense 재로딩 스크립트 추가 --> <script type="module" src="../scripts/adsense-reloader.js"></script> </head> <body> <slot /> </body> </html>주의:
type="module"을 사용하여 모듈 스크립트로 로드하는 것이 일반적이며, Astro 빌드 시스템이 이를 처리한다. 만약 스크립트가 DOM에 직접 접근해야 하는 경우is:inline이나client:디렉티브를 고려할 수 있다. 여기서는astro:after-swap이벤트를 감지하므로type="module"만으로 충분하다.
5. 결과
위와 같이 수정 배포한 결과, Astro 블로그에서 페이지를 전환해도 AdSense 광고가 정상적으로 로드되고 노출되는 것을 확인했다. astro:after-swap 이벤트 리스너와 window.adsbygoogle.push({});의 조합이 Astro의 SPA-like 동작 환경에서 AdSense를 안정적으로 운영하는 핵심이었다.
이 삽질을 통해 Astro의 뷰 트랜지션 동작 방식과 외부 스크립트 연동 시 고려해야 할 사항에 대해 깊이 이해하게 되었다.
DevBJ | No Bio, Just Log 기술 삽질로그