Google DFP - 从内部调整 SafeFrame 自定义广告素材外部 Iframe 容器的大小(展开广告)
Google DFP - Resize SafeFrame custom creative outer Iframe container from inside (expand ad)
我正在寻找可以从 Google DFP 中的自定义广告素材内部扩展 SafeFrame 自定义广告的解决方案,这是否可行?
有 2 种可能的解决方案:
1) 使用 SafeFrame API
优点:
- 你可以用它 "out of the box"
- 您可以在任何网站上使用它,不需要网站上的自定义代码
- 使用安全
缺点:
- 它仅限于填充网站的可见区域
- 需要等待,直到广告单元对用户可见
2) 使用 window.postMessage()
javascript 方法
编写您自己的 API
缺点:
- 您需要向您的网站添加自定义代码
- 如果您使用某些第 3 方广告素材,这可能是一种威胁
优点:
- 您几乎可以通过广告素材对您的网站执行任何操作
1) 使用 SafeFrame API
这个API真的好用,你可以看一些例子
GPT Safeframe preview tool.
首先,您需要在网站<head>
中更新 DFP 初始化脚本
var pageConfig = {
allowOverlayExpansion: true,
allowPushExpansion: true,
sandbox: true
};
googletag.pubads().setSafeFrameConfig(pageConfig);
这将允许在您的网站上展开 SafeFrame 广告。更多关于这个在
Control SafeFrame Container behavior through GPT.
现在您可以创建自定义广告素材并将其作为 SafeFrame 投放到您的网站上。这是我的一个例子。这个例子可以 "wait" util 它是可见的,然后将扩展到 <div id="container">
的高度,它在 SafeFrame:
内
<div id="container">
some lines to make container height<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
</div>
<script>
// global expanded indicator variable, because API don't have any
var expanded = false;
function expand() {
var self= $sf.ext.geom().self;
var config = {
push: true, // we want to push expanded content
b: 0
};
var el = document.getElementById('container');
var containerHeight = el.offsetHeight;
// get height from bottom, that need to be expanded
var expandBottom = containerHeight - self.h;
// if container is whole inside a SafeFrame, it will not expand
if(expandBottom < 0) return;
config.b = expandBottom;
$sf.ext.expand(config);
}
function expandDelayed(forceExpand) {
// expand will run just once, or you can force it to run again
// but collapse first is needed
if(expanded && forceExpand || !expanded) {
$sf.ext.collapse();
expanded = false;
// there must be some timeout, because .collapse(); method is deplayed somehow
setTimeout(expand, 0);
}
}
$sf.ext.register(160, 150, function(status, data) {
// this code will do whole magic of "waiting" for right moment
if (status === 'geom-update') {
expandDelayed();
}
// change global expanded status
if (status === 'expanded') {
expanded = true;
}
});
// init
expandDelayed();
</script>
2。使用 window.postMessage()
javascript 方法
编写您自己的 API
首先,您需要将此代码放入网站 <head>
中的 DFP 初始化脚本。此代码会将广告位的 ID 添加为 #hash-tag
到 <iframe>
的 src,以便您可以从广告素材内部获取它。
googletag.pubads().addEventListener('slotRenderEnded', function (event) {
var containerId = event.slot.getSlotElementId();
var containerEl = document.getElementById(containerId);
if (containerEl === null) return;
var iframeEl = containerEl.querySelectorAll('iframe')[0];
// it's delayed by 10 milliseconds, because iframe is not yet fully rendered
// and limited to max to 10 seconds to wait
var timeoutFunction = function () {
var src = "#" + containerId;
// `src` attribute is null, when iframe is FriendlyIframe, and
// when it's present, then it's SafeFrame
if (iframeEl.getAttribute('src') !== null) {
src = iframeEl.getAttribute('src').replace(/#.*/, "") + src;
} else {
var name = iframeEl.getAttribute('name') + "#" + containerId;
iframeEl.setAttribute('name', name);
}
iframeEl.setAttribute('src', src);
};
setTimeout(timeoutFunction, 10);
});
其次,您需要将此代码添加到您的网站,最好是单独的 .js 文件。
function onMessageReceivedGetStyle(e) {
// this will filter just setStyle commands from correct origin
if (
!(e.origin === 'http://tpc.googlesyndication.com' || e.origin === 'https://tpc.googlesyndication.com') ||
typeof e.data !== 'object' ||
typeof e.data.id !== 'string' ||
e.data.cmd !== 'setStyle' ||
typeof e.data.params !== 'object'
) {
return;
}
// remove # character from id, we don't use jquery
var elementId = e.data.id.replace(/#/, "");
var wrapperEl = document.getElementById(elementId);
if (wrapperEl === null) {
return;
}
var elements = [wrapperEl];
// you can target child elements too with query parameter
if (typeof e.data.query === 'string' && e.data.query) {
elements = wrapperEl.querySelectorAll(e.data.query);
}
elements.forEach(function (element) {
Object.keys(e.data.params).forEach(function (param) {
element.style[param] = e.data.params[param];
});
});
}
if (window.addEventListener) {
addEventListener('message', onMessageReceivedGetStyle, false);
}
else {
if (window.attachEvent) {
attachEvent('onmessage', onMessageReceivedGetStyle);
}
else {
window.onmessage = onMessageReceivedGetStyle;
}
}
第三件事是您在 DFP 广告管理系统中自定义广告素材类型的自定义代码。这是示例,类似于
第一个例子,但这里这个脚本可以等到所有内容和图像都加载完毕,然后 expand/shrink 你的
带有广告素材的 iframe:
<div id="container">
<a href="#" target="_blank">
<img src="%%FILE:JPG1%%">
</a>
<a href="#" target="_blank">
<img src="%%FILE:JPG2%%">
</a>
</div>
<style>
a {
display: block;
margin-bottom: .5em;
}
img {
display: block;
max-width: 100%;
}
*:last-child {
margin-bottom: 0;
}
</style>
<script>
var container = document.getElementById('container');
function resizeOutsideSafeFrame() {
if (!window.top.postMessage) {
return false;
}
// get ID of your Ad unit <div> with this creative
var divGptAdId = '%%PATTERN:url%%';
if (divGptAdId.indexOf('#') !== -1) {
divGptAdId = divGptAdId.split('#')[1];
} else {
divGptAdId = window.location.hash;
}
if(!divGptAdId) {
if (window.name.indexOf('#') !== -1) {
divGptAdId = window.name.split('#')[1];
}
}
if(!divGptAdId) {
return;
}
// set with to fullwidth, and height to height of container inside creative
var width = '100%';
var height = container.offsetHeight + 'px';
// send our request to website
window.top.postMessage({
cmd: 'setStyle',
id: divGptAdId,
query: 'div, iframe', // we want to target child div and iframe and don't change container styles
params: {
display: 'block',
height: height,
width: width
}
}, '*');
}
document.onreadystatechange = function () {
// resize iframe when all is loaded
if (document.readyState == "complete") {
resizeOutsideSafeFrame();
}
};
// first resize must occur little bit later
setTimeout(resizeOutsideSafeFrame, 100);
</script>
就是这样。当您想从 iframe 内部更改您网站上的任何内容时,您可以在您的
网站并从 iframe 内部调用此命令。
编辑 1:
现在才注意到,var divGptAdId = '%%PATTERN:url%%;
不会return 以#hash 方式在页面上更正 div 的 id,所以现在需要给他一个正确的容器 div id 更改:
if(!divGptAdId) {
return;
}
至
if(!divGptAdId) {
divGptAdId = 'div-gpt-ad-container-div-id-1';
}
我找不到任何可靠的文档,所以来自 PayteR 的示例对我帮助很大!我不得不尝试使用新的维度来让广告以正确的方式展开。
这是我根据 PayteR 的示例创建的一些示例代码:
/* Main object for namespacing */
var Ad = function(obj) {};
/*
Register your ad with the dimensions of the current ad.
- This is basically an event handler for the the ad frame.
- 728 initial ad width
- 90 initial ad height
*/
Ad.prototype.registerExpand = function() {
$sf.ext.register(728, 90, function(status, data){});
};
/* Expand function to be called on click or load */
Ad.prototype.expandAd = function() {
/* Get the current geometry of your ad */
var self = $sf.ext.geom().self;
/*
Set the new geometry
- Increase height 315 pixels
- Expand downward by setting the bottom to the new height minus the current height
*/
$sf.ext.expand({
h: 315,
b: 315 - self.h
});
};
/* Intialize, register, and expand */
var ad = new Ad();
ad.registerExpand();
ad.expandAd();
我正在寻找可以从 Google DFP 中的自定义广告素材内部扩展 SafeFrame 自定义广告的解决方案,这是否可行?
有 2 种可能的解决方案:
1) 使用 SafeFrame API
优点:
- 你可以用它 "out of the box"
- 您可以在任何网站上使用它,不需要网站上的自定义代码
- 使用安全
缺点:
- 它仅限于填充网站的可见区域
- 需要等待,直到广告单元对用户可见
2) 使用 window.postMessage()
javascript 方法
缺点:
- 您需要向您的网站添加自定义代码
- 如果您使用某些第 3 方广告素材,这可能是一种威胁
优点:
- 您几乎可以通过广告素材对您的网站执行任何操作
1) 使用 SafeFrame API
这个API真的好用,你可以看一些例子 GPT Safeframe preview tool.
首先,您需要在网站<head>
中更新 DFP 初始化脚本
var pageConfig = {
allowOverlayExpansion: true,
allowPushExpansion: true,
sandbox: true
};
googletag.pubads().setSafeFrameConfig(pageConfig);
这将允许在您的网站上展开 SafeFrame 广告。更多关于这个在 Control SafeFrame Container behavior through GPT.
现在您可以创建自定义广告素材并将其作为 SafeFrame 投放到您的网站上。这是我的一个例子。这个例子可以 "wait" util 它是可见的,然后将扩展到 <div id="container">
的高度,它在 SafeFrame:
<div id="container">
some lines to make container height<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
line<br>
</div>
<script>
// global expanded indicator variable, because API don't have any
var expanded = false;
function expand() {
var self= $sf.ext.geom().self;
var config = {
push: true, // we want to push expanded content
b: 0
};
var el = document.getElementById('container');
var containerHeight = el.offsetHeight;
// get height from bottom, that need to be expanded
var expandBottom = containerHeight - self.h;
// if container is whole inside a SafeFrame, it will not expand
if(expandBottom < 0) return;
config.b = expandBottom;
$sf.ext.expand(config);
}
function expandDelayed(forceExpand) {
// expand will run just once, or you can force it to run again
// but collapse first is needed
if(expanded && forceExpand || !expanded) {
$sf.ext.collapse();
expanded = false;
// there must be some timeout, because .collapse(); method is deplayed somehow
setTimeout(expand, 0);
}
}
$sf.ext.register(160, 150, function(status, data) {
// this code will do whole magic of "waiting" for right moment
if (status === 'geom-update') {
expandDelayed();
}
// change global expanded status
if (status === 'expanded') {
expanded = true;
}
});
// init
expandDelayed();
</script>
2。使用 window.postMessage()
javascript 方法
编写您自己的 API
首先,您需要将此代码放入网站 <head>
中的 DFP 初始化脚本。此代码会将广告位的 ID 添加为 #hash-tag
到 <iframe>
的 src,以便您可以从广告素材内部获取它。
googletag.pubads().addEventListener('slotRenderEnded', function (event) {
var containerId = event.slot.getSlotElementId();
var containerEl = document.getElementById(containerId);
if (containerEl === null) return;
var iframeEl = containerEl.querySelectorAll('iframe')[0];
// it's delayed by 10 milliseconds, because iframe is not yet fully rendered
// and limited to max to 10 seconds to wait
var timeoutFunction = function () {
var src = "#" + containerId;
// `src` attribute is null, when iframe is FriendlyIframe, and
// when it's present, then it's SafeFrame
if (iframeEl.getAttribute('src') !== null) {
src = iframeEl.getAttribute('src').replace(/#.*/, "") + src;
} else {
var name = iframeEl.getAttribute('name') + "#" + containerId;
iframeEl.setAttribute('name', name);
}
iframeEl.setAttribute('src', src);
};
setTimeout(timeoutFunction, 10);
});
其次,您需要将此代码添加到您的网站,最好是单独的 .js 文件。
function onMessageReceivedGetStyle(e) {
// this will filter just setStyle commands from correct origin
if (
!(e.origin === 'http://tpc.googlesyndication.com' || e.origin === 'https://tpc.googlesyndication.com') ||
typeof e.data !== 'object' ||
typeof e.data.id !== 'string' ||
e.data.cmd !== 'setStyle' ||
typeof e.data.params !== 'object'
) {
return;
}
// remove # character from id, we don't use jquery
var elementId = e.data.id.replace(/#/, "");
var wrapperEl = document.getElementById(elementId);
if (wrapperEl === null) {
return;
}
var elements = [wrapperEl];
// you can target child elements too with query parameter
if (typeof e.data.query === 'string' && e.data.query) {
elements = wrapperEl.querySelectorAll(e.data.query);
}
elements.forEach(function (element) {
Object.keys(e.data.params).forEach(function (param) {
element.style[param] = e.data.params[param];
});
});
}
if (window.addEventListener) {
addEventListener('message', onMessageReceivedGetStyle, false);
}
else {
if (window.attachEvent) {
attachEvent('onmessage', onMessageReceivedGetStyle);
}
else {
window.onmessage = onMessageReceivedGetStyle;
}
}
第三件事是您在 DFP 广告管理系统中自定义广告素材类型的自定义代码。这是示例,类似于 第一个例子,但这里这个脚本可以等到所有内容和图像都加载完毕,然后 expand/shrink 你的 带有广告素材的 iframe:
<div id="container">
<a href="#" target="_blank">
<img src="%%FILE:JPG1%%">
</a>
<a href="#" target="_blank">
<img src="%%FILE:JPG2%%">
</a>
</div>
<style>
a {
display: block;
margin-bottom: .5em;
}
img {
display: block;
max-width: 100%;
}
*:last-child {
margin-bottom: 0;
}
</style>
<script>
var container = document.getElementById('container');
function resizeOutsideSafeFrame() {
if (!window.top.postMessage) {
return false;
}
// get ID of your Ad unit <div> with this creative
var divGptAdId = '%%PATTERN:url%%';
if (divGptAdId.indexOf('#') !== -1) {
divGptAdId = divGptAdId.split('#')[1];
} else {
divGptAdId = window.location.hash;
}
if(!divGptAdId) {
if (window.name.indexOf('#') !== -1) {
divGptAdId = window.name.split('#')[1];
}
}
if(!divGptAdId) {
return;
}
// set with to fullwidth, and height to height of container inside creative
var width = '100%';
var height = container.offsetHeight + 'px';
// send our request to website
window.top.postMessage({
cmd: 'setStyle',
id: divGptAdId,
query: 'div, iframe', // we want to target child div and iframe and don't change container styles
params: {
display: 'block',
height: height,
width: width
}
}, '*');
}
document.onreadystatechange = function () {
// resize iframe when all is loaded
if (document.readyState == "complete") {
resizeOutsideSafeFrame();
}
};
// first resize must occur little bit later
setTimeout(resizeOutsideSafeFrame, 100);
</script>
就是这样。当您想从 iframe 内部更改您网站上的任何内容时,您可以在您的 网站并从 iframe 内部调用此命令。
编辑 1:
现在才注意到,var divGptAdId = '%%PATTERN:url%%;
不会return 以#hash 方式在页面上更正 div 的 id,所以现在需要给他一个正确的容器 div id 更改:
if(!divGptAdId) {
return;
}
至
if(!divGptAdId) {
divGptAdId = 'div-gpt-ad-container-div-id-1';
}
我找不到任何可靠的文档,所以来自 PayteR 的示例对我帮助很大!我不得不尝试使用新的维度来让广告以正确的方式展开。
这是我根据 PayteR 的示例创建的一些示例代码:
/* Main object for namespacing */
var Ad = function(obj) {};
/*
Register your ad with the dimensions of the current ad.
- This is basically an event handler for the the ad frame.
- 728 initial ad width
- 90 initial ad height
*/
Ad.prototype.registerExpand = function() {
$sf.ext.register(728, 90, function(status, data){});
};
/* Expand function to be called on click or load */
Ad.prototype.expandAd = function() {
/* Get the current geometry of your ad */
var self = $sf.ext.geom().self;
/*
Set the new geometry
- Increase height 315 pixels
- Expand downward by setting the bottom to the new height minus the current height
*/
$sf.ext.expand({
h: 315,
b: 315 - self.h
});
};
/* Intialize, register, and expand */
var ad = new Ad();
ad.registerExpand();
ad.expandAd();