Skip to content
Tolinku
Tolinku
Sign In Start Free
Marketing · · 5 min read

Banner Frequency Capping: Finding the Right Balance

By Tolinku Staff
|
Tolinku seo app indexing dashboard screenshot for marketing blog posts

Every time your smart banner appears, it has a diminishing chance of converting the user. The first impression has the highest conversion probability. By the tenth impression, the user has already decided not to install and the banner is just noise. Frequency capping limits how often the banner appears, protecting user experience while preserving the conversion opportunities that matter.

This guide covers frequency capping strategies, implementation approaches, and how to find the right balance for your audience. For dismiss behavior (what happens when users actively close the banner), see banner dismiss behavior. For banner scheduling, see banner scheduling for campaigns.

Tolinku smart banners list with status, segment, and scheduling info The smart banners list showing banner titles, status toggles, segments, and action buttons.

Why Frequency Cap

Diminishing Returns

Banner conversion rates follow a predictable decay curve:

Impression # Relative CTR
1 100% (baseline)
2 70-80%
3 50-60%
5 30-40%
10 10-20%
15+ < 5%

After 5-10 impressions, the marginal conversion value of each additional impression approaches zero, while the annoyance cost continues to accumulate.

User Experience Cost

Each unnecessary banner impression:

  • Takes up screen space that could show content.
  • Adds cognitive load (the user must decide to ignore or dismiss it again).
  • Erodes trust ("this site keeps pushing its app on me").
  • Can increase bounce rate if the banner is too persistent.

The Balance

The goal is to show the banner enough times to capture users who are genuinely interested, but stop before you annoy users who are not. The right cap depends on your app, your audience, and the banner's content.

Types of Frequency Caps

Impression Cap

Limit the total number of times the banner is shown to a user:

function trackImpression() {
  const count = parseInt(localStorage.getItem('banner_impressions') || '0') + 1;
  localStorage.setItem('banner_impressions', count.toString());
  return count;
}

function isWithinCap() {
  const impressions = parseInt(localStorage.getItem('banner_impressions') || '0');
  return impressions < 10; // Show up to 10 times total
}

Recommended caps:

  • Evergreen banners (generic "get the app"): 5-10 impressions total
  • Campaign banners (time-limited promotions): 3-5 impressions
  • Aggressive banners (full-screen, floating): 2-3 impressions

Time-Window Cap

Limit impressions within a rolling time window:

function isWithinTimeWindowCap() {
  const impressionLog = JSON.parse(localStorage.getItem('banner_impression_log') || '[]');
  const windowMs = 24 * 60 * 60 * 1000; // 24 hours
  const maxPerWindow = 3;

  const now = Date.now();
  const recentImpressions = impressionLog.filter(ts => (now - ts) < windowMs);

  return recentImpressions.length < maxPerWindow;
}

function logImpression() {
  const impressionLog = JSON.parse(localStorage.getItem('banner_impression_log') || '[]');
  impressionLog.push(Date.now());

  // Keep only recent entries to avoid localStorage bloat
  const cutoff = Date.now() - (30 * 24 * 60 * 60 * 1000);
  const trimmed = impressionLog.filter(ts => ts > cutoff);
  localStorage.setItem('banner_impression_log', JSON.stringify(trimmed));
}

Recommended caps:

  • 1-2 impressions per session
  • 3-5 impressions per day
  • 10-15 impressions per week

Session Cap

Limit impressions per browsing session:

function isWithinSessionCap() {
  const sessionImpressions = parseInt(sessionStorage.getItem('banner_session_impressions') || '0');
  return sessionImpressions < 1; // Show once per session
}

A session cap of 1 means the user sees the banner once when they visit. If they dismiss it, it does not reappear during that visit. This is the least intrusive approach.

Page-Type Cap

Show the banner only on certain page types, limiting total exposure:

