Skip to content

Commit 4a86a23

Browse files
musikeleMichele Nasti
and
Michele Nasti
authored
Add macro to track clicks (#196)
* added support for GAM macro %%CLICK_URL_UNESC%% * add tests for %%CLICK_URL_UNESC%% * add info about clickUrlUnesc in readme Co-authored-by: Michele Nasti <michele@rtk.io>
1 parent d7b728c commit 4a86a23

File tree

4 files changed

+97
-6
lines changed

4 files changed

+97
-6
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ You can find a detailed explanations on the [Prebid Universal Creative](http://p
2323
ucTagData.hbPb = "%%PATTERN:hb_pb%%";
2424
ucTagData.hbFormat = "%%PATTERN:hb_format%%";
2525
ucTagData.adId = "%%PATTERN:hb_adid%%";
26+
// if you're using GAM and want to track outbound clicks on native ads you can add this line
27+
ucTagData.clickUrlUnesc = "%%CLICK_URL_UNESC%%";
2628
ucTagData.requestAllAssets = true;
2729
2830
try {

src/nativeAssetManager.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,21 @@ const assetTypeMapping = {
5959
const DEFAULT_CACHE_HOST = 'prebid.adnxs.com';
6060
const DEFAULT_CACHE_PATH = '/pbc/v1/cache';
6161

62-
export function newNativeAssetManager(win, pubUrl) {
62+
const CLICK_URL_UNESC = `%%CLICK_URL_UNESC%%`;
63+
64+
let clickUrlUnesc = '';
65+
66+
export function newNativeAssetManager(win, nativeTag) {
67+
const { pubUrl } = nativeTag;
68+
69+
70+
// clickUrlUnesc contains the url to track clicks in GAM. we check if it
71+
// has been transformed, by GAM, in an URL.
72+
// if CLICK_URL_UNESC is the string "%%CLICK_URL_UNESC%%", we're not in GAM.
73+
if (nativeTag.clickUrlUnesc && nativeTag.clickUrlUnesc !== CLICK_URL_UNESC) {
74+
clickUrlUnesc = nativeTag.clickUrlUnesc;
75+
}
76+
6377
const sendMessage = prebidMessenger(pubUrl, win);
6478
let callback;
6579
let errorCountEscapeHatch = 0;
@@ -289,6 +303,9 @@ export function newNativeAssetManager(win, pubUrl) {
289303
}
290304

291305
if (data.message === 'assetResponse') {
306+
// add GAM %%CLICK_URL_UNESC%% to the data object to be eventually used in renderers
307+
data.clickUrlUnesc = clickUrlUnesc;
308+
292309
const body = win.document.body.innerHTML;
293310
const head = win.document.head.innerHTML;
294311

@@ -375,6 +392,10 @@ export function newNativeAssetManager(win, pubUrl) {
375392
}
376393
}
377394
}
395+
396+
//substitute CLICK_URL_UNESC with actual value
397+
html = html.replaceAll(CLICK_URL_UNESC, bid.clickUrlUnesc || "");
398+
378399
win.document.body.innerHTML += html;
379400
callback && callback();
380401
win.removeEventListener('message', replaceAssets);

src/nativeRenderManager.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export function newNativeRenderManager(win) {
5151
let renderNativeAd = function(doc, nativeTag) {
5252
window.pbNativeData = nativeTag;
5353
sendMessage = prebidMessenger(nativeTag.pubUrl, win);
54-
const nativeAssetManager = newNativeAssetManager(window, nativeTag.pubUrl);
54+
const nativeAssetManager = newNativeAssetManager(window, nativeTag);
5555

5656
if (nativeTag.hasOwnProperty('adId')) {
5757

test/spec/nativeAssetManager_spec.js

+72-4
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,16 @@ const mockDocument = {
4040
};
4141

4242
// creates mock postmessage response from prebid's native.js:getAssetMessage
43-
function createResponder(assets,url,template) {
43+
function createResponder(assets,url,template, clickUrlUnesc = '') {
4444
return function(type, listener) {
4545
if (type !== 'message') { return; }
4646

47-
const data = { message: 'assetResponse', adId: AD_ID, assets, adTemplate:template, rendererUrl:url };
47+
const data = {
48+
message: 'assetResponse',
49+
adId: AD_ID, assets,
50+
adTemplate:template,
51+
rendererUrl:url,
52+
};
4853
listener({ data: JSON.stringify(data), origin: ORIGIN});
4954
};
5055
}
@@ -86,8 +91,11 @@ function generateRenderer(assets) {
8691
describe('nativeAssetManager', () => {
8792
let win;
8893

89-
function makeManager() {
90-
return newNativeAssetManager(win, ORIGIN);
94+
function makeManager(args) {
95+
return newNativeAssetManager(win, {
96+
pubUrl: ORIGIN,
97+
...args
98+
});
9199
}
92100

93101
beforeEach(() => {
@@ -578,4 +586,64 @@ describe('nativeAssetManager', () => {
578586
expect(win.document.body.style.width).to.equal('600px');
579587
});
580588
});
589+
590+
describe('GAM macro %%CLICK_URL_UNESC%%', () => {
591+
it("should remove %%CLICK_URL_UNESC%% if there's no variable set", () => {
592+
const html = `<script>
593+
let nativeTag = {};
594+
nativeTag.adTemplate = "<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"%%CLICK_URL_UNESC%%##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>";
595+
nativeTag.pubUrl = "https://www.url.com";
596+
nativeTag.adId = "`+AD_ID+`";
597+
nativeTag.requestAllAssets = true;
598+
window.pbNativeTag.renderNativeAd(nativeTag);
599+
</script>`;
600+
win.pbNativeData = {
601+
pubUrl : 'https://www.url.com',
602+
adId : AD_ID,
603+
adTemplate : '<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"%%CLICK_URL_UNESC%%##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>'
604+
};
605+
606+
win.document.body.innerHTML = html;
607+
win.addEventListener = createResponder([
608+
{ key: 'body', value: 'Body content' },
609+
{ key: 'title', value: 'new value' },
610+
{ key: 'clickUrl', value: 'http://www.example.com' },
611+
{ key: 'image', value: 'http://www.image.com/picture.jpg' },
612+
]);
613+
614+
const nativeAssetManager = makeManager();
615+
nativeAssetManager.loadAssets(AD_ID);
616+
617+
expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
618+
});
619+
620+
it("should substitute %%CLICK_URL_UNESC%% with clickUrlUnesc value", () => {
621+
const html = `<script>
622+
let nativeTag = {};
623+
nativeTag.adTemplate = "<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"%%CLICK_URL_UNESC%%##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>";
624+
nativeTag.pubUrl = "https://www.url.com";
625+
nativeTag.adId = "`+AD_ID+`";
626+
nativeTag.requestAllAssets = true;
627+
window.pbNativeTag.renderNativeAd(nativeTag);
628+
</script>`;
629+
win.pbNativeData = {
630+
pubUrl : 'https://www.url.com',
631+
adId : AD_ID,
632+
adTemplate : '<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"%%CLICK_URL_UNESC%%##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>',
633+
};
634+
635+
win.document.body.innerHTML = html;
636+
win.addEventListener = createResponder([
637+
{ key: 'body', value: 'Body content' },
638+
{ key: 'title', value: 'new value' },
639+
{ key: 'clickUrl', value: 'http://www.example.com' },
640+
{ key: 'image', value: 'http://www.image.com/picture.jpg' },
641+
], null, null, );
642+
643+
const nativeAssetManager = makeManager({ clickUrlUnesc: 'https://will.redirect/?to='});
644+
nativeAssetManager.loadAssets(AD_ID);
645+
646+
expect(win.document.body.innerHTML).to.include(`<a href="https://will.redirect/?to=http://www.example.com" target="_blank" class="pb-click">new value</a>`);
647+
});
648+
});
581649
});

0 commit comments

Comments
 (0)