This guide outlines how to use Prebid.js's open source wrapper with the Audience Network API to access Audience Network Demand for mobile web display.
For Audience Network account setup details, you can review the Getting started guide.
var adUnits = [{ code: 'div-gpt-ad-1486479040361-0', sizes: [[300, 250]], bids: [{ bidder: 'audienceNetwork', params: { placementId: '<YOUR_PLACEMENT_ID>', } }] },];
fb_bidid
if using Audience Network tag in DFP, fb_adid
if using the Prebid Snippet in DFP):pbjs.bidderSettings = { audienceNetwork: { adserverTargeting: [ { key: "fb_bidid", val: function (bidResponse) { // make the bidId available for targeting if required return bidResponse.fb_bidid; } }, { key: "hb_bidder", val: function (bidResponse) { return bidResponse.bidderCode; } }, { key: "hb_pb", val: function(bidResponse) { return bidResponse.pbMg; } }, ], }, };
<div>
tag from each example (stripping off the <html><head>...</head><body>
and </body></html>
tags). The ad should be requested and displayed within 10 minutes of the bid being issued. For ad units served directly (not through DFP), the iframe’s document should be:<html> <body> <div style="display:none; position: relative;"> <script type="text/javascript"> var data = { placementid: '%%PATTERN:fb_placementid%%', format: '%%PATTERN:fb_format%%', bidid: '%%PATTERN:fb_bidid%%', testmode: false, onAdLoaded: function(element) { console.log('Audience Network [%%PATTERN:fb_placementid%%] ad loaded'); element.style.display = 'block'; }, onAdError: function(errorCode, errorMessage) { console.log('Audience Network [%%PATTERN:fb_placementid%%] error (' + errorCode + ') ' + errorMessage); } }; </script> <script> (function(a,b,c){var d="https://www.facebook.com",e="https://connect.facebook.net/en_US/fbadnw55.js",f={iframeLoaded:true,xhrLoaded:true},g=a.data,h=function(){if(Date.now)return Date.now();else return+new Date()},i=function(B){var C=d+"/audience_network/client_event",D={cb:h(),event_name:"ADNW_ADERROR",ad_pivot_type:"audience_network_mobile_web",sdk_version:"5.5.web",app_id:g.placementid.split("_")[0],publisher_id:g.placementid.split("_")[1],error_message:B},E=[];for(var F in D)E.push(encodeURIComponent(F)+"="+encodeURIComponent(D[F]));var G=C+"?"+E.join("&"),H=new XMLHttpRequest();H.open("GET",G,true);H.send();if(g.onAdError)g.onAdError("1000","Internal error.")},j=function(){if(b.currentScript)return b.currentScript;else{var B=b.getElementsByTagName("script");return B[B.length-1]}},k=function(B){try{return B.document.referrer}catch(C){}return""},l=function(){var B=a,C=[B];try{while(B!==B.parent&&B.parent.document)C.push(B=B.parent)}catch(D){}return C.reverse()},m=function(){var B=l();for(var C=0;C<B.length;C++){var D=B[C],E=D.ADNW||{};D.ADNW=E;if(!D.ADNW)continue;return E.v55=E.v55||{ads:[],window:D}}throw new Error("no_writable_global")},n=function(B){var C=B.indexOf("/",B.indexOf("://")+3);if(C===-1)return B;return B.substring(0,C)},o=function(B){return B.location.href||k(B)},p=function(B){if(B.sdkLoaded)return;var C=B.window.document,D=C.createElement("iframe");D.name="fbadnw";D.style.display="none";D.onload=function(){var E=D.contentDocument.createElement("script");E.src=e;E.async=true;D.contentDocument.body.appendChild(E)};C.body.appendChild(D);B.sdkLoaded=true},q=function(B){var C=/^https?:\/\/www\.google(\.com?)?.\w{2,3}$/;return!!B.match(C)},r=function(B){return!!B.match(/cdn\.ampproject\.org$/)},s=function(){var B=c.ancestorOrigins||[],C=B[B.length-1]||c.origin,D=B[B.length-2]||c.origin;if(q(C)&&r(D))return n(D);else return n(C)},t=function(B){try{return JSON.parse(B)}catch(A){i(A.message);throw A}},u=function(B,C,D){if(!B.iframe){var E=D.createElement("iframe");E.src=d+"/audiencenetwork/iframe/";E.style.display="none";D.body.appendChild(E);B.iframe=E;B.iframeAppendedTime=h();B.iframeData={}}C.iframe=B.iframe;C.iframeData=B.iframeData;C.tagJsIframeAppendedTime=B.iframeAppendedTime||0},v=function(B){var C=d+"/audiencenetwork/xhr/?sdk=5.5.web";for(var D in B)if(typeof B[D]!=="function")C+="&"+D+"="+encodeURIComponent(B[D]);var E=new XMLHttpRequest();E.open("GET",C,true);E.withCredentials=true;E.onreadystatechange=function(){if(E.readyState===4){var F=t(E.response);B.events.push({name:"xhrLoaded",source:B.iframe.contentWindow,data:F,postMessageTimestamp:h(),receivedTimestamp:h()})}};E.send()},w=function(B,C){var D=d+"/audiencenetwork/xhriframe/?sdk=5.5.web";for(var E in C)if(typeof C[E]!=="function")D+="&"+E+"="+encodeURIComponent(C[E]);var F=b.createElement("iframe");F.src=D;F.style.display="none";b.body.appendChild(F);C.iframe=F;C.iframeData={};C.tagJsIframeAppendedTime=h()},x=function(B){var C=function(event){try{var E=event.data;if(E.name in f)B.events.push({name:E.name,source:event.source,data:E.data})}catch(A){}},D=B.iframe.contentWindow.parent;D.addEventListener("message",C,false)},y=function(a){if(a.context&&a.context.sourceUrl)return true;try{return!!JSON.parse(decodeURI(a.name)).ampcontextVersion}catch(A){return false}},z=function(B){var C=h(),D=l()[0],E=j().parentElement,F=D!=a.top,G=D.$sf&&D.$sf.ext,H=o(D),I=m();p(I);var J={amp:y(D),events:[],tagJsInitTime:C,rootElement:E,iframe:null,tagJsIframeAppendedTime:I.iframeAppendedTime||0,url:H,domain:s(),channel:n(o(D)),width:screen.width,height:screen.height,pixelratio:a.devicePixelRatio,placementindex:I.ads.length,crossdomain:F,safeframe:!!G,placementid:g.placementid,format:g.format||"300x250",testmode:!!g.testmode,onAdLoaded:g.onAdLoaded,onAdError:g.onAdError};if(g.bidid)J.bidid=g.bidid;if(F||!c.ancestorOrigins)w(I,J);else{u(I,J,D.document);v(J)}x(J);J.rootElement.dataset.placementid=J.placementid;I.ads.push(J)};try{z()}catch(A){i(A.message||A);throw A}})(window,document,location); </script> </div> </body> </html>
For units served via DFP but injected into the page by Prebid.js, set the DFP line-item's creative to:
<script> var w = window;for (i = 0; i < 10; i++) { w = w.parent; if (w.pbjs) { try { w.pbjs.renderAd(document, '%%PATTERN:hb_adid%%'); break; } catch (e) { continue; } } } </script>
We support 300x250 banner placements for Header Bidding.
A single call can request bids for multiple placements. Each placement needs to provide an ID and a format. Placement IDs should be unique within a single request unless you have Lazy Loading implemented on your site. Viewability for each Placement ID is taken into account when determining the bid request so keeping these unique is extremely important for optimal performance.
Here's an example of a raw request with three 300x250 banner placements using different Placement IDs for each slot on the page:
https://an.facebook.com/v2/placementbid.json? sdk=5.5.web&/* placement 1 */ placementids[]=123_456& adformats[]=300x250&/* placement 2 */ placementids[]=123_567& adformats[]=300x250/* placement 3 */ placementids[]=123_678& adformats[]=300x250
We return a JSON object describing the bids.
errors
holds a list of error messages, e.g. missing mandatory parameters, disabled placement, etc. Where the error affects a single placement only, it will be prefixed with the placement ID.bids
holds a map of placement ID to an array of bids (there may not be entries for all placement IDs or all bids requested per placement ID, e.g. for no bid).bid_id
is a token needed to later fetch and display the ad associated with this bid. The token is valid for 10 minutes.bid_price_cents
is the bid value, in USD cents, on a CPM basis. E.g. if the bid is 711.2, then the CPM is $7.11, and we will pay 0.7 cents for this single impression.{ "errors": [ ], "bids": { "123_456": [ { "placement_id": "123_456", "bid_id": "12345_67890", "bid_price_cents": 321.96265882399, "bid_price_currency": "usd", "bid_price_model": "cpm" }, ], "123_789": [ { "placement_id": "123_789", "bid_id": "12345_09876", "bid_price_cents": 711.28405256274, "bid_price_currency": "usd", "bid_price_model": "cpm" }, { "placement_id": "123_789", "bid_id": "12345_60987", "bid_price_cents": 702.34565789214, "bid_price_currency": "usd", "bid_price_model": "cpm" }, ], }, }
We may choose not to bid on any request. Common reasons include not being able to match the user to a Facebook account, or the page not running in a mobile browser.