Viewability Tracking
Automatic tracking of ad viewability using IAB industry standards to ensure quality impressions.
Why Viewability Matters
- Advertiser Value: Advertisers only want to pay for ads that users actually saw
- Higher Revenue: Viewable impressions command higher CPM rates
- Industry Standard: IAB (Interactive Advertising Bureau) requires viewability tracking
- Quality Signal: High viewability rates indicate quality inventory
IAB Viewability Standard
| Ad Type | Visibility | Duration | BZZE Ads |
|---|---|---|---|
| Display Ads | 50% pixels | 1 second | N/A |
| Video Ads | 50% pixels | 2 seconds | ✅ Implemented |
| Large Display (>242,500 pixels) | 30% pixels | 1 second | N/A |
BZZE Ads uses the IAB video standard: An impression is viewable if 50% or more of the video player is visible in the viewport for at least 2 continuous seconds.
How It Works
Automatic Tracking
The SDK automatically tracks viewability using the browser's IntersectionObserver API:
// Simplified view of SDK's viewability tracking
1. Ad starts playing
↓
2. IntersectionObserver monitors visibility
• Checks every 100ms
• Tracks what % of ad is visible
↓
3. When 50%+ visible for 2+ seconds
• Mark as "viewable impression"
• Send tracking event to server
• Update analytics
↓
4. Ad continues playing
• Viewability tracked once per impression
• No duplicate tracking
Technical Implementation
// Inside the SDK (you don't need to implement this)
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const visibilityRatio = entry.intersectionRatio;
if (visibilityRatio >= 0.5) {
// 50%+ visible
if (!viewabilityTimer) {
// Start 2-second timer
viewabilityTimer = setTimeout(() => {
// Ad was 50%+ visible for 2+ seconds
trackViewableImpression();
}, 2000);
}
} else {
// Less than 50% visible
if (viewabilityTimer) {
// Reset timer
clearTimeout(viewabilityTimer);
viewabilityTimer = null;
}
}
});
}, {
threshold: [0, 0.25, 0.5, 0.75, 1.0]
});
// Observe the ad player
observer.observe(adPlayerElement);
Viewability Metrics
Getting Viewability Data
Access viewability metrics through the analytics API:
const analytics = RewardedAd.getAnalytics();
console.log('Total Impressions:', analytics.impressions);
console.log('Viewable Impressions:', analytics.viewableImpressions);
// Calculate viewability rate
const viewabilityRate = analytics.impressions > 0
? (analytics.viewableImpressions / analytics.impressions * 100).toFixed(1)
: 0;
console.log('Viewability Rate:', viewabilityRate + '%');
Display Viewability Stats
function displayViewabilityStats() {
const analytics = RewardedAd.getAnalytics();
const stats = {
impressions: analytics.impressions,
viewable: analytics.viewableImpressions,
nonViewable: analytics.impressions - analytics.viewableImpressions,
rate: analytics.impressions > 0
? (analytics.viewableImpressions / analytics.impressions * 100).toFixed(1)
: 0
};
console.log('═══ Viewability Report ═══');
console.log('Total Impressions:', stats.impressions);
console.log('Viewable:', stats.viewable, `(${stats.rate}%)`);
console.log('Non-Viewable:', stats.nonViewable);
console.log('═══════════════════════════');
return stats;
}
Viewability Scenarios
✅ Viewable Impression Examples
| Scenario | Viewable? | Reason |
|---|---|---|
| Ad plays full-screen | ✅ Yes | 100% visible for entire duration |
| Ad is 75% visible for 5 seconds | ✅ Yes | Exceeds 50% threshold and 2s duration |
| User watches entire ad | ✅ Yes | Visible throughout playback |
| Ad starts off-screen, user scrolls to it after 1s | ✅ Yes | Once 50%+ visible for 2s, counts |
❌ Non-Viewable Impression Examples
| Scenario | Viewable? | Reason |
|---|---|---|
| User switches tab immediately | ❌ No | Never reached 2s visibility |
| Ad plays in background tab | ❌ No | 0% visible (not in viewport) |
| User minimizes browser after 1s | ❌ No | Didn't reach 2s threshold |
| Only 40% of player visible | ❌ No | Below 50% visibility threshold |
| User scrolls away after 1.5s | ❌ No | Didn't reach 2s continuous visibility |
Best Practices for High Viewability
1. Full-Screen Ad Player
// The SDK automatically uses full-screen player
RewardedAd.showAd();
// → Opens in full-screen overlay
// → Guaranteed 100% viewability
2. Pause Game During Ads
RewardedAd.init({
appId: "YOUR_APP_ID",
apiKey: "YOUR_API_KEY",
userId: "user_123",
onAdShown: function() {
// Pause game to keep focus on ad
pauseGame();
stopGameAudio();
},
onClose: function() {
// Resume after ad closes
resumeGame();
}
});
3. Discourage Tab Switching
While you can't prevent users from switching tabs, you can detect and handle it:
// Optional: Detect visibility changes
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
console.log('⚠️ User switched tabs during ad');
// Ad continues playing (SDK handles viewability tracking)
} else {
console.log('✅ User returned to tab');
}
});
Monitoring Viewability
Real-Time Monitor
class ViewabilityMonitor {
constructor() {
this.startTime = Date.now();
this.lastViewabilityRate = 0;
}
update() {
const analytics = RewardedAd.getAnalytics();
if (analytics.impressions === 0) {
console.log('No impressions yet');
return;
}
const rate = (analytics.viewableImpressions / analytics.impressions * 100).toFixed(1);
// Check if rate changed
if (rate !== this.lastViewabilityRate) {
console.log(`📊 Viewability Rate: ${rate}% (${analytics.viewableImpressions}/${analytics.impressions})`);
this.lastViewabilityRate = rate;
// Alert if rate is low
if (rate < 80 && analytics.impressions >= 5) {
console.warn('⚠️ Low viewability rate detected!');
}
}
}
startMonitoring() {
setInterval(() => this.update(), 5000); // Check every 5s
}
}
// Usage (for development/testing)
const monitor = new ViewabilityMonitor();
monitor.startMonitoring();
Debug Viewability Issues
// Enable debug mode to see viewability logs
RewardedAd.enableDebug();
RewardedAd.init({
appId: "YOUR_APP_ID",
apiKey: "YOUR_API_KEY",
userId: "user_123"
});
// You'll see logs like:
// 👁️ [BZZE Ads] Ad visibility: 100%
// 👁️ [BZZE Ads] Viewability threshold met (50%+ for 2s)
// ✅ [BZZE Ads] Viewable impression tracked
Viewability Benchmarks
Industry Averages
| Platform | Average Viewability | Good Performance |
|---|---|---|
| Mobile Games | 70-80% | 85%+ |
| Desktop Games | 75-85% | 90%+ |
| Mobile Web | 50-65% | 70%+ |
| BZZE Ads (Full-Screen) | 95-100% | 98%+ |
Note: BZZE Ads achieves very high viewability rates (95-100%) because of the full-screen ad player design.
What's a Good Viewability Rate?
- 90%+: Excellent - Premium quality
- 80-90%: Good - Industry standard
- 70-80%: Acceptable - Room for improvement
- <70%: Poor - Investigate issues
Impact on Revenue
Why Viewability Affects CPM
Advertisers pay more for viewable impressions because they know the ad was actually seen. Apps with 90%+ viewability can command 20-40% higher CPMs.
| Viewability Rate | CPM Impact | Example |
|---|---|---|
| <50% | -50% to -70% | $2 CPM instead of $5 |
| 50-70% | -20% to -40% | $3.50 CPM instead of $5 |
| 70-85% | Standard | $5 CPM (baseline) |
| 85-95% | +10% to +20% | $5.50-$6 CPM |
| 95-100% | +20% to +40% | $6-$7 CPM |
FAQ
Q: Is viewability tracking automatic?
A: Yes! The SDK automatically tracks viewability for all ad impressions. You don't need to implement anything.
Q: Can I disable viewability tracking?
A: No, viewability tracking is required for IAB compliance and cannot be disabled.
Q: Does viewability tracking affect performance?
A: No, viewability tracking uses the browser's native IntersectionObserver API which has minimal performance impact.
Q: What if my viewability rate is low?
A: For BZZE Ads (full-screen player), viewability should be 95%+. If it's lower, check for:
- Users switching tabs frequently
- Network issues causing ads to load slowly
- Browser/device compatibility issues
Q: Are non-viewable impressions still counted?
A: Yes, all impressions are counted, but only viewable impressions contribute to premium ad inventory and higher CPMs.