Reels Ad Impression Recovery via Autoscroll
Built an impression recovery system at Meta that captures lost revenue for Instagram Reels by auto-scrolling to high-value ads using Kotlin and Android.
Reels Autoscroll to Ads
Company: Meta
Surface: Instagram Reels
Role: Android Software Engineer
Impact Area: Ads Monetization, Impression Recovery
The Problem
Instagram Reels is one of the highest-revenue advertising surfaces at Meta. Every time a user navigates away from the Reels tab and comes back, whether from a cross-navigation to their DMs, a quick check of their profile, or switching to another app entirely, the Reels feed is already populated. Ads have already been ranked by the server. High-value interstitial ads have already been injected at specific positions in the feed.
But when the user returns, they land at their previous scroll position or at the top of the feed and scroll organically. They have no awareness that a high-eCPM interstitial is sitting just a few items away from where they landed. Without any intervention, that ad expires on the client side via TTL without ever receiving an impression.
The server-side ranking compute was wasted. The eCPM value was never captured. And this was happening across millions of warm start sessions every day.
The Insight
Before building anything, I ran a data analysis on warm start session behavior across the Reels surface. I looked specifically at the delta between interstitials injected into the feed and those that actually received impressions within the first few minutes of a warm start session.
The pattern was clear. A significant fraction of high-value interstitials, particularly those in the upper eCPM percentiles, were expiring unused. The ranking had happened. The injection had happened. The opportunity was right there in the feed. But the surface had no mechanism to surface it at the precise moment it mattered most: the moment the user came back.
This meant the solution did not require any new server infrastructure, any new ranking computation, or any new ad inventory. The inventory already existed. The ranking was already done. A targeted client-side intervention was all that was needed.
The Solution
I designed and built Reels Autoscroll to Ads, a system that detects warm start and cross-navigation return events on the Reels surface, inspects the current in-feed interstitial inventory, and if a high-value eligible ad is found, smoothly auto-scrolls the Reels feed to that ad.
The system operates through four tightly scoped components:
NavigationEventEmitter publishes warm start and cross-navigation events when the user returns to the Reels surface. This required new event types distinct from cold start, because the surface state and available inventory are fundamentally different between a fresh launch and a return navigation.
AdsInventoryInspector provides a queryable snapshot of all currently injected ads on the Reels surface, including their types, eCPM values, TTL expiry timestamps, and impression states. This was a new interface into the existing ads state management layer.
InterstitialEvaluator applies a multi-stage filter pipeline to identify the single best candidate interstitial from the current inventory. The pipeline filters for interstitial type, eCPM above a configurable threshold, unimpressed state, and within-TTL freshness, then selects the highest eCPM candidate from the remaining set.
AutoScrollOrchestrator coordinates the scroll animation, the viewport entry check, and the impression event emission. Critically, the impression is only recorded after the ad fully enters the viewport, reusing the existing viewability tracking stack to ensure no impression inflation.
Key Engineering Decisions
The eCPM threshold. Not every interstitial justifies overriding the user's organic scroll behavior. I established a minimum eCPM threshold, controlled via remote config, below which the autoscroll does not trigger. This ensures the feature only fires for genuinely high-value inventory, preserving user experience for the majority of cases while capturing revenue for the minority that matters most.
Warm start versus cold start distinction. The event taxonomy required precision. A cold start means no feed is populated and no ads are injected yet. A warm start means the feed is already loaded and ads are already positioned. These are fundamentally different states and needed distinct event types, each triggering different handling logic.
Impression validity. A scroll to an ad is not the same as an impression. I specifically designed the system so the impression event fires only after the ad occupies the required viewport percentage, using the same viewability threshold as organic impressions. This prevented any inflation of the impression metric while still capturing the genuine impression that the autoscroll delivers.
TTL vs. server freshness. The client TTL is a proxy for server-side ad freshness, not an exact mirror. In edge cases, an ad that is still within client TTL may have expired on the server. I added post-impression discrepancy monitoring using the Unified Logging system (see Unified Logging project) to track and calibrate this gap over time.
Instrumentation and Experimentation
Every stage of the decision pipeline was instrumented: how many ads were evaluated per session, how many passed the eCPM threshold, how many passed the TTL and impression state filters, how many scroll events were triggered, and how many resulted in a confirmed viewport impression.
The A/B experiment compared warm start interstitial impression rates between the treatment group (autoscroll enabled) and the control group (standard organic behavior). The primary metric was interstitial impression rate on warm start sessions. Guardrail metrics included session length, swipe rate, and explicit negative feedback signals (report ad, hide ad).
The results showed meaningful improvement in interstitial impression recovery on warm start sessions, with engagement guardrail metrics within acceptable bounds. The feature was approved for full rollout.
Outcome and Scale
Reels Autoscroll to Ads is now part of the standard Reels monetization stack, running across millions of warm start and cross-navigation sessions daily. It adds zero server request overhead, executes the decision pipeline entirely on the client in sub-millisecond time, and has no impact on frame rate or scroll performance.
The core principle behind this feature applies broadly: before investing in infrastructure to generate more ad inventory, first ensure that the existing inventory is being captured with maximum efficiency. In this case, the inventory was already there. It just needed a smarter surface to recover it.