SwAdPopup
Ad Placement Four Essentials
- Use case: fullscreen popups triggered by business actions — button click / exit-intent / once every N swipes in a short-video feed (
SwVideoFeed @changecounter →popupRef.open()); slotKey e.g.feed_popup- Industry form: Interstitial / Vignette (AdSDK format
popup)- Visual form: fullscreen overlay + single images popped one by one (
sequential) or story-stream carousel (carousel) + dismissible countdown- Tracking events:
adImpression(reported as soon as the popup layer shows,ad_type=popup) /adClick; built-in zero-config, silent no-op when the gate is off⚠️ For the auto-popup-on-entry splash, use SwAdSplash, not this component (the
trigger=onloadmode has been removed). Picking the wrong scenario = wrongad_type/ timing in tracking. See Ad Component Selection.
SwAdPopup is the business-triggered fullscreen popup ad slot component — the business holds a ref and calls open() / close(); it does not pop automatically. It shares the same popup core as SwAdSplash (auto-popup on entry); the only differences are trigger method (manual vs auto-on-entry) + frequency default (0 vs session) + ad_type (popup vs splash). Multiple creatives can be shown sequentially or as a story-stream carousel. Impression / click tracking is built in.
Copy + CTA overlay (opt-in): when an item carries any of
title/description/cta/advertiser, a "headline + sub-copy + CTA button" overlay renders over the creative image (like a real ad); pass onlyimageto keep it image-only. The CTA is a button-styled<span>(the whole ad is already a link; clicks go tolink).
Manually triggered popup
Props
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
items | SwAdItem[] | ✓ | — | Ad creative array |
slotKey | string | ✓ | — | Ad slot key → ad_slot_key |
slotName | string | undefined | Ad slot name → ad_slot_name | |
pageKey | string | undefined | Page key → page_key | |
pageName | string | undefined | Page name → page_name | |
ratio | string | '3/4' | Popup creative aspect ratio | |
overlay | boolean | true | Show the overlay | |
mode | 'sequential' | 'carousel' | 'sequential' | Multi-creative: one-by-one / story-stream carousel | |
frequency | AdFrequencyStrategy | 'always' | Frequency strategy, defaults to 'always' (no capping) (the business gates open() timing itself); to layer on a cap pass 'session' / N days | |
frequencyKey | string | undefined | Frequency storage key (defaults to slotKey) | |
showAdLabel | boolean | undefined | "Ad" compliance badge; when not set it follows the global swiftConfig.ad.showLabel (default true), an explicit value always wins | |
autoplayDelay | number | 3000 | carousel interval (ms) | |
closableAfter | number | 0 | Closable only after N milliseconds (mis-close guard; 0 = closable immediately) | |
loop | boolean | true | Whether carousel loops |
Events
| Name | Payload | Description |
|---|---|---|
open | — | Popup opened |
close | — | Popup closed |
empty | — | items empty (no popup) |
impression | items: SwAdItem[] | Impression (auto tracking) |
click | item: SwAdItem | Creative clicked (auto tracking) |
error | — | Render / load error |
Exposed methods (ref)
| Method | Description |
|---|---|
open() | Open the popup (call it at the business trigger moment; if frequency is set and not hit, it silently doesn't pop) |
close() | Close the popup |
Story-stream carousel + optional frequency capping
mode="carousel" shows multiple creatives as a story stream, with a closableAfter countdown and autoplayDelay switching interval. frequency defaults to 0 (no capping — every open() pops); to layer on a cap (e.g. a feed's "every N swipes but at most one round per session") pass frequency="session":
Story-stream carousel popup
Sequential mode (default)
closableAfter countdown lock
<!-- Manual trigger -->
<SwAdPopup ref="popupRef" :items="ads" slot-key="promo" />
<SwButton @click="popupRef?.open()">View campaign</SwButton>
<!-- Once every 5 swipes in a short-video feed, at most one round per session -->
<SwAdPopup ref="feedPopup" :items="ads" slot-key="feed_popup" frequency="session" />
<!-- SwVideoFeed @change: if (++count % 5 === 0) feedPopup.value?.open() -->
<!-- Non-modal (overlay=false, background not locked) + carousel stops at the last slide (loop=false) +
frequency-key: explicit capping storage key (defaults to slot-key; change the key on release to reset capping) -->
<SwAdPopup :items="ads" slot-key="promo" mode="carousel" :overlay="false" :loop="false" frequency-key="promo-2026q3" />
Style Tokens
Knobs of the shared AdPopupBase kernel (SwAdSplash uses the exact same set; the fallback is the default):
| Variable | Default | Description |
|---|---|---|
--sw-ad-popup-overlay-bg | rgb(0 0 0 / 60%) | Popup scrim background |
--sw-ad-popup-topbar-gradient | linear-gradient(180deg, rgb(0 0 0 / 50%) 0%, rgb(0 0 0 / 0%) 100%) | Top-bar gradient scrim (backdrop for the close button / counter) |
--sw-ad-popup-seq-color | rgb(255 255 255 / 90%) | Carousel counter text color |
--sw-ad-popup-seq-border | rgb(255 255 255 / 60%) | Carousel counter border color |
--sw-ad-popup-bar-track | rgb(255 255 255 / 25%) | Progress track color |
--sw-ad-popup-bar-fill | var(--primary) | Progress filled color |
--sw-ad-popup-nav-bg | rgb(0 0 0 / 35%) | Prev/next navigation button background |
--sw-ad-popup-nav-color | rgb(255 255 255) | Prev/next navigation icon color |
--sw-ad-popup-pill-bg | rgb(255 255 255 / 12%) | Pill button background (e.g. "skip") |
--sw-ad-popup-pill-bg-hover | rgb(255 255 255 / 22%) | Pill button hover background |
--sw-ad-popup-pill-color | rgb(255 255 255) | Pill button text color |
The title / description / CTA overlay on the creative is rendered by the internal
AdOverlay; its knobs are--sw-ad-overlay-*(shared by three ad components) — see SwAdPreroll · Creative Overlay Tokens.
Caveats
- The business owns trigger timing — the component doesn't pop automatically; the business holds a
refand callsopen()at the right moment (click / exit intent / feed swipe counter, etc.). frequencydefaults to'always'(no capping); pass'session'/ N days to layer on a capping cap (useAdFrequency; on a missopen()silently doesn't pop).- When
closableAfter > 0, closing is blocked during the countdown (mis-touch guard); the close button appears when it ends. - Tracking is built in (
ad_type=popup) and behind the tracker's double gate.