function shouldShowOnPage() {
  const path = window.location.pathname;

  // Show on product pages and article pages
  if (path.startsWith('/products/') || path.startsWith('/articles/')) {
    return true;
  }

  // Don't show on checkout, account, or utility pages
  return false;
}

This is not a frequency cap per se, but it limits the pages where the banner appears, effectively capping how often the user encounters it during a typical browse.

Combined Frequency Strategy

The most effective approach combines multiple cap types:

function shouldShowBanner() {
  // 1. Has the user already installed the app?
  if (hasInstalledApp()) return false;

  // 2. Is the banner permanently dismissed?
  if (isPermanentlyDismissed()) return false;

  // 3. Is the dismiss timer still active?
  if (isDismissTimerActive()) return false;

  // 4. Session cap: max 1 per session
  if (getSessionImpressions() >= 1) return false;

  // 5. Daily cap: max 3 per day
  if (getDailyImpressions() >= 3) return false;

  // 6. Total cap: max 15 lifetime
  if (getTotalImpressions() >= 15) return false;

  // 7. Page type check
  if (!isHighValuePage()) return false;

  return true;
}

This ensures:

  • No more than 1 impression per visit.
  • No more than 3 per day.
  • No more than 15 total.
  • Only on pages where the banner is relevant.
  • Respects active dismissals.

Resetting the Cap

New Campaign Reset

When you launch a new campaign with a fresh banner, consider resetting the impression counter:

function checkForNewCampaign(currentCampaignId) {
  const lastCampaignId = localStorage.getItem('banner_campaign_id');

  if (lastCampaignId !== currentCampaignId) {
    // New campaign: reset impression counters
    localStorage.setItem('banner_campaign_id', currentCampaignId);
    localStorage.setItem('banner_impressions', '0');
    localStorage.removeItem('banner_impression_log');
    // Keep dismiss state (don't reset if user actively dismissed)
  }
}

Reset the impression counter, but do not reset the dismiss state. A user who actively dismissed the banner has made a stronger signal than one who simply saw it.

App Detection Reset

If you detect that the user has installed the app (via a cookie set by the app, or by checking Universal Links/App Links), stop showing the banner entirely:

function hasInstalledApp() {
  // Check for a cookie set by the app's web-to-app bridge
  if (document.cookie.includes('app_installed=true')) return true;

  // Check for a localStorage flag set by the app
  if (localStorage.getItem('app_installed') === 'true') return true;

  return false;
}

Measuring Cap Effectiveness

Metrics to Track

  • Conversion rate by impression number: At which impression does the conversion rate approach zero? That is your ideal cap.
  • Banner CTR with different caps: Test cap of 5 vs. 10 vs. 15. Does the higher cap actually produce more installs, or just more impressions?
  • Bounce rate by cap: Does a higher cap increase bounce rate?
  • User satisfaction: If you run surveys, include a question about the app banner frequency.

Finding Your Optimal Cap

Run an A/B test with different cap settings:

function getCapVariant() {
  const variants = [
    { maxTotal: 5, maxDaily: 2, id: 'low' },
    { maxTotal: 10, maxDaily: 3, id: 'medium' },
    { maxTotal: 20, maxDaily: 5, id: 'high' },
  ];

  const hash = simpleHash(getUserId());
  return variants[hash % variants.length];
}

Measure total installs per variant over 2-4 weeks. The variant with the highest installs per unique visitor (not per impression) is your optimal cap.

Tolinku Frequency Capping

Tolinku's smart banners include configurable frequency caps. Set impression limits, time windows, and session caps through the dashboard without writing code. The SDK tracks impressions automatically and respects all configured caps.

For dismiss behavior after cap is reached, see banner dismiss behavior. For campaign-based cap resets, see banner scheduling. For the complete setup, see the smart banners guide.

Get deep linking tips in your inbox

One email per week. No spam.

Ready to add deep linking to your app?

Set up Universal Links, App Links, deferred deep linking, and analytics in minutes. Free to start.