개발
구글 애드센스 광고 로딩 안되면 영역 감추기 (3) ~ 사용자 인터렉션 핸들러
나는 내 블로그를 1부터 싹다 만든 케이스라 어떤 플랫폼이나 애드온에 도움을 받지않고 광고 스크립트 코드를 바로 적용해야 하는 상황이었다.
일반적으로 구글 광고 코드는 문서내에 직접 삽입하는 방식이거나 자동 광고를 켜놓아서 광고 스크립트가 로드될 시 알아서 광고가 채워지도록 만들어야한다.
다만 이런 스크립트 실행은 본문의 랜더링 속도에 크게 영향을 끼치기 마련이고 최악의 경우엔 '느린 사이트'로 인지될수도 있는 단점을 가지고있다.
무엇보다도 보여줄 내용이 많으면 그만큼 광고가 지연되어서 뜨기 마련이고, 이렇게 뜨는 광고는 하나같이 제대로된게 붙는 경우가 없는 웃긴 상황이 많다.

관련된 내용으로 많은 정보를 검색해보았지만 내 상황에 딱 맞는 문제 제시나 해결방안이 없어서 몇달간 끙끙 앓는 문제로 놔두게 되었다.
그러다가 최근에 워드프레스로 최적화가 정말 잘된 사이트가 있어서 코드를 뜯어보고 여러 테스트를 진행해본바, 광고 스크립트를 자체적으로 늦게 로드하면 위의 문제 대부분을 해결할 수 있다는 사실을 알게되었다.
애드센스 스크립트 지연 로드
우리가 일반적으로 애드센스 스크립트를 넣는다하면
html
의 head
부분에 애드센스에서 제공하는 스크립트를 넣거나 본문에 일일히 삽입하는 방식을 취하게된다.
당장 수동 단위 광고를 만들고 코드를 달라고해도 위와같이
html
코드내에 바로 넣을수 있는 덩어리를 주게된다.이말은 즉슨 해당 페이지가 처음에 랜더링(로드)될때 해당 광고도 이어서 로드될 수 있도록 만든 정석적인 코드이다.
다만 이런 방식은 페이지 로드 시 광고를 바로 요구한다는점에서 페이지 자체 랜더링 속도를 지연시킬 수 있으며 이것은 사용자 인터넷 환경이나 디바이스 환경에 매우 의존적인 코드라고 볼 수 있다.
무엇보다도 이런방식으로 처리하면 웹 지표(코어 웹 바이탈)에서 소위말하는 '느린 사이트'로써 낙인 찍히게 된다.
왜 갑자기 웹 지표이야기?
여기서 웹 지표 이야기가 갑자기 튀어나와서 뭔가 싶겠지만, 우리가 흔히 말하는 최적화 사이트는 여러가지를 웹페이지를 수집하는 주체에 제공할때 우리 사이트가 좋은 사이트라는걸 알리기위해 여러 작업을 해둔 사이트를 말한다.
단순히 보아서는 SEO 최적화를 한 사이트에서부터 시작해 위에서 언급한 사이트 랜더링 속도에 대한 최적화 과정까지 모든걸 맞춘 사이트를 뜻하는 것이다.
여기서 요즘에는 코어 웹 바이탈이라는 웹 지표가 웹사이트를 판단하는 중요 지표로 작용하는데, 이를 잘 해소하기위해서는 웹에서 사용하는 이미지의 경량화, 스크립트 경량화, 스타일코드 경량화, 외부 코드 사용 지양 등 여러가지 기술적 요소가 필요하다.
근데 여기서 대부분의 광고 코드는 이런 지표를 망가트리는 1등 주범이다.
이런 웹 지표를 검색할땐 자체적인 검사기를 통해 여러가지를 판단하게되는데, 여기서 이 검사기의 약점이라고 해야하나 하나의 허점이 있다.
바로 "실제 사용자처럼 인터렉션 이벤트를 작동하지 않는다는 점"이다.
그래서 상대적으로 무겁고 제어하기 어려운 애드센스 광고 스크립트를 이런 허점을 이용한 트리거&지연로딩 방식으로 우회하는것이다.
광고 로딩 최적화
핵심은 아래 코드와 같다.
function initAdScript() {
const doInit = () => {
initAd();
// 이벤트 제거
window.removeEventListener('scroll', handleUserInteraction);
window.removeEventListener('mousemove', handleUserInteraction);
window.removeEventListener('touchstart', handleUserInteraction);
window.removeEventListener('keydown', handleUserInteraction);
};
const handleUserInteraction = () => doInit();
// 사용자 입력 감지
window.addEventListener('scroll', handleUserInteraction, { passive: true });
window.addEventListener('mousemove', handleUserInteraction, { passive: true });
window.addEventListener('touchstart', handleUserInteraction, { passive: true });
window.addEventListener('keydown', handleUserInteraction);
// 시간 초과 시 강제 초기화 (예: 5초 후)
setTimeout(doInit, 5000);
}
Copy
광고를 로딩하는 함수
initAd
를 그냥 실행시키는게아니라 사용자의 인터렉션, 스크롤, 마우스 움직임, 터치 시작, 키입력 등을 트리거로해 작동시키거나 이런 이벤트 핸들러가 작동되지않는다면 5초의 긴 시간뒤에 천천히 로딩을 시키는 것이다.function initAd() {
if (initAd.hasInitialized) return;
initAd.hasInitialized = true;
// 애드센스 스크립트 삽입
const s = document.createElement('script');
s.async = true;
s.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-000000000000';
s.crossOrigin = 'anonymous';
s.onload = () => {
document.querySelectorAll('.adsbygoogle').forEach((el) => {
if (!el.getAttribute('data-adsbygoogle-status')) {
(adsbygoogle = window.adsbygoogle || []).push({});
}
});
setTimeout(() => {
initAdClean();
}, 1000); // 광고 렌더링 시간 확보
};
document.head.appendChild(s);
}
Copy
그리고 광고 스크립트를 위와 같이 동적으로 삽입(injection) 시켜 초기 랜더링과 별개의 작업으로 분리 시키는 것이다.
<ins class="adsbygoogle" style="display:block;width:300px;height:600px" data-ad-client="ca-pub-0000000000000" data-ad-slot="0000000000000"></ins>
Copy
그리고 실제로 광고가 띄워질 위치는 위에처럼 간단한
ins
태그로 삽입시키면 된다.최종적으로 initAdClean을 통해 광고 로드 작업 1초 이후에 로드가 되지않은 광고를 일괄 삭제하면 지연로딩과 안보이는 광고에 대한 삭제처리까지 깔끔하게 작업이 가능하다.
function initAdClean() {
if (initAdClean.hasInitialized) return;
initAdClean.hasInitialized = true;
setTimeout(() => {
const ads = document.querySelectorAll('.adsbygoogle');
ads.forEach(ad => {
const wrapper = ad.closest('.ad, .google-auto-placed');
if (!wrapper) return;
const status = ad.getAttribute('data-ad-status');
if (status !== 'filled') {
wrapper.remove();
fetchAsidePost();
}
});
}, 500);
}
Copy
나는 속도 최적화를 위해서 단순하게 0.5초의 타임아웃 이후에 위 코드 처리를했다만 제대로하려면 뷰포트 검사방식을 통해 해당 코드를 보완하는것도 나쁘지 않다.
위의
fetchAsidePost
함수는 내 사이트 한정으로 사이드바 광고 로드가 안되면 내 컨텐츠를 띄워주는 코드이다.본문 내용이 길때 Intersection Observer 방식으로
위 코드처럼 그냥 0.5초만에 검사해서 처리해버리니까 뷰포트 바깥의 광고, 그러니가 하단 푸터광고 같은게 바로바로 날라가버리는 문제가 발생했다.
이부분만 인터섹션 옵저버 기능을 이용해 보완해보았다.
function initAdClean() {
if (initAdClean.hasInitialized) return;
initAdClean.hasInitialized = true;
const ads = document.querySelectorAll('.adsbygoogle');
const observer = new IntersectionObserver((entries, obs) => {
entries.forEach(entry => {
const ad = entry.target;
if (!entry.isIntersecting) return;
const wrapper = ad.closest('.ad, .google-auto-placed');
if (!wrapper) return;
let elapsed = 0;
const maxWait = 1000;
const interval = 200;
const checkAdInterval = setInterval(() => {
const status = ad.getAttribute('data-ad-status');
if (status === 'filled') {
clearInterval(checkAdInterval);
} else if (elapsed >= maxWait) {
clearInterval(checkAdInterval);
wrapper.remove();
if (!fetchAsidePost.hasFetched) {
fetchAsidePost();
}
}
elapsed += interval;
}, interval);
obs.unobserve(ad); // 1번만 처리
});
}, {
root: null,
rootMargin: '1000px 0px',
threshold: 0.1 // 요소가 10% 이상 보이면 감지
});
ads.forEach(ad => {
observer.observe(ad);
});
}
Copy
일단 이렇게 보완하니 잘보인다.
결론
이런류의 지연 스크립트 처리는 처음에 페이지를 로드할때 일부 핵심 스크립트가 누락되어있어 어떤 시점으로보면 약간 기만에 가깝다만, 반대로 말하면 초기에 빠른 페이지 로딩을 제공한 이후 필요에 따라 선택적으로 스크립트를 제공할 수 있다는 부분으로만 보면 웹 페이지 서비스에 대한 하나의 전략이라고도 생각할 수 있지 않을까 싶다.
어찌되었든 위 코드를 구상하면서 정말 여러가지를 배웠다는거에 의의를 가져볼까 한다!
#광고 #JavaScript
0
개의 댓글
개발 카테고리의 다른 글

