StageUp
Web SDKAdvertisements

Common Features

This document centralizes the shared concepts previously duplicated in each ad type guide so that individual type docs can focus on their unique capabilities.

🧱 Core Structure & Shared Invocation Pattern

// 1) One‑time SDK initialization (app global)
AdStage.init({
  apiKey: 'your-api-key',
  debug: process.env.NODE_ENV === 'development'
});
 
// 2) Invoke after container DOM exists (accepts id or Element)
const slotId = AdStage.ads.banner('banner-container', { /* options */ });
// const slotId = AdStage.ads.text(element, { /* options */ });
// const slotId = AdStage.ads.video('video-wrapper', { /* options */ });
 
// 3) Optional manual cleanup (usually NOT needed: auto disposal)
AdStage.ads.destroy(slotId);

React / Next.js Provider Pattern (Shared)

import { AdStageProvider, useAdStageInstance } from '@adstage/web-sdk';
 
// layout / root
<AdStageProvider config={{ apiKey: process.env.NEXT_PUBLIC_ADSTAGE_API_KEY, debug: true }}>
  {children}
</AdStageProvider>
 
// component
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 }} />;
}

⚙️ Shared Option Summary

OptionTypeDescriptionApplies To
onClickfunction(adData)Callback on ad clickAll
adIdstringForce a specific adAll
language`'ko''en''ja'
deviceType`'MOBILE''DESKTOP'`Device filter
countryISO2 country codeCountry filterAll

Type‑specific options are documented in each (banner / text / video) guide.

🔄 Lifecycle & Internal Flow

graph TD
  A[init call] --> B[slot function]
  B --> C[Container lookup / retry]
  C --> D[Server ad request]
  D --> E[Async load]
  E --> F[Render]
  F --> G[Impression track]
  G --> H[Click / interaction track]

Key Characteristics

  • Immediate return: slotId returned before server response ⇒ non‑blocking UI
  • Deferred container: retries if container not yet in DOM; renders later when available
  • MutationObserver auto cleanup: DOM removal triggers automatic destroy()
  • Multi‑ad safety: repeated calls on same container keep only the latest (implementation policy)

🧪 Slot Management API

// All slots
const all = AdStage.ads.getAllSlots();
 
// Get one slot
const slot = AdStage.ads.getSlotById(slotId);
 
// Manual removal (if needed)
AdStage.ads.destroy(slotId);

Example slot shape:

interface AdStageSlot {
  id: string;
  type: 'banner' | 'text' | 'video';
  container: HTMLElement;
  status: 'pending' | 'loading' | 'loaded' | 'error' | 'destroyed';
  meta?: Record<string, any>;
}

🚀 Performance & Optimization Strategies

StrategyExplanationNotes
Background loadingAsync load avoids blocking initial paintslotId is immediate
Delayed container supportHandles late DOM insertion automaticallySimplifies init code
Auto cleanupPrevents memory/event leaksHelpful in SPA navigations
Minimal DOM mutationOnly inner container updatedReduces layout shifts
Type‑aware sizingBanner/Video sized; Text auto heightLowers CLS

Responsive Pattern Template

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
Global ProviderSingle SDK initApp / RootLayout
Hook (useAdStageInstance)Safe SDK accessCSR components
Cleanup in useEffectGuarantees destroyClarifies slot lifetime
Skeleton stylingCustomize .adstage-loadingUX polish

🎨 Shared 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; }

See type docs for additional styling specifics.

🛠 Debugging & Monitoring

Enable Debug Mode

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

Listen to Custom Events

document.addEventListener('adstage:ad:loaded', e => {
  console.log('Loaded:', e.detail);
});
 
document.addEventListener('adstage:ad:error', e => {
  console.error('Load failed:', e.detail);
});

Diagnostic Helper

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

🔐 Safety & Best Practices

TopicRecommendation
API KeyPublic exposure acceptable but use least‑privileged key
Event trackingFor extra analytics in onClick, send async before navigation
Error handlingLog / alert on adstage:ad:error
Retry policyContainer delay handled internally → avoid redundant setTimeout loops

❓ FAQ (Shared)

Q. Do I need to always call destroy()?
A. Usually no. DOM removal is auto‑detected. Call manually only if you immediately reuse the same container for a different purpose.

Q. slotId is returned but nothing displays. Why?
A. It may still be loading, or filters (adId / language / deviceType / country) excluded available ads. Enable debug mode and inspect emitted events.

Q. Does this render server‑side in Next.js?
A. No. Rendering is client‑only. Invoke inside use client components.

Q. What happens on repeated calls for the same container?
A. Prior slot is removed; the latest invocation takes precedence (implementation policy).

Table of Contents