StageUp
Web SDKAdvertisements

Common Features

This document gathers the "common concepts" that were repeated across the individual ad type documents into one place to make maintenance easier, so that the ad type documents can focus on the features unique to each type.

๐Ÿงฑ Basic Structure & Common Call Pattern

// 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);

Common Pattern for React / Next.js Provider

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 }} />;
}

โš™๏ธ Common Options Summary

OptionTypeDescriptionApplies To
onClickfunction(adData)Callback when the ad is clickedAll types
adIdstringForce a specific adAll types
language'ko' | 'en' | 'ja' | 'zh'Language filterAll types
deviceType'MOBILE' | 'DESKTOP'Device filterAll types
countryCountry code (ISO2)Country filterAll types

For options unique to each ad type, refer to the respective document (banner/text/video).

๐Ÿ”„ Lifecycle & Internal Behavior

graph TD
  A[init ํ˜ธ์ถœ] --> B[slot ํ•จ์ˆ˜ ํ˜ธ์ถœ]
  B --> C[์ปจํ…Œ์ด๋„ˆ ํƒ์ƒ‰/์žฌ์‹œ๋„]
  C --> D[์„œ๋ฒ„ ๊ด‘๊ณ  ์š”์ฒญ]
  D --> E[๋น„๋™๊ธฐ ๋กœ๋”ฉ]
  E --> F[๋ Œ๋”๋ง]
  F --> G[๋…ธ์ถœ ์ถ”์ ]
  G --> H[ํด๋ฆญ/์ƒํ˜ธ์ž‘์šฉ ์ถ”์ ]

Key Characteristics

  • Immediate-return type: slotId is returned immediately before the server responds โ‡’ no UI blocking
  • Handling of deferred containers: even if the container is not yet in the DOM, it will retry for a certain time and render once it is attached
  • Automatic cleanup based on MutationObserver: destroy() runs automatically when the DOM is removed
  • Multi-ad safe: when the same container is called repeatedly, only the latest call is valid (implementation policy)

๐Ÿงช Slot Management API

// ๋ชจ๋“  ์Šฌ๋กฏ ์ •๋ณด
const all = AdStage.ads.getAllSlots();
 
// ํŠน์ • ์Šฌ๋กฏ ์กฐํšŒ
const slot = AdStage.ads.getSlotById(slotId);
 
// ์ˆ˜๋™ ์ œ๊ฑฐ (ํ•„์š”ํ•œ ๊ฒฝ์šฐ)
AdStage.ads.destroy(slotId);

Slot object (actual fields):

interface AdSlot {
  id: string;                 // ์Šฌ๋กฏ ID (slotId)
  containerId: string;        // ์ปจํ…Œ์ด๋„ˆ DOM id
  adType: 'BANNER' | 'TEXT' | 'VIDEO' | 'NATIVE' | 'INTERSTITIAL' | 'POPUP';
  width: number | string;     // ์ˆซ์ž(px) ๋˜๋Š” ๋ฌธ์ž์—ด('100%' ๋“ฑ)
  height: number | string;    // ์ˆซ์ž(px) ๋˜๋Š” ๋ฌธ์ž์—ด('auto' ๋“ฑ)
  isLoaded: boolean;          // ๊ด‘๊ณ  ๋กœ๋“œ ์™„๋ฃŒ ์—ฌ๋ถ€
  isVisible: boolean;         // ๋…ธ์ถœ ์ƒํƒœ
  refreshRate: number;        // ์ž๋™ ์ƒˆ๋กœ๊ณ ์นจ ์ฃผ๊ธฐ(์ดˆ)
  lazyLoad: boolean;          // ์ง€์—ฐ ๋กœ๋”ฉ ์—ฌ๋ถ€
  targeting: Record<string, any>;
 
  // ์Šฌ๋กฏ ๋ฉ”์„œ๋“œ
  load(): Promise<Advertisement | null>;
  render(ad: Advertisement): void;
  refresh(): Promise<void>;
  destroy(): void;
}