05/30
페이지 로드 완료시 addEventListener 적용 순서 및 전략
사이트 최적화 작업을 하면서 스크립트를 정리하고있는데, 지피티가 개선해준 코드와 내 원래코드간의 이벤트 핸들링 기법이 달라서 이왕에 Javascript 방식의 이벤트 핸들러로 전부 교체하는 작업을 진행했다. 자바스크립트에서는 기본적으로 addEventListener 기능을 이용해서 이벤트 핸들러를 여러개 추가하는 방식으로...

05/26
yt-dlp nsig 에러 해결 방법 (버전 문제)
최근에 유튜브 영상 하나 다운받고 싶은게 있어서 오랜만에 yt-dlp를 이용해서 영상 다운로드를 실행해보았다. 근데 평상시처럼 다운로드가 되지않고 경고와 에러코드가 주르륵 뜨면서 다운이 안되는것이 아닌가... 뭔가 심상치 않다. 그래서 에러 코드를 잘 읽어보고 문제를 파악해보았더니, 유튜브 측에서 URL에 담겨있는...

05/22
챗지피티(ChatGPT) 환각 증상 줄이는 프롬프트
비단 챗지피티뿐만이 아닌 대부분의 LLM AI 서비스는 자신들이 모르는 정보에 대해서 솔직하게 모른다라고 답변하지않고 최대한 설명을하려는 본능에 따라 잘못된 정보를 우리에게 주곦나다. 이런 현상을 환각(Hallucination)이라 부르면서 현재 사용자는 이런 AI의 맹점을 확인하며 자료를 검토하는 방식의 사용이 주를 이...