Frequency Capping
Control how often users see ads with automatic limits and cooldown timers to ensure quality user experience.
How Frequency Capping Works
BZZE Ads SDK enforces three types of frequency limits automatically:
- Cooldown Between Ads: 60 seconds minimum between each ad
- Hourly Limit: Maximum 10 ads per hour per user
- Daily Limit: Maximum 50 ads per day per user
Default Limits
| Limit Type | Value | Enforcement | Can Override? |
|---|---|---|---|
| Between Ads (Cooldown) | 60 seconds | Client + Server | ❌ No (fixed) |
| Per Hour | 10 ads | Server-side | ❌ No (fixed) |
| Per Day | 50 ads | Server-side | ❌ No (fixed) |
Checking Cooldown Status
Method 1: getCooldownRemaining()
Get the number of seconds until the next ad can be shown:
const cooldown = RewardedAd.getCooldownRemaining();
if (cooldown === 0) {
console.log('✅ Ready to show ad!');
RewardedAd.showAd();
} else {
console.log(`⏳ Wait ${cooldown} seconds`);
showCooldownTimer(cooldown);
}
Method 2: isAdAvailable()
Simple boolean check if ad can be shown right now:
if (RewardedAd.isAdAvailable()) {
// Cooldown passed AND ad is preloaded
RewardedAd.showAd();
} else {
// Either in cooldown or no ad ready
console.log('Ad not available');
}
Displaying Cooldown Timer
Basic Countdown
const button = document.getElementById('rewardButton');
function updateButtonState() {
const cooldown = RewardedAd.getCooldownRemaining();
if (cooldown === 0) {
button.disabled = false;
button.textContent = '▶️ Watch Ad';
button.style.background = '#4CAF50';
} else {
button.disabled = true;
button.textContent = `⏳ Wait ${cooldown}s`;
button.style.background = '#9E9E9E';
}
}
// Update every second
setInterval(updateButtonState, 1000);
updateButtonState();
Formatted Countdown
function formatTime(seconds) {
if (seconds === 0) return 'Ready!';
if (seconds < 60) return `${seconds}s`;
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
function updateCooldown() {
const cooldown = RewardedAd.getCooldownRemaining();
const statusText = document.getElementById('cooldownStatus');
statusText.textContent = formatTime(cooldown);
}
setInterval(updateCooldown, 1000);
Progress Bar
const COOLDOWN_DURATION = 60; // 60 seconds
const progressBar = document.getElementById('cooldownProgress');
const progressText = document.getElementById('cooldownText');
function updateProgressBar() {
const remaining = RewardedAd.getCooldownRemaining();
const progress = ((COOLDOWN_DURATION - remaining) / COOLDOWN_DURATION) * 100;
progressBar.style.width = `${progress}%`;
if (remaining === 0) {
progressText.textContent = '✅ Ready!';
progressBar.style.backgroundColor = '#10b981';
} else {
progressText.textContent = `${remaining}s remaining`;
progressBar.style.backgroundColor = '#f59e0b';
}
}
setInterval(updateProgressBar, 100);
Handling Rate Limit Errors
Client-Side Detection
RewardedAd.init({
appId: "YOUR_APP_ID",
apiKey: "YOUR_API_KEY",
userId: "user_123",
onNoFill: function(data) {
if (data.reason === 'RATE_LIMIT') {
console.log('⚠️ Rate limit reached');
showMessage('You\'ve watched the maximum ads for now. Try again later!');
} else if (data.reason === 'COOLDOWN') {
const cooldown = RewardedAd.getCooldownRemaining();
showMessage(`Please wait ${cooldown} seconds before the next ad.`);
} else {
showMessage('No ads available right now.');
}
}
});
Server-Side Rate Limit Response
When server-side limits are hit, the SDK receives a specific error:
RewardedAd.init({
appId: "YOUR_APP_ID",
apiKey: "YOUR_API_KEY",
userId: "user_123",
onError: function(error) {
if (error.code === 'RATE_LIMIT_HOURLY') {
console.log('⚠️ Hourly limit (10 ads/hour) reached');
showMessage('Hourly ad limit reached. Try again in an hour!');
} else if (error.code === 'RATE_LIMIT_DAILY') {
console.log('⚠️ Daily limit (50 ads/day) reached');
showMessage('Daily ad limit reached. Come back tomorrow!');
}
}
});
Best Practices
1. Always Show Cooldown Timer
// Good: Clear feedback
const cooldown = RewardedAd.getCooldownRemaining();
if (cooldown > 0) {
showNotification(`Next ad available in ${cooldown}s`);
}
2. Disable Button During Cooldown
// Good: Prevent clicks during cooldown
button.disabled = RewardedAd.getCooldownRemaining() > 0;
// Bad: Allow clicks that will fail
button.disabled = false; // Always enabled
3. Offer Alternative Actions
function tryShowAd() {
const cooldown = RewardedAd.getCooldownRemaining();
if (cooldown > 0) {
// Offer alternative ways to earn rewards
showAlternativeOptions([
'Complete daily quest',
'Invite friends',
'Purchase coins'
]);
} else {
RewardedAd.showAd();
}
}
4. Respect Global Limits
- Creating multiple user IDs per user
- Clearing localStorage to reset cooldown
- Modifying client-side timers
Limits are enforced server-side. Bypass attempts will be detected and may result in account suspension.
Industry Standards
Recommended Frequency Caps
| Industry | Between Ads | Per Hour | Per Day |
|---|---|---|---|
| Mobile Games | 30-60s | 10-15 ads | 30-50 ads |
| Casual Games | 60-120s | 6-10 ads | 20-30 ads |
| Social Apps | 120-300s | 5-8 ads | 15-25 ads |
| BZZE Ads | 60s | 10 ads | 50 ads |
BZZE Ads uses industry-standard limits optimized for both user experience and revenue.
Complete Example
// Complete frequency capping implementation
class AdManager {
constructor() {
this.button = document.getElementById('adButton');
this.statusText = document.getElementById('adStatus');
this.progressBar = document.getElementById('adProgress');
this.initializeAds();
this.startUIUpdates();
}
initializeAds() {
RewardedAd.init({
appId: "YOUR_APP_ID",
apiKey: "YOUR_API_KEY",
userId: "user_123",
onReward: (reward) => {
console.log('✅ Reward earned!');
this.grantReward();
},
onNoFill: (data) => {
if (data.reason === 'RATE_LIMIT') {
this.showMessage('Hourly/daily limit reached!');
} else if (data.reason === 'COOLDOWN') {
this.showMessage('Please wait for cooldown');
}
},
onError: (error) => {
console.error('Ad error:', error);
if (error.code.includes('RATE_LIMIT')) {
this.showMessage('Ad limit reached. Try again later!');
}
}
});
}
startUIUpdates() {
setInterval(() => this.updateUI(), 1000);
this.updateUI();
}
updateUI() {
const cooldown = RewardedAd.getCooldownRemaining();
const available = RewardedAd.isAdAvailable();
if (cooldown === 0 && available) {
// Ready to show ad
this.button.disabled = false;
this.button.textContent = '▶️ Watch Ad for Reward';
this.button.style.background = '#4CAF50';
this.statusText.textContent = 'Ready!';
this.progressBar.style.width = '100%';
this.progressBar.style.backgroundColor = '#10b981';
} else if (cooldown > 0) {
// In cooldown
this.button.disabled = true;
this.button.textContent = `⏳ Cooldown: ${cooldown}s`;
this.button.style.background = '#9E9E9E';
this.statusText.textContent = `Wait ${cooldown} seconds`;
const progress = ((60 - cooldown) / 60) * 100;
this.progressBar.style.width = `${progress}%`;
this.progressBar.style.backgroundColor = '#f59e0b';
} else {
// No ad available
this.button.disabled = true;
this.button.textContent = '📭 No ads available';
this.button.style.background = '#9E9E9E';
this.statusText.textContent = 'Loading ads...';
}
}
showAd() {
const cooldown = RewardedAd.getCooldownRemaining();
if (cooldown > 0) {
this.showMessage(`Please wait ${cooldown} seconds`);
return;
}
RewardedAd.showAd({
rewardPreview: '100 coins'
});
}
grantReward() {
// Your reward logic here
console.log('💰 100 coins granted!');
this.showMessage('You earned 100 coins!');
}
showMessage(text) {
alert(text); // Replace with your notification system
}
}
// Initialize
const adManager = new AdManager();
// Attach to button
document.getElementById('adButton').onclick = () => {
adManager.showAd();
};
FAQ
Q: Can I customize the frequency limits?
A: No, limits are fixed to ensure quality for all users and advertisers. Contact support if you have special requirements.
Q: Do limits reset at midnight?
A: Daily limits reset 24 hours after the first ad of the day. Hourly limits are rolling (not clock-based).
Q: What happens if a user clears localStorage?
A: Client-side cooldown may reset, but server-side hourly/daily limits remain enforced.
Q: Are limits per-app or per-user?
A: Per-user global. A user who hits the limit in one app cannot watch ads in another app using the same SDK.
Q: Can I detect when limits will reset?
A: The SDK doesn't provide limit reset times, but you can track the time of the first ad impression and calculate accordingly.