공통 기능 이 문서는 개별 광고 타입 문서에 반복되던 "공통 개념"을 한 곳에 모아 유지보수를 쉽게 하고, 광고 타입 문서는 각 타입 고유 기능 에 집중할 수 있도록 합니다.
// 1) SDK 초기화 (앱 전역 1회)
AdStage. init ({
apiKey: 'your-api-key' ,
debug: process.env. NODE_ENV === 'development'
});
// 2) 컨테이너 DOM 준비 후 호출 (id 또는 Element 모두 허용)
AdStage.ads. banner ( 'banner-container' , { /* 옵션 */ });
// AdStage.ads.text(element, { /* 옵션 */ });
// AdStage.ads.video('video-wrapper', { /* 옵션 */ });
// 3) 필요 시 수동 제거 (대부분 필요 없음: 자동 정리 지원)
AdStage.ads. destroy (slotId);
import { AdStageProvider, useAdStageInstance } from '@adstage/web-sdk' ;
// layout / root
< AdStageProvider config = {{ apiKey: process.env. NEXT_PUBLIC_ADSTAGE_API_KEY , debug: true }}>
{children}
</ AdStageProvider >
// 개별 컴포넌트
function BannerSlot () {
const adstage = useAdStageInstance ();
const ref = useRef ( null );
useEffect (() => {
if ( ! adstage || ! ref.current) return ;
const id = adstage.ads. banner (ref.current, { width: '100%' , height: 250 });
return () => adstage.ads. destroy (id);
}, [adstage]);
return < div ref = {ref} style = {{ height: 250 }} />;
}
옵션 타입 설명 적용 대상 onClickfunction(adData)광고 클릭 시 콜백 전 타입 adIdstring특정 광고 강제 지정 전 타입 language'ko' | 'en' | 'ja' | 'zh'언어 필터 전 타입 deviceType'MOBILE' | 'DESKTOP'디바이스 필터 전 타입 country국가 코드 (ISO2) 국가 필터 전 타입
광고 타입별 고유 옵션은 각 문서(배너/텍스트/비디오) 참조.
graph TD
A[init 호출] --> B[slot 함수 호출]
B --> C[컨테이너 탐색/재시도]
C --> D[서버 광고 요청]
D --> E[비동기 로딩]
E --> F[렌더링]
F --> G[노출 추적]
G --> H[클릭/상호작용 추적]
즉시 반환형: slotId는 서버 응답 전 즉시 반환 ⇒ UI 블로킹 없음
지연 컨테이너 대응: 컨테이너가 아직 DOM에 없어도 일정 시간 재시도 후 붙으면 렌더링
MutationObserver 기반 자동 정리: DOM 제거 시 destroy() 자동 실행
다중 광고 안전: 동일 컨테이너 중복 호출 시 최신 호출만 유효 (구현체 정책)
// 모든 슬롯 정보
const all = AdStage.ads. getAllSlots ();
// 특정 슬롯 조회
const slot = AdStage.ads. getSlotById (slotId);
// 수동 제거 (필요한 경우)
AdStage.ads. destroy (slotId);
슬롯 객체(예시 형태):
interface AdStageSlot {
id : string ;
type : 'banner' | 'text' | 'video' ;
container : HTMLElement ;
status : 'pending' | 'loading' | 'loaded' | 'error' | 'destroyed' ;
meta ?: Record < string , any >;
}
전략 설명 비고 백그라운드 로딩 비동기 로딩으로 초기 렌더 차단 없음 slotId 즉시 사용 가능지연 컨테이너 지원 DOM 나중 삽입 케이스 자동 처리 초기화 코드 단순화 자동 정리 메모리/이벤트 릭 방지 SPA 전환 시 유용 최소 DOM 조작 컨테이너 내부 DOM만 업데이트 부모 레이아웃 영향 최소화 타입별 사이즈 최적화 배너/비디오는 크기 지정, 텍스트는 높이 자동 CLS 감소
function selectDeviceType () {
return window.innerWidth <= 768 ? 'MOBILE' : 'DESKTOP' ;
}
const base = { language: 'ko' , deviceType: selectDeviceType () };
const id = AdStage.ads. banner ( 'rwd-banner' , { width: '100%' , height: 250 , ... base });
window. addEventListener ( 'resize' , () => {
AdStage.ads. destroy (id);
const next = AdStage.ads. banner ( 'rwd-banner' , { width: '100%' , height: 250 , deviceType: selectDeviceType () });
});
패턴 설명 사용 시점 Provider 전역 초기화 한 번만 SDK 설정 App/RootLayout 훅(useAdStageInstance) 안전한 SDK access CSR 컴포넌트 cleanup in useEffect destroy 보장슬롯 수명 명확화 Skeleton 스타일 .adstage-loading 상태 커스터마이즈UX 개선
.adstage-ad , .adstage-text-ad , .adstage-video-ad { position : relative ; overflow : hidden ; }
.adstage-loading { opacity : .6 ; transition : opacity .15 s ; }
.adstage-loaded { opacity : 1 ; }
.adstage-error { outline : 1 px solid #f87171 ; }
타입별 추가 스타일은 개별 문서 참조.
AdStage. init ({ apiKey: 'your-api-key' , debug: true });
document. addEventListener ( 'adstage:ad:loaded' , e => {
console. log ( '로드 완료:' , e.detail);
});
document. addEventListener ( 'adstage:ad:error' , e => {
console. error ( '로드 실패:' , e.detail);
});
function dumpAdStage () {
const slots = AdStage.ads. getAllSlots ();
console. table (slots. map ( s => ({ id: s.id, type: s.type, status: s.status })));
}
주제 권장 사항 API Key 퍼블릭 노출 가능하나 권한 최소화된 키 사용 이벤트 추적 onClick에서 추가 추적 시 비동기 전송 후 라우팅 권장 오류 대응 adstage:ad:error 이벤트 로깅/알림 연동재시도 정책 컨테이너 지연 삽입 케이스 자체 처리 → 추가 setTimeout 남용 지양
Q. destroy()를 꼭 호출해야 하나요?
A. 대부분 필요 없습니다. DOM 제거 감지가 자동 수행됩니다. 다만 동일 컨테이너를 즉시 다른 용도로 재사용할 경우 수동 destroy()를 권장합니다.
Q. 광고가 안 뜨는데 slotId는 나옵니다.
A. 비동기 로딩 중이거나 필터(adId / language / deviceType / country)에 걸러졌을 수 있습니다. 디버그 모드를 활성화하고 이벤트 로그를 확인하세요.
Q. SSR(Next.js)에서 서버 측에서 렌더됩니까?
A. 아니요. 광고 렌더는 클라이언트 측에서만 수행됩니다. use client 컴포넌트 내부에서 호출하세요.
Q. 동일 위치에 연속 호출 시 어떻게 됩니까?
A. 구현 정책에 따라 기존 슬롯이 제거되고 마지막 호출 기준으로 유지됩니다.