Skip to content

Commit

Permalink
amp integration (#756)
Browse files Browse the repository at this point in the history
* and postMessage listener and handler

* edit to sandbox domain

* update postMessage domain

* update postMessage domain

* work on render second ad bug

* rollback changes to match master

* add AMP example

* updates to address review notes

* updates to address review notes
  • Loading branch information
Nate Cozi authored and Matt Kendall committed Nov 1, 2016
1 parent 34f7b1f commit eeec25b
Show file tree
Hide file tree
Showing 4 changed files with 337 additions and 0 deletions.
81 changes: 81 additions & 0 deletions integrationExamples/gpt/amp/amp_page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!doctype html>
<html amp lang="en">
<head>
<!--
This is an example AMP page. This example includes:
amp_page.html host on publisher's amp domain (amp.publisher.com)
amp_page.html (canonical) host on publisher's main domain (publisher.com -- implied, not
part of example)
remote.html host on publisher's amp-x-domain domain (amp-x-domain.publisher.com)
creative.html script tag returned by ad server to fill with Prebid demand
-->
<meta charset="utf-8">
<title>Hello, AMPs</title>
<link rel="canonical" href="http://example.ampproject.org/article-metadata.html" />
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">

<!-- The following meta tag specifies the path to the publisher-hosted file to use as the
AMP x-domain host. The domain for ./remote.html must be different from the domain for
./amp_page.html to be a cross domain (secure, unfriendly) iframe. In this example the
domains and ports are:
https://publisher.com:9999/amp_page.html
and
https://amp.publisher.com:5000/remote.html
Further reading
AMP documentation <amp-ad> spec
https://www.ampproject.org/docs/reference/components/amp-ad
See sections on "Running ads from a custom domain" and "Enhance incoming ad
configuration" for more details on techniques used here.
-->
<meta name="amp-3p-iframe-src" content="https://amp.publisher.com:5000/remote.html">

<script async custom-element="amp-ad" src="https://cdn.ampproject.org/v0/amp-ad-0.1.js"></script>
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "NewsArticle",
"headline": "Open-source framework for publishing content",
"datePublished": "2015-10-07T12:02:41Z",
"image": [
"logo.jpg"
]
}
</script>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
<script async src="https://cdn.ampproject.org/v0.js"></script>
</head>
<body>
<h1>Welcome to the mobile web</h1>

<amp-ad
width="300"
height="250"
layout="fixed"
type="doubleclick"
data-slot="/19968336/header-bid-tag-1">
</amp-ad>

<amp-ad
width="300"
height="250"
layout="fixed"
type="doubleclick"
data-slot="/19968336/header-bid-tag-2">
</amp-ad>

<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam aliquam ac orci vitae cursus.
Nulla rutrum egestas felis ut bibendum. Maecenas blandit tellus eu turpis posuere condimentum sit amet eget eros. Donec sollicitudin sit amet enim ut ultricies. Nunc semper enim a dignissim convallis. Vestibulum faucibus eget ante non pellentesque. Maecenas convallis consectetur dolor, non facilisis felis interdum id. Cras ac leo et massa facilisis porttitor ut vitae dolor. Phasellus odio felis, pharetra vel sem vitae, ultricies ornare sapien. In sodales semper ultricies.

Suspendisse potenti. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer tempus rutrum libero, sit amet finibus sapien rutrum sed. Vestibulum accumsan turpis vel est cursus vulputate. Nam id risus ligula. Praesent metus elit, iaculis sit amet egestas id, interdum id nibh. Nullam egestas tempor lorem at consectetur. Fusce sit amet mattis massa, id semper elit. Mauris blandit lectus a orci lobortis malesuada.

Donec id turpis quam. Morbi fringilla justo nisi, et mattis nibh laoreet non. Aliquam orci eros, tincidunt a feugiat id, gravida ut nisl. Morbi et arcu facilisis, congue mauris ut, ultricies ligula. Vivamus vulputate est non facilisis iaculis. Phasellus quis auctor odio. Nulla facilisi. Sed convallis feugiat erat, sit amet tincidunt justo bibendum ut. Sed maximus justo sit amet pharetra tincidunt. Vivamus laoreet nisi vel est feugiat, sed egestas ante congue.

