From 354e475ab15c6f5bccdb72d348e8a3a1b433ecac Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Tue, 9 Jun 2026 11:48:11 -0400 Subject: [PATCH 1/3] Add mobile web interstitial GPT example --- features/InterstitialAds.md | 96 +++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/features/InterstitialAds.md b/features/InterstitialAds.md index 3505900010..ac5af1f807 100644 --- a/features/InterstitialAds.md +++ b/features/InterstitialAds.md @@ -66,6 +66,102 @@ pbjs.addAdUnits({ }); ``` +### Mobile Web Interstitial with GPT + +Google Publisher Tag (GPT) web interstitials are out-of-page slots, so they do +not require a container `div`. However, the Prebid.js ad unit still needs a +`code` value that can be matched to the GPT slot when setting targeting. In the +example below, both use the ad unit path as the shared identifier. + +```javascript +var PREBID_TIMEOUT = 1000; +var INTERSTITIAL_AD_UNIT = '/1234567/homepage/mobile-web-interstitial'; + +var googletag = googletag || {}; +googletag.cmd = googletag.cmd || []; + +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +var adUnits = [{ + code: INTERSTITIAL_AD_UNIT, + mediaTypes: { + banner: { + sizes: [[320, 480], [480, 320]] + } + }, + ortb2Imp: { + instl: 1 + }, + bids: [{ + bidder: 'bidderThatSupportsInterstitials', + params: { + placementId: '12345' + } + }] +}]; + +function requestInterstitialBids() { + pbjs.que.push(function() { + pbjs.addAdUnits(adUnits); + pbjs.requestBids({ + adUnitCodes: [INTERSTITIAL_AD_UNIT], + bidsBackHandler: sendInterstitialAdServerRequest, + timeout: PREBID_TIMEOUT + }); + }); +} + +function sendInterstitialAdServerRequest() { + if (pbjs.interstitialAdServerRequestSent || !interstitialSlot) { + return; + } + + pbjs.interstitialAdServerRequestSent = true; + googletag.cmd.push(function() { + pbjs.que.push(function() { + pbjs.setTargetingForGPTAsync([INTERSTITIAL_AD_UNIT]); + googletag.pubads().refresh([interstitialSlot]); + }); + }); +} + +var interstitialSlot; + +googletag.cmd.push(function() { + interstitialSlot = googletag.defineOutOfPageSlot( + INTERSTITIAL_AD_UNIT, + googletag.enums.OutOfPageFormat.INTERSTITIAL + ); + + if (!interstitialSlot) { + return; + } + + interstitialSlot.addService(googletag.pubads()); + googletag.pubads().disableInitialLoad(); + googletag.enableServices(); + + // For pages using single-request architecture with other ad slots, call + // googletag.display(interstitialSlot) only after defining the static slots. + googletag.display(interstitialSlot); + requestInterstitialBids(); +}); + +setTimeout(sendInterstitialAdServerRequest, PREBID_TIMEOUT); +``` + +In this example: + +- `ortb2Imp.instl: 1` signals interstitial demand to bidders that support it. +- `defineOutOfPageSlot()` may return `null` when the page or device does not + support GPT web interstitials, so check for that before requesting bids. +- `disableInitialLoad()` prevents GPT from requesting the interstitial until + Prebid.js targeting has been set. +- `display()` registers the GPT web interstitial slot. The ad appears only when + GPT receives a fill and an eligible GPT web interstitial trigger occurs, such + as a supported link click. + ## How Bid Adapters Should Read Interstitial Flag To access global data, a Prebid.js bid adapter needs only to retrieve the interstitial flag from the adUnit like this: From 0105c63d54c981c88ec86813d3f647089cf25b28 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Tue, 9 Jun 2026 12:30:41 -0400 Subject: [PATCH 2/3] Add mobile web interstitial GPT example ### Motivation - Provide a concrete example for pairing a Prebid.js interstitial ad unit with a Google Publisher Tag (GPT) out-of-page interstitial to address Prebid.js issue #5917. - Clarify the expected flow and signals (including `ortb2Imp.instl`) for bidders and publishers using web interstitials. ### Description - Added a new "Mobile Web Interstitial with GPT" section to `features/InterstitialAds.md` containing a complete code example that shows a Prebid ad unit, `pbjs.requestBids`, `pbjs.setTargetingForGPTAsync`, and `googletag.defineOutOfPageSlot` usage. - Introduced a simple guard (`pbjs.interstitialAdServerRequestSent`) in the example to avoid sending duplicate ad server refreshes if the slot is not ready. - Documented implementation notes covering that `defineOutOfPageSlot()` may return `null`, the use of `googletag.pubads().disableInitialLoad()`, and that `googletag.display()` registers the GPT interstitial slot which only appears when GPT receives a fill and an eligible trigger occurs. ### Testing - Ran `npx markdownlint-cli --config .markdownlint.json features/InterstitialAds.md` against the edited Markdown file and observed no lint failures. - Ran `bundle exec jekyll build` to verify the site generates and the build completed successfully. --- features/InterstitialAds.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/features/InterstitialAds.md b/features/InterstitialAds.md index ac5af1f807..33aee0acdb 100644 --- a/features/InterstitialAds.md +++ b/features/InterstitialAds.md @@ -119,10 +119,14 @@ function sendInterstitialAdServerRequest() { pbjs.interstitialAdServerRequestSent = true; googletag.cmd.push(function() { - pbjs.que.push(function() { - pbjs.setTargetingForGPTAsync([INTERSTITIAL_AD_UNIT]); + if (pbjs.libLoaded) { + pbjs.que.push(function() { + pbjs.setTargetingForGPTAsync([INTERSTITIAL_AD_UNIT]); + googletag.pubads().refresh([interstitialSlot]); + }); + } else { googletag.pubads().refresh([interstitialSlot]); - }); + } }); } @@ -157,7 +161,8 @@ In this example: - `defineOutOfPageSlot()` may return `null` when the page or device does not support GPT web interstitials, so check for that before requesting bids. - `disableInitialLoad()` prevents GPT from requesting the interstitial until - Prebid.js targeting has been set. + either Prebid.js targeting has been set, or the timeout expires and the sample + falls back to a GPT refresh without Prebid.js targeting. - `display()` registers the GPT web interstitial slot. The ad appears only when GPT receives a fill and an eligible GPT web interstitial trigger occurs, such as a supported link click. From 7b2a0c7c2bc442eeec80ce029f113dd3a263c3c1 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Wed, 10 Jun 2026 03:16:36 -0400 Subject: [PATCH 3/3] docs: Add Mobile Web GPT interstitial example to InterstitialAds.md ### Motivation - Provide a concrete example and guidance for using Prebid.js with Google Publisher Tag (GPT) web interstitials on mobile, clarifying how the Prebid ad unit `code` maps to the GPT slot and how to signal interstitial demand with `ortb2Imp.instl`. - Explain practical considerations for GPT out-of-page slots such as `defineOutOfPageSlot()` possibly returning `null`, coordinating Prebid targeting with GPT, and handling fallback timing. ### Description - Add a new "Mobile Web Interstitial with GPT" section to `features/InterstitialAds.md` that includes a complete sample integration demonstrating `ortb2Imp.instl: 1`, ad unit configuration, `pbjs.requestBids()` usage, and a `sendInterstitialAdServerRequest()` flow. - Show how to define an out-of-page GPT slot with `googletag.defineOutOfPageSlot(..., googletag.enums.OutOfPageFormat.INTERSTITIAL)`, check for a `null` return, call `googletag.display()` to register the interstitial, and coordinate `pbjs.setTargetingForGPTAsync()` with `googletag.pubads().refresh()`. - Document the use of `disableInitialLoad()` to prevent GPT from requesting the interstitial before Prebid targeting is set and the timeout-based fallback that refreshes GPT when Prebid times out. ### Testing - No automated tests were run because this is a documentation-only change. --- features/InterstitialAds.md | 39 ++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/features/InterstitialAds.md b/features/InterstitialAds.md index 33aee0acdb..ce8feb7905 100644 --- a/features/InterstitialAds.md +++ b/features/InterstitialAds.md @@ -73,6 +73,15 @@ not require a container `div`. However, the Prebid.js ad unit still needs a `code` value that can be matched to the GPT slot when setting targeting. In the example below, both use the ad unit path as the shared identifier. +GPT web interstitials can prerender the creative markup before the ad is +actually displayed. For this reason, the Prebid.js ad unit should be declared +with `deferBilling: true`, and the publisher should call `pbjs.triggerBilling()` +only after deciding the interstitial is billable. The example below stores the +winning Prebid bid and triggers billing from GPT's `impressionViewable` event; +publishers should customize that trigger for their requirements. Confirm that +participating bid adapters support `onBidBillable` before relying on deferred +billing. + ```javascript var PREBID_TIMEOUT = 1000; var INTERSTITIAL_AD_UNIT = '/1234567/homepage/mobile-web-interstitial'; @@ -83,8 +92,13 @@ googletag.cmd = googletag.cmd || []; var pbjs = pbjs || {}; pbjs.que = pbjs.que || []; +var interstitialSlot; +var interstitialWinningBid; +var interstitialBillingTriggered = false; + var adUnits = [{ code: INTERSTITIAL_AD_UNIT, + deferBilling: true, mediaTypes: { banner: { sizes: [[320, 480], [480, 320]] @@ -103,6 +117,9 @@ var adUnits = [{ function requestInterstitialBids() { pbjs.que.push(function() { + pbjs.onEvent('bidWon', function(bid) { + interstitialWinningBid = bid; + }, INTERSTITIAL_AD_UNIT); pbjs.addAdUnits(adUnits); pbjs.requestBids({ adUnitCodes: [INTERSTITIAL_AD_UNIT], @@ -130,7 +147,16 @@ function sendInterstitialAdServerRequest() { }); } -var interstitialSlot; +function triggerInterstitialBilling() { + if (interstitialBillingTriggered || !interstitialWinningBid || !pbjs.libLoaded) { + return; + } + + interstitialBillingTriggered = true; + pbjs.que.push(function() { + pbjs.triggerBilling(interstitialWinningBid); + }); +} googletag.cmd.push(function() { interstitialSlot = googletag.defineOutOfPageSlot( @@ -144,6 +170,11 @@ googletag.cmd.push(function() { interstitialSlot.addService(googletag.pubads()); googletag.pubads().disableInitialLoad(); + googletag.pubads().addEventListener('impressionViewable', function(event) { + if (event.slot === interstitialSlot) { + triggerInterstitialBilling(); + } + }); googletag.enableServices(); // For pages using single-request architecture with other ad slots, call @@ -158,6 +189,9 @@ setTimeout(sendInterstitialAdServerRequest, PREBID_TIMEOUT); In this example: - `ortb2Imp.instl: 1` signals interstitial demand to bidders that support it. +- `deferBilling: true` prevents Prebid.js from calling `onBidBillable` at win + time. Store the winning bid and call `pbjs.triggerBilling()` when your chosen + signal indicates that the GPT web interstitial is billable. - `defineOutOfPageSlot()` may return `null` when the page or device does not support GPT web interstitials, so check for that before requesting bids. - `disableInitialLoad()` prevents GPT from requesting the interstitial until @@ -166,6 +200,9 @@ In this example: - `display()` registers the GPT web interstitial slot. The ad appears only when GPT receives a fill and an eligible GPT web interstitial trigger occurs, such as a supported link click. +- The `impressionViewable` listener is one example billing trigger. Use the GPT + or application event that best represents when the interstitial should be + billed for your integration. ## How Bid Adapters Should Read Interstitial Flag