@highfivve/ad-tag 5.6.3 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ads/a9.js +13 -11
- package/lib/ads/adService.js +1 -1
- package/lib/ads/criteo.js +49 -0
- package/lib/ads/id5.js +30 -0
- package/lib/ads/modules/ad-reload/index.js +3 -2
- package/lib/ads/modules/emetriq/trackLoginEvent.js +7 -1
- package/lib/ads/modules/identitylink/index.js +14 -1
- package/lib/ads/modules/interstitial/interstitialAd.js +4 -0
- package/lib/ads/modules/sticky-footer-ad/desktopFloorAd.js +1 -0
- package/lib/ads/modules/sticky-footer-ad/mobileSticky.js +4 -0
- package/lib/ads/modules/sticky-footer-ad-v2/footerStickyAd.js +4 -0
- package/lib/ads/modules/sticky-header-ad/renderResult.js +4 -0
- package/lib/ads/moli.js +19 -0
- package/lib/ads/prebid.js +15 -4
- package/lib/gen/packageJson.js +1 -1
- package/package.json +1 -1
package/lib/ads/a9.js
CHANGED
|
@@ -3,7 +3,6 @@ import { AssetLoadMethod } from '../util/assetLoaderService';
|
|
|
3
3
|
import { isSizeEqual } from '../util/sizes';
|
|
4
4
|
import { SizeConfigService } from './sizeConfigService';
|
|
5
5
|
import { tcfapi } from '../types/tcfapi';
|
|
6
|
-
var TCPurpose = tcfapi.responses.TCPurpose;
|
|
7
6
|
import * as adUnitPath from './adUnitPath';
|
|
8
7
|
const isA9SlotDefinition = (slotDefinition) => {
|
|
9
8
|
return !!slotDefinition.moliSlot.a9;
|
|
@@ -11,13 +10,13 @@ const isA9SlotDefinition = (slotDefinition) => {
|
|
|
11
10
|
const hasRequiredConsent = (tcData) => !tcData.gdprApplies ||
|
|
12
11
|
(tcData.vendor.consents['793'] &&
|
|
13
12
|
[
|
|
14
|
-
TCPurpose.STORE_INFORMATION_ON_DEVICE,
|
|
15
|
-
TCPurpose.SELECT_BASIC_ADS,
|
|
16
|
-
TCPurpose.CREATE_PERSONALISED_ADS_PROFILE,
|
|
17
|
-
TCPurpose.SELECT_PERSONALISED_ADS,
|
|
18
|
-
TCPurpose.MEASURE_AD_PERFORMANCE,
|
|
19
|
-
TCPurpose.APPLY_MARKET_RESEARCH,
|
|
20
|
-
TCPurpose.DEVELOP_IMPROVE_PRODUCTS
|
|
13
|
+
tcfapi.responses.TCPurpose.STORE_INFORMATION_ON_DEVICE,
|
|
14
|
+
tcfapi.responses.TCPurpose.SELECT_BASIC_ADS,
|
|
15
|
+
tcfapi.responses.TCPurpose.CREATE_PERSONALISED_ADS_PROFILE,
|
|
16
|
+
tcfapi.responses.TCPurpose.SELECT_PERSONALISED_ADS,
|
|
17
|
+
tcfapi.responses.TCPurpose.MEASURE_AD_PERFORMANCE,
|
|
18
|
+
tcfapi.responses.TCPurpose.APPLY_MARKET_RESEARCH,
|
|
19
|
+
tcfapi.responses.TCPurpose.DEVELOP_IMPROVE_PRODUCTS
|
|
21
20
|
].every(purpose => tcData.purpose.consents[purpose]));
|
|
22
21
|
export const a9Init = (config, assetService) => mkInitStep('a9-init', (context) => new Promise(resolve => {
|
|
23
22
|
context.window__.apstag = context.window__.apstag || {
|
|
@@ -84,9 +83,12 @@ export const a9Configure = (config, schainConfig) => mkConfigureStep('a9-configu
|
|
|
84
83
|
resolve();
|
|
85
84
|
});
|
|
86
85
|
});
|
|
87
|
-
export const a9PublisherAudiences = (config) => mkConfigureStepOnce('a9-publisher-audiences', (context, _slots) => new Promise(resolve => {
|
|
88
|
-
const
|
|
89
|
-
|
|
86
|
+
export const a9PublisherAudiences = (config, audienceTargeting) => mkConfigureStepOnce('a9-publisher-audiences', (context, _slots) => new Promise(resolve => {
|
|
87
|
+
const runtimeHem = audienceTargeting?.hem?.sha256;
|
|
88
|
+
const publisherAudience = runtimeHem !== undefined
|
|
89
|
+
? { enabled: !!config.publisherAudience?.enabled, sha256Email: runtimeHem }
|
|
90
|
+
: config.publisherAudience;
|
|
91
|
+
if (publisherAudience !== undefined && publisherAudience.enabled) {
|
|
90
92
|
const tokenConfig = {
|
|
91
93
|
hashedRecords: [
|
|
92
94
|
{
|
package/lib/ads/adService.js
CHANGED
|
@@ -96,7 +96,7 @@ export class AdService {
|
|
|
96
96
|
if (config.a9 && config.a9.enabled !== false && env === 'production' && isGam) {
|
|
97
97
|
init.push(a9Init(config.a9, this.assetService));
|
|
98
98
|
configure.push(a9Configure(config.a9, config.schain));
|
|
99
|
-
configure.push(a9PublisherAudiences(config.a9));
|
|
99
|
+
configure.push(a9PublisherAudiences(config.a9, runtimeConfig.audience));
|
|
100
100
|
prepareRequestAds.push(a9ClearTargetingStep());
|
|
101
101
|
requestBids.push(a9RequestBids(config.a9));
|
|
102
102
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const criteoEnrichWithFpd = (runtimeConfig, userSyncConfig, source) => (bidderConfigs) => {
|
|
2
|
+
const criteoEnabled = userSyncConfig?.userIds?.find(uid => uid.name === 'criteo') !== undefined;
|
|
3
|
+
if (!criteoEnabled) {
|
|
4
|
+
return bidderConfigs;
|
|
5
|
+
}
|
|
6
|
+
const uids = [];
|
|
7
|
+
if (runtimeConfig.audience?.hem?.sha256 !== undefined) {
|
|
8
|
+
uids.push({
|
|
9
|
+
id: runtimeConfig.audience.hem.sha256,
|
|
10
|
+
atype: 3,
|
|
11
|
+
ext: { stype: 'hemsha256' }
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
if (runtimeConfig.audience?.hem?.sha256ofMD5 !== undefined) {
|
|
15
|
+
uids.push({
|
|
16
|
+
id: runtimeConfig.audience.hem.sha256ofMD5,
|
|
17
|
+
atype: 3,
|
|
18
|
+
ext: { stype: 'hemsha256md5' }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
if (uids.length === 0) {
|
|
22
|
+
return bidderConfigs;
|
|
23
|
+
}
|
|
24
|
+
return [
|
|
25
|
+
...bidderConfigs.filter(config => !config.options.bidders.every(b => b === 'criteo')),
|
|
26
|
+
{
|
|
27
|
+
options: {
|
|
28
|
+
bidders: ['criteo'],
|
|
29
|
+
config: {
|
|
30
|
+
ortb2: {
|
|
31
|
+
user: {
|
|
32
|
+
ext: {
|
|
33
|
+
data: {
|
|
34
|
+
eids: [
|
|
35
|
+
{
|
|
36
|
+
source: source,
|
|
37
|
+
uids: uids
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
merge: true
|
|
47
|
+
}
|
|
48
|
+
];
|
|
49
|
+
};
|
package/lib/ads/id5.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const createPd = (runtimeConfig) => {
|
|
2
|
+
const sha256Email = runtimeConfig.audience?.hem?.sha256;
|
|
3
|
+
if (!sha256Email) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
const pdKeys = {
|
|
7
|
+
1: sha256Email
|
|
8
|
+
};
|
|
9
|
+
const pdRaw = Object.entries(pdKeys)
|
|
10
|
+
.map(([key, value]) => {
|
|
11
|
+
return `${key}=${encodeURIComponent(value)}`;
|
|
12
|
+
})
|
|
13
|
+
.join('&');
|
|
14
|
+
return btoa(pdRaw);
|
|
15
|
+
};
|
|
16
|
+
export const enrichId5WithFpd = (runtimeConfig, userIds) => {
|
|
17
|
+
return userIds?.map(idProvider => {
|
|
18
|
+
if (idProvider.name === 'id5Id') {
|
|
19
|
+
const pd = createPd(runtimeConfig);
|
|
20
|
+
return {
|
|
21
|
+
...idProvider,
|
|
22
|
+
params: {
|
|
23
|
+
...idProvider.params,
|
|
24
|
+
...(pd && { pd })
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return idProvider;
|
|
29
|
+
});
|
|
30
|
+
};
|
|
@@ -28,12 +28,13 @@ export class AdReload {
|
|
|
28
28
|
this.adVisibilityService = new AdVisibilityService(new UserActivityService(window, config.userActivityLevelControl, logger), this.refreshIntervalMs, config.refreshIntervalMsOverrides ?? {}, false, !!config.disableAdVisibilityChecks, config.viewabilityOverrides ?? {}, window, logger);
|
|
29
29
|
};
|
|
30
30
|
this.setupSlotRenderListener = (config, slotsToMonitor, reloadAdSlotCallback, window, logger) => window.googletag.pubads().addEventListener('slotRenderEnded', renderEndedEvent => {
|
|
31
|
-
const { slot: googleTagSlot, campaignId, advertiserId, yieldGroupIds, isEmpty: slotIsEmpty } = renderEndedEvent;
|
|
31
|
+
const { slot: googleTagSlot, campaignId, advertiserId, companyIds, yieldGroupIds, isEmpty: slotIsEmpty } = renderEndedEvent;
|
|
32
32
|
const slotDomId = googleTagSlot.getSlotElementId();
|
|
33
33
|
const slotIsMonitored = slotsToMonitor.indexOf(slotDomId) > -1;
|
|
34
34
|
const orderIdNotExcluded = !campaignId || config.excludeOrderIds.indexOf(campaignId) === -1;
|
|
35
35
|
const orderIdIncluded = !!campaignId && config.includeOrderIds.indexOf(campaignId) > -1;
|
|
36
|
-
const advertiserIdIncluded = !!advertiserId && config.includeAdvertiserIds.indexOf(advertiserId) > -1
|
|
36
|
+
const advertiserIdIncluded = (!!advertiserId && config.includeAdvertiserIds.indexOf(advertiserId) > -1) ||
|
|
37
|
+
(!!companyIds && config.includeAdvertiserIds.some(id => companyIds.includes(id)));
|
|
37
38
|
const yieldGroupIdIncluded = !!yieldGroupIds && config.includeYieldGroupIds.some(id => yieldGroupIds.indexOf(id) > -1);
|
|
38
39
|
const trackingSlotAllowed = !slotIsEmpty &&
|
|
39
40
|
slotIsMonitored &&
|
|
@@ -32,7 +32,13 @@ export const trackLoginEvent = (context, moduleConfig, document, logger) => {
|
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
const url = new URL(`https://xdn-ttp.de/lns/import-event-${moduleConfig.login.partner}`);
|
|
35
|
-
|
|
35
|
+
const hemSha256 = context.runtimeConfig__.audience?.hem?.sha256;
|
|
36
|
+
const resolvedGuid = hemSha256 !== undefined ? context.window__.btoa(hemSha256) : moduleConfig.login.guid;
|
|
37
|
+
if (resolvedGuid === undefined) {
|
|
38
|
+
logger.warn('emetriq', 'no guid provided for login event tracking');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
url.searchParams.append('guid', resolvedGuid);
|
|
36
42
|
if (context.tcData__.gdprApplies) {
|
|
37
43
|
url.searchParams.append('gdpr', '1');
|
|
38
44
|
url.searchParams.append('gdpr_consent', context.tcData__.tcString);
|
|
@@ -42,9 +42,22 @@ export class IdentityLink {
|
|
|
42
42
|
}
|
|
43
43
|
const window = context.window__;
|
|
44
44
|
window.addEventListener('envelopeModuleReady', () => {
|
|
45
|
+
const hashedEmailAddresses = [...moduleConfig.hashedEmailAddresses];
|
|
46
|
+
const sha1 = context.runtimeConfig__.audience?.hem?.sha1;
|
|
47
|
+
const sha256 = context.runtimeConfig__.audience?.hem?.sha256;
|
|
48
|
+
const md5 = context.runtimeConfig__.audience?.hem?.md5;
|
|
49
|
+
if (sha1 !== undefined) {
|
|
50
|
+
hashedEmailAddresses[0] = sha1;
|
|
51
|
+
}
|
|
52
|
+
if (sha256 !== undefined) {
|
|
53
|
+
hashedEmailAddresses[1] = sha256;
|
|
54
|
+
}
|
|
55
|
+
if (md5 !== undefined) {
|
|
56
|
+
hashedEmailAddresses[2] = md5;
|
|
57
|
+
}
|
|
45
58
|
window.atsenvelopemodule.setAdditionalData({
|
|
46
59
|
type: 'emailHashes',
|
|
47
|
-
id:
|
|
60
|
+
id: hashedEmailAddresses
|
|
48
61
|
});
|
|
49
62
|
});
|
|
50
63
|
return context.assetLoaderService__
|
|
@@ -14,6 +14,10 @@ const interstitialRenderedEvent = (interstitialDomId, disallowedAdvertiserIds, w
|
|
|
14
14
|
else if (event.advertiserId && disallowedAdvertiserIds.includes(event.advertiserId)) {
|
|
15
15
|
resolve({ result: 'disallowed', slot: event.slot });
|
|
16
16
|
}
|
|
17
|
+
else if (event.companyIds &&
|
|
18
|
+
disallowedAdvertiserIds.some(id => event.companyIds?.includes(id))) {
|
|
19
|
+
resolve({ result: 'disallowed', slot: event.slot });
|
|
20
|
+
}
|
|
17
21
|
else {
|
|
18
22
|
event.slot.setConfig({ safeFrame: { forceSafeFrame: true } });
|
|
19
23
|
resolve({ result: 'standard', slot: event.slot });
|
|
@@ -22,6 +22,7 @@ const renderFooterAd = (window, floorAdDomId, disallowedAdvertiserIds, log) => (
|
|
|
22
22
|
slot.getSlotElementId() !== floorAdDomId ||
|
|
23
23
|
event.isEmpty ||
|
|
24
24
|
(!!event.advertiserId && disallowedAdvertiserIds.includes(event.advertiserId)) ||
|
|
25
|
+
(!!event.companyIds && disallowedAdvertiserIds.some(id => event.companyIds?.includes(id))) ||
|
|
25
26
|
window.matchMedia('(max-width: 767px)').matches) {
|
|
26
27
|
log.debug('[footer-ad]', 'remove footer ad container');
|
|
27
28
|
return;
|
|
@@ -23,6 +23,10 @@ const stickyRenderedEvent = (adSticky, mobileStickyDomId, disallowedAdvertiserId
|
|
|
23
23
|
else if (!!event.advertiserId && disallowedAdvertiserIds.includes(event.advertiserId)) {
|
|
24
24
|
resolve('disallowed');
|
|
25
25
|
}
|
|
26
|
+
else if (!!event.companyIds &&
|
|
27
|
+
disallowedAdvertiserIds.some(id => event.companyIds?.includes(id))) {
|
|
28
|
+
resolve('disallowed');
|
|
29
|
+
}
|
|
26
30
|
else {
|
|
27
31
|
resolve('standard');
|
|
28
32
|
}
|
|
@@ -15,6 +15,10 @@ const stickyRenderedEvent = (mobileStickyDomId, disallowedAdvertiserIds, window)
|
|
|
15
15
|
else if (event.advertiserId && disallowedAdvertiserIds.includes(event.advertiserId)) {
|
|
16
16
|
resolve('disallowed');
|
|
17
17
|
}
|
|
18
|
+
else if (!!event.companyIds &&
|
|
19
|
+
disallowedAdvertiserIds.some(id => event.companyIds?.includes(id))) {
|
|
20
|
+
resolve('disallowed');
|
|
21
|
+
}
|
|
18
22
|
else {
|
|
19
23
|
resolve('standard');
|
|
20
24
|
}
|
|
@@ -10,6 +10,10 @@ export const adRenderResult = (ctx, headerSlot, disallowedAdvertiserIds, minVisi
|
|
|
10
10
|
if (event.advertiserId && disallowedAdvertiserIds.includes(event.advertiserId)) {
|
|
11
11
|
resolve('disallowed');
|
|
12
12
|
}
|
|
13
|
+
else if (event.companyIds &&
|
|
14
|
+
disallowedAdvertiserIds.some(id => event.companyIds?.includes(id))) {
|
|
15
|
+
resolve('disallowed');
|
|
16
|
+
}
|
|
13
17
|
else if (event.isEmpty) {
|
|
14
18
|
resolve('empty');
|
|
15
19
|
}
|
package/lib/ads/moli.js
CHANGED
|
@@ -589,6 +589,24 @@ export const createMoliTag = (window) => {
|
|
|
589
589
|
addLabel(domain);
|
|
590
590
|
}
|
|
591
591
|
}
|
|
592
|
+
function setAudience(audience) {
|
|
593
|
+
switch (state.state) {
|
|
594
|
+
case 'configurable':
|
|
595
|
+
case 'configured': {
|
|
596
|
+
state.runtimeConfig.audience = audience;
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
case 'spa-finished':
|
|
600
|
+
case 'spa-requestAds': {
|
|
601
|
+
state.nextRuntimeConfig.audience = audience;
|
|
602
|
+
break;
|
|
603
|
+
}
|
|
604
|
+
default: {
|
|
605
|
+
getLogger(state.runtimeConfig, window).error('MoliGlobal', `Setting audience targeting after configuration: ${JSON.stringify(audience)}`);
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
592
610
|
function newEmptyRuntimeConfig(previous, options) {
|
|
593
611
|
return {
|
|
594
612
|
environment: previous?.environment ?? 'production',
|
|
@@ -639,6 +657,7 @@ export const createMoliTag = (window) => {
|
|
|
639
657
|
triggerDelay: triggerDelay,
|
|
640
658
|
getState: getState,
|
|
641
659
|
openConsole: openConsole,
|
|
660
|
+
setAudience: setAudience,
|
|
642
661
|
addEventListener: eventService.addEventListener,
|
|
643
662
|
removeEventListener: eventService.removeEventListener
|
|
644
663
|
};
|
package/lib/ads/prebid.js
CHANGED
|
@@ -8,6 +8,8 @@ import { AssetLoadMethod } from '../util/assetLoaderService';
|
|
|
8
8
|
import { packageJson } from 'ad-tag/gen/packageJson';
|
|
9
9
|
import { prebidOutstreamRenderer } from 'ad-tag/ads/prebid-outstream';
|
|
10
10
|
import { isGamInterstitial } from 'ad-tag/ads/auctions/interstitialContext';
|
|
11
|
+
import { criteoEnrichWithFpd } from 'ad-tag/ads/criteo';
|
|
12
|
+
import { enrichId5WithFpd } from 'ad-tag/ads/id5';
|
|
11
13
|
const prebidTimeout = (context) => {
|
|
12
14
|
return new Promise((_, reject) => {
|
|
13
15
|
context.window__.setTimeout(() => reject('Prebid did not resolve in time. Maybe you forgot to import the prebid distribution in the ad tag'), 5000);
|
|
@@ -152,7 +154,8 @@ export const prebidInit = (assetService) => mkInitStep('prebid-init', context =>
|
|
|
152
154
|
});
|
|
153
155
|
export const prebidRemoveAdUnits = (prebidConfig) => mkConfigureStep('prebid-remove-adunits', (context) => new Promise(resolve => {
|
|
154
156
|
if (prebidConfig.ephemeralAdUnits !== true) {
|
|
155
|
-
context.window__.pbjs =
|
|
157
|
+
context.window__.pbjs =
|
|
158
|
+
context.window__.pbjs || { que: [] };
|
|
156
159
|
const adUnits = context.window__.pbjs.adUnits;
|
|
157
160
|
if (adUnits) {
|
|
158
161
|
context.window__.pbjs.que.push(() => {
|
|
@@ -165,7 +168,8 @@ export const prebidRemoveAdUnits = (prebidConfig) => mkConfigureStep('prebid-rem
|
|
|
165
168
|
}));
|
|
166
169
|
export const prebidClearAuction = () => {
|
|
167
170
|
return mkConfigureStepOncePerRequestAdsCycle('prebid-clear-auction', (context) => new Promise(resolve => {
|
|
168
|
-
context.window__.pbjs =
|
|
171
|
+
context.window__.pbjs =
|
|
172
|
+
context.window__.pbjs || { que: [] };
|
|
169
173
|
context.window__.pbjs.que.push(() => {
|
|
170
174
|
context.logger__.debug('Prebid', 'Clearing prebid auctions');
|
|
171
175
|
context.window__.pbjs.clearAllAuctions();
|
|
@@ -203,12 +207,19 @@ export const prebidConfigure = (prebidConfig, schainConfig) => {
|
|
|
203
207
|
}
|
|
204
208
|
});
|
|
205
209
|
}
|
|
210
|
+
const enrichedUserIds = enrichId5WithFpd(context.runtimeConfig__, prebidConfig.config.userSync?.userIds);
|
|
206
211
|
context.window__.pbjs.setConfig({
|
|
207
212
|
...prebidConfig.config,
|
|
208
213
|
...{ schain: mkSupplyChainConfig([schainConfig.supplyChainStartNode]) },
|
|
209
|
-
...{ floors: prebidConfig.config.floors || {} }
|
|
214
|
+
...{ floors: prebidConfig.config.floors || {} },
|
|
215
|
+
...{
|
|
216
|
+
userSync: prebidConfig.config.userSync
|
|
217
|
+
? { ...prebidConfig.config.userSync, userIds: enrichedUserIds }
|
|
218
|
+
: prebidConfig.config.userSync
|
|
219
|
+
}
|
|
210
220
|
});
|
|
211
|
-
|
|
221
|
+
const bidderConfigs = criteoEnrichWithFpd(context.runtimeConfig__, prebidConfig.config.userSync, context.window__.location.host)(prebidConfig.bidderConfigs || []);
|
|
222
|
+
bidderConfigs.forEach(({ options, merge }) => {
|
|
212
223
|
context.window__.pbjs.setBidderConfig(options, merge);
|
|
213
224
|
});
|
|
214
225
|
prebidConfig.schain.nodes.forEach(({ bidder, node, appendNode }) => {
|
package/lib/gen/packageJson.js
CHANGED