Nunc ultricies sodales dolor eget semper. Phasellus ac ligula ac mi fermentum ornare sed et lacus. Curabitur ante enim, maximus ac lacus in, hendrerit mollis enim. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas posuere nisl ac nisl sagittis faucibus. Quisque pellentesque vehicula lectus, ac malesuada dui mollis pulvinar. Nam in lectus placerat eros feugiat dictum ut vel quam. Etiam magna mauris, euismod in felis sodales, interdum ultricies nisl. Nunc elit mi, pellentesque vel est nec, tempus dignissim purus. Praesent pharetra, odio ut cursus dictum, erat felis gravida lorem, at pretium justo dolor quis odio. Mauris tincidunt accumsan mi, gravida condimentum enim vulputate at. Phasellus pretium hendrerit commodo. Quisque blandit rhoncus erat, sed tincidunt dolor rutrum et.

Nunc nec condimentum mauris, vel porta sem. Donec finibus sapien lacus, quis faucibus neque lobortis non. Nam faucibus nunc odio. Aliquam dolor nisl, placerat sed ipsum quis, facilisis sollicitudin nisi. Nullam sed ultrices enim. Ut sollicitudin mi dignissim, faucibus massa in, pellentesque velit. Donec auctor vel libero in posuere. Ut venenatis odio nec euismod egestas. Nunc posuere pretium sapien finibus sagittis. Nunc volutpat ante eget eleifend consequat. Donec sed quam sit amet quam venenatis pulvinar. Nullam in ex id magna pellentesque tempus.
</div>
</body>
</html>
38 changes: 38 additions & 0 deletions integrationExamples/gpt/amp/creative.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!-- This script tag should be returned by your ad server -->

<script>
// This is the `renderAd` function from Prebid.js moved within the creative iframe
var renderAd = function (ev) {
var key = ev.message ? "message" : "data";
var data = {};
try {
data = JSON.parse(ev[key]);
} catch (e) {
// Do nothing. No ad found.
}
if (data.ad || data.adUrl) {
if (data.ad) {
document.write(data.ad);
document.close();
} else if (data.adUrl) {
document.write('<IFRAME SRC="' + data.adUrl + '" FRAMEBORDER="0" SCROLLING="no" MARGINHEIGHT="0" MARGINWIDTH="0" TOPMARGIN="0" LEFTMARGIN="0" ALLOWTRANSPARENCY="true"></IFRAME>');
document.close();
}
}
};

var requestAdFromPrebid = function () {
var message = JSON.stringify({
message: 'Prebid creative requested: %%PATTERN:hb_adid%%',
adId: '%%PATTERN:hb_adid%%'
});
window.parent.postMessage(message, '*');
};

var listenAdFromPrebid = function () {
window.addEventListener("message", renderAd, false);
};

listenAdFromPrebid();
requestAdFromPrebid();
</script>
17 changes: 17 additions & 0 deletions integrationExamples/gpt/amp/gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/** Run `gulp serve` to serve files from this directory in development
* Set two different entries in hosts to use x-domain iframes
* AMP requires https
*/

var gulp = require('gulp');
var connect = require('gulp-connect');
var port = 5000;

gulp.task('serve', function() {
connect.server({
port: port,
root: './',
livereload: true,
https: true
});
});
201 changes: 201 additions & 0 deletions integrationExamples/gpt/amp/remote.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="robots" content="noindex">
<script>

/** This file is the AMP x-domain iframe source file.
* Host this file on a cross-domain from your AMP pages,
* set the `amp-3p-iframe-src` meta tag on your AMP pages
* (see `./amp_page.html`)
*
* see "Enhance incoming ad configuration" section of AMP docs
* https://www.ampproject.org/docs/reference/components/amp-ad
*/

(function() {
var v = location.search.substr(1);
if (!(/^\d+(-canary)?$/.test(v))) return;
var u = 'https://3p.ampproject.net/'+encodeURIComponent(v)+'/f.js';
document.write('<script'+' src="'+encodeURI(u)+'"><'+'/script>');
})();
</script>

<!-- start Prebid.js AMP integration -->

