useAdFrequency()

useAdFrequency is the ad display frequency-control composable, generic for any frequency-capped ad slot (e.g. the SwAdPopup entry popup). It isn't tied to "splash" semantics. Decision records go through the framework's encrypted cache utils (useSession / useLocal auto-prefix cachePrefix + AES-encrypt; no raw storage).

Parameters

useAdFrequency(key, strategy):

NameTypeRequiredDescription
keystring✓Unique key for the frequency record (e.g. 'home-popup'). Stored as ad_seen_<key> for devtools identification
strategyAdFrequencyStrategy✓Frequency strategy, see below

AdFrequencyStrategy ('session' \| 'always' \| PeriodSpec)

ValueMeaningStorage
'session'Show once per session, reset on tab closesessionStorage (encrypted)
number > 0Don't show again within N days (N may be fractional, e.g. 0.5 = 12h)localStorage (encrypted, stores timestamp)
0 / negativeShow every time (debug / uncapped)not read/written

Return Value

NameTypeDescription
shouldShow() => booleanWhether to show now. Returns false under SSR — frequency is a client-only decision
markShown() => voidMark as shown (writes to the encrypted cache)

Usage Examples

// Example 1: entry popup, once per session
const { shouldShow, markShown } = useAdFrequency('home-popup', 'session')
onMounted(() => {
  if (shouldShow()) {
    openPopup()
    markShown()
  }
})

// Example 2: promo popup, once every 3 days
const { shouldShow, markShown } = useAdFrequency('promo-2026', 3)
onMounted(() => {
  if (shouldShow()) {
    openPromo()
    markShown()
  }
})

// Example 3: uncapped during debugging (show every time)
const { shouldShow } = useAdFrequency('debug-ad', 0)

How It Works

  • The decision logic is extracted into the pure function shouldShowByStrategy(strategy, stored, now) (touches no storage / Date, for easy unit testing):
    • number <= 0 → always true (every time)
    • 'session' → true only when there's no mark (not shown this session)
    • number > 0 → true when there's no mark, or now - lastShown >= N days
  • shouldShow() returns false under SSR (!IS_CLIENT) to avoid server-side misjudgment + hydration mismatch.

Caveats

  • Check shouldShow() first, then markShown() — markShown isn't called automatically on display; the business must mark explicitly after actually showing.
  • Keep key globally unique; use distinct keys for distinct ad slots, otherwise frequency records overwrite each other.
  • SwAdPopup — popup ad component, often paired with this composable for entry frequency capping
  • Ad & Tracking