๐Ÿš€ Common Performance & Optimization Strategies

StrategyDescriptionNotes
Background loadingNo blocking of initial render thanks to async loadingslotId is usable immediately
Deferred container supportAutomatically handles cases where the DOM is inserted laterSimplifies initialization code
Automatic cleanupPrevents memory/event leaksUseful during SPA transitions
Minimal DOM manipulationUpdates only the DOM inside the containerMinimizes impact on parent layout
Size optimization per typeBanner/video specify size, text uses automatic heightReduces CLS

Common Template for Responsive Pattern

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() });
});
PatternDescriptionWhen to Use
Global initialization via ProviderConfigure the SDK only onceApp/RootLayout
Hook (useAdStageInstance)Safe SDK accessCSR component
cleanup in useEffectGuarantees destroyClarifies slot lifetime
Skeleton styleCustomize the .adstage-loading stateImproves UX

๐ŸŽจ Common CSS Classes

.adstage-ad, .adstage-text-ad, .adstage-video-ad { position: relative; overflow: hidden; }
.adstage-loading { opacity: .6; transition: opacity .15s; }
.adstage-loaded { opacity: 1; }
.adstage-error { outline: 1px solid #f87171; }

For additional styles per type, refer to the individual documents.

๐Ÿ›  Debugging & Monitoring

Enabling Debug Mode

AdStage.init({ apiKey: 'your-api-key', debug: true });

Click Hook (onClick callback)

The SDK does not emit DOM CustomEvents such as adstage:ad:loaded / adstage:ad:error. If you need an ad interaction hook, pass an onClick callback when creating the slot.

AdStage.ads.banner('banner-container', {
  width: '100%',
  height: 250,
  onClick: (adData) => {
    console.log('๊ด‘๊ณ  ํด๋ฆญ๋จ:', adData);
    // ์ถ”๊ฐ€ ์ถ”์ /๋ผ์šฐํŒ… ๋กœ์ง
  }
});

Checking Load Status

You can check whether loading has completed by polling the slot's isLoaded field (if you turn on debug mode, load/failure is printed to the console).

const slotId = AdStage.ads.banner('banner-container', { width: '100%', height: 250 });
 
const timer = setInterval(() => {
  const slot = AdStage.ads.getSlotById(slotId);
  if (slot?.isLoaded) {
    console.log('๋กœ๋“œ ์™„๋ฃŒ:', slot);
    clearInterval(timer);
  }
}, 200);

State Diagnostic Utility

function dumpAdStage() {
  const slots = AdStage.ads.getAllSlots();
  console.table(slots.map(s => ({
    id: s.id,
    containerId: s.containerId,
    adType: s.adType,
    isLoaded: s.isLoaded
  })));
}

๐Ÿ” Safety & Best Practices

TopicRecommendation
API KeyIt can be publicly exposed, but use a key with minimal permissions
Event trackingWhen adding tracking in onClick, sending asynchronously before routing is recommended
Error handlingDiagnose load failures using debug mode console logs and the slot's isLoaded state
Retry policyThe deferred container insertion case is handled internally โ†’ avoid overusing additional setTimeout

โ“FAQ (Common)

Q. Do I have to call destroy()?
A. In most cases, no. DOM removal detection is performed automatically. However, if you reuse the same container immediately for a different purpose, a manual destroy() is recommended.

Q. The ad isn't showing, but the slotId is returned.
A. It may still be loading asynchronously, or it may have been filtered out by a filter (adId / language / deviceType / country). Enable debug mode and check the event log.

Q. With SSR (Next.js), is it rendered on the server side?
A. No. Ad rendering is performed only on the client side. Call it inside a use client component.

Q. What happens with consecutive calls at the same location?
A. Per the implementation policy, the existing slot is removed and the state is maintained based on the last call.

Table of Contents