<script>
// The Prebid global must match Prebid.js setting
var $$PREBID_GLOBAL$$ = pbjs;
var prebidSrc = 'https://publisher.com:9999/build/dev/prebid.js';
var rightSlotSizes = [[300, 250], [300, 600], [300, 250], [100, 100]];
var adUnits = [
{
code: '/19968336/header-bid-tag-1',
sizes: rightSlotSizes,
bids: [
{
bidder: 'appnexusAst',
params: {
placementId: '4799418',
dealId: 'some deal!'
}
},
{
bidder: 'aol',
params: {
network: '10077.1',
placement: 3671670
}
},
{
bidder: 'sovrn',
params: {
tagid: "315045"
}
}
]
},
{
code: '/19968336/header-bid-tag-2',
sizes: rightSlotSizes,
bids: [
{
bidder: 'appnexusAst',
params: {
placementId: '4799418',
dealId: 'some deal!'
}
},
{
bidder: 'aol',
params: {
network: '10077.1',
placement: 3671670
}
},
{
bidder: 'sovrn',
params: {
tagid: "315045"
}
}
]
}
];

// load Prebid.js
(function () {
var d = document, pbs = d.createElement("script"), pro = d.location.protocal;
pbs.type = "text/javascript";
pbs.src = prebidSrc;
var target = document.getElementsByTagName("head")[0];
target.insertBefore(pbs, target.firstChild);
})();

var pbjs = pbjs || {};
pbjs.que = pbjs.que || [];
var PREBID_TIMEOUT = 3000;

var date = new Date().getTime();

/** wrap the rest of the setup in a function that will be called by the
* AMP `draw3p` hook see
* this example for more info:
* https://dfp-amp-testing-1185.appspot.com/amp_tests/dfp-3p-iframe.html
* */
function loadPrebidJS() {
pbjs.que.push(function () {
pbjs.logging = true;
pbjs.addAdUnits(adUnits);

pbjs.requestBids({
bidsBackHandler: function (bidResponses) {
initAdserver();
console.log('bidsBackHandler responses: ', bidResponses);
},
timeout: 3000
});
});
}

function setTargeting(config, done) {
config.targeting = getTargeting(config.slot);
done(config);
}

function getTargeting(slot) {
var targeting = window.context.master.pbjs.getAdserverTargeting()[slot];
for (var key in targeting) {
if (targeting.hasOwnProperty(key)) {
targeting[key] = [targeting[key]];
}
}
targeting['prebid_amp'] = ['true'];
return targeting;
}

function initAdserver() {
var i;
var adCalls = window.context.master.adCalls;
var adCallsLength = adCalls.length;
for (i = 0; i < adCallsLength; i++) {
adCalls.pop()();
}
}

function listenAdRequestFromCreative() {
addEventListener('message', sendAdToCreative, false);
}

function sendAdToCreative(ev) {
var key = ev.message ? 'message' : 'data';
var data = {};
try {
data = JSON.parse(ev[key]);
} catch (e) {
// Do nothing. No ad found.
}
if (data.adId) {
// AMP ads a `context` object to `window`s and that is used to find the
// `master` iframe where Prebid is loaded
var adObject = window.context.master.pbjs._bidsReceived.find(function (bid) {
return bid.adId === data.adId;
});

var ad = adObject.ad;
var adUrl = adObject.adUrl;
var message = JSON.stringify({
message: 'Prebid creative sent: ' + data.adId,
ad: ad,
adUrl: adUrl
});
ev.source.postMessage(message, '*');
}
}
</script>
</head>
<body style="margin:0">
<div id="c" style="position:absolute;top:0;left:0;bottom:0;right:0;">
<script>
/** The draw3p function is the integration point between AMP and content in third party
* iframes. For more info see: https://github.com/ampproject/amphtml/blob/e5501a30adf15c8fef049729f5e0e3137dbb18ca/3p/integration.js#L252
*/
draw3p(function(config, done) {
if (typeof window.context.master.adCalls === 'undefined') {
window.context.master.adCalls = [];
}
if (window.context && window.context.isMaster) {
loadPrebidJS();
}
window.context.master.adCalls.push(setTargeting.bind(null, config, done));
}, ['doubleclick'], ['publisher.com']);
// the first array contains ad networks used, the second domains allows to load this file in an iframe

listenAdRequestFromCreative();
</script>
</div>

<script>if (window.docEndCallback) window.docEndCallback()</script>
</body>
</html>

0 comments on commit eeec25b

Please sign in to comment.