Interstitial Ads - Prebid.js

Interstitial ads are often placed at natural transition points of the user’s experience, such as moving from one page to the next. These ads are generally center-aligned overlaying user content.

This document covers how to setup interstitial ad units.

Please check with each of this AdUnit’s bidders to ensure they’re reading the interstitial flag from the standard Prebid location. If the bidder doesn’t specifically support interstitials, results may be unexpected.

How It Works

The flow for publishers is the following:

  • Publisher traffics an interstitial line item with appropriate size(s) (GAM example)
  • Publisher defines ad server interstitial slot on the page (GAM Example)
  • Publisher creates a PBJS AdUnit and defines the appropriate interstitial ad sizes, adUnit.mediaType, and a special interstitial flag
  • Publisher adds bidders and parameters that support interstitials to the PBJS AdUnit(s)
  • Prebid requests bids for interstitial adUnits and invokes the ad server call from the requestBids callback

Ad Sizes

Publishers must set the desired size in the respective adUnit.

The below sizes are specials sizes to indicate the ad will be full screen for mobile or tablet devices:

  • 320x480: Fullscreen mobile phone portrait ad
  • 480x320: Fullscreen mobile phone landscape ad
  • 768x1024: Fullscreen tablet portrait ad
  • 1024x768: Fullscreen tablet landscape ad

In-Page Example

The Prebid Interstitial flag reflects the OpenRTB standard, specifying it at the imp level.

Supplying Interstitial Flag

If an attribute is specific to an AdUnit, it can be passed this way:

pbjs.addAdUnits({
    code: "test-div",
    mediaTypes: {
        banner: {
            sizes: [[300,250]]
        }
    },
    ortb2Imp: {
        instl:1
    },
    bids: [
      ... bidders that support interstitials ...
    ]
});

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.

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.

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 interstitialSlot;
var interstitialWinningBid;
var interstitialBillingTriggered = false;

var adUnits = [{
    code: INTERSTITIAL_AD_UNIT,
    deferBilling: true,
    mediaTypes: {
        banner: {
            sizes: [[320, 480], [480, 320]]
        }
    },
    ortb2Imp: {
        instl: 1
    },
    bids: [{
        bidder: 'bidderThatSupportsInterstitials',
        params: {
            placementId: '12345'
        }
    }]
}];

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],
            bidsBackHandler: sendInterstitialAdServerRequest,
            timeout: PREBID_TIMEOUT
        });
    });
}

function sendInterstitialAdServerRequest() {
    if (pbjs.interstitialAdServerRequestSent || !interstitialSlot) {
        return;
    }

    pbjs.interstitialAdServerRequestSent = true;
    googletag.cmd.push(function() {
        if (pbjs.libLoaded) {
            pbjs.que.push(function() {
                pbjs.setTargetingForGPTAsync([INTERSTITIAL_AD_UNIT]);
                googletag.pubads().refresh([interstitialSlot]);
            });
        } else {
            googletag.pubads().refresh([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(
        INTERSTITIAL_AD_UNIT,
        googletag.enums.OutOfPageFormat.INTERSTITIAL
    );

    if (!interstitialSlot) {
        return;
    }

    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
    // 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.
  • 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 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.
  • 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

To access global data, a Prebid.js bid adapter needs only to retrieve the interstitial flag from the adUnit like this:

utils.deepAccess(bidRequest.ortb2Imp, 'instl')

The assumption is that bid adapters will copy the values to the appropriate protocol location for their endpoint.

Billing Deferral

Optimizing when billing occurs for an interstitial ad can sometimes be tricky. The following built-in Prebid.js functionality can help assist with this:

  • Bid adapters can provide a method called onBidBillable(bid) which will be invoked by Prebid.js when it deems a bid to be billable (Note: A bid adapter must have the onBidBillable method configured for this to work).
  • When a bid wins, it is by default also billable. That is, by default, Prebid.js will invoke the bid adapter methods onBidWon and onBidBillable one after the other.
  • A publisher can flag individual adUnits as being separately billable with the following configuration: pbjs.addAdUnits({deferBilling: true, ...})
  • Winning bids for adUnits with deferBilling set to true will trigger a bid adapters onBidWon method but not their onBidBillable method.
  • Finally, when appropriate (e.g. an interstitial is displayed), the publisher may call pbjs.triggerBilling(winningBidObjectToBill) with the winning bid to be billed, which would trigger a bid adapters onBidBillable method.