Skip to content

PS bid caching failures - #943

Open
mdanylov-sigma wants to merge 4 commits into
masterfrom
feature/1258-cache-bid-failures
Open

mdanylov-sigma wants to merge 4 commits into
masterfrom
feature/1258-cache-bid-failures

Conversation

@mdanylov-sigma

@mdanylov-sigma mdanylov-sigma commented May 15, 2026

Copy link
Copy Markdown
Collaborator

Handles Prebid Server bid caching failures for prebid/prebid-mobile-ios#1258, aligned with the reviewed design doc and the iOS implementation in prebid/prebid-mobile-ios#1327.

Changes

  • Added PrebidMobile.setFilterOutUncachedBids(boolean) (default false). It only filters which bids reach the ad server and never requests caching on its own. Original API already asks Prebid Server to cache bids, so the request builder is unchanged.
  • Scoped the filtering and its result codes to Original API ad units. The Rendering API renders creatives from the bid markup and never depends on Prebid Cache, so a cache failure there is not a demand failure.
  • A bid counts as cached only when ext.prebid.cache.bids or ext.prebid.cache.vastXml has a cacheId. Prebid Cache is read with GET /cache?uuid=<cacheId> and Prebid Universal Creative builds that request from hb_cache_id. url is just cacheId joined with the cache host and path, so it never counts on its own.
  • Bids are filtered while the response is parsed (Seatbid.BidFilter), so bid lists are not rebuilt afterwards. Seatbids left without bids are dropped.
  • If the bid Prebid Server designated as the winner (unsuffixed hb_pb + hb_bidder) is filtered out, the highest-priced cached bid is promoted instead of discarding all remaining demand. The result stays ResultCode.SUCCESS, and the new BidInfo.isTopBidFiltered() reports the promotion for yield tracking.
  • If every returned bid is filtered out, fetch demand returns the new ResultCode.NO_CACHED_BIDS (FetchDemandResult.NO_CACHED_BIDS for mediation). A response that has no winner for any other reason still returns NO_BIDS.
  • BidLoader logs how many bids were removed and when a bid was promoted, and still notifies PrebidEventDelegate with the server response when all bids are filtered.
  • Kotlin demo: added "GAM (Original API) Display Banner 320x50 [Filter Uncached Bids]" showing how to handle both outcomes.

Usage

PrebidMobile.setFilterOutUncachedBids(true)

prebidAdUnit.fetchDemand(gamRequest, prebidRequest) { bidInfo ->
    when (bidInfo.resultCode) {
        ResultCode.SUCCESS -> {
            if (bidInfo.isTopBidFiltered) {
                // The top bid failed to cache, a lower-priced cached bid was promoted
            }
        }
        ResultCode.NO_CACHED_BIDS -> {
            // No returned bid was cached, no Prebid targeting is attached
        }
        else -> {}
    }
    adView.loadAd(gamRequest)
}

Notes

  • A promoted bid carries only bidder-suffixed keys (for example hb_pb_appnexus), since the unsuffixed keys belonged to the filtered winner. Line items that target only the unsuffixed hb_pb will not match it. iOS behaves the same way.
  • The removed-bid count is logged only. Automatic retry is deferred, and enabling the flag by default in 4.0 is still an open question.

Testing

  • BidResponseTest: filtering, winner promotion, url without cacheId, Rendering API not filtered, flag disabled.
  • CacheTest: cacheId-only predicate, vastXml and lowercase vastxml.
  • BidLoaderTest: NO_CACHED_BIDS vs NO_BIDS, promoted winner, Rendering API, event delegate.
  • PrebidTest: the flag does not add a cache request.
  • ./gradlew :PrebidMobile-core:testReleaseUnitTest: 1318 passed, 0 failed. Kotlin demo compiles.

@mdanylov-sigma
mdanylov-sigma force-pushed the feature/1258-cache-bid-failures branch from 54281ec to b8e0080 Compare July 3, 2026 12:34
Brings Android in line with the approved design doc for
prebid/prebid-mobile-ios#1258 and the iOS implementation in
prebid/prebid-mobile-ios#1327.

- Rename PrebidMobile.setRequireServerSideBidCache to
  setFilterOutUncachedBids and give it a single responsibility: it only
  filters which bids reach the ad server and never requests caching.
  Prebid.java no longer adds the cache request for it, since Original API
  already asks Prebid Server to cache bids.
- Scope the filtering and its result codes to Original API ad units. The
  Rendering API renders from the bid markup and never reads Prebid Cache,
  so a cache failure there is not a demand failure.
- Require cacheId for a successful cache entry (bids or vastXml). Prebid
  Cache is read with GET /cache?uuid=<cacheId> and PUC builds that request
  from hb_cache_id. url is only cacheId joined with the cache host and path.
- Keep filtering at parse time (Seatbid.BidFilter) so bid lists are not
  rebuilt, and drop seatbids left without bids.
- Promote the highest-priced cached bid when the bid Prebid Server
  designated as the winner is filtered out. Previously all remaining cached
  demand was discarded. The result stays SUCCESS and
  BidInfo.isTopBidFiltered() reports the promotion for yield tracking.
- BidLoader logs removed and promoted bids, returns NO_CACHED_BIDS when
  every bid was filtered and NO_BIDS otherwise, and still notifies the event
  delegate on that path, matching iOS.
- Add the GAM (Original API) Display Banner 320x50 [Filter Uncached Bids]
  example to the Kotlin demo.

Also restores BannerViewTest and InterstitialAdUnitTest to master.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants