• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

prebid / Prebid.js / #305

27 Jun 2025 12:10PM UTC coverage: 90.409% (-0.01%) from 90.422%
#305

push

travis-ci

prebidjs-release
Prebid 9.52.0 release

43449 of 54513 branches covered (79.7%)

64185 of 70994 relevant lines covered (90.41%)

174.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.44
/modules/teadsIdSystem.js
1
/**
1✔
2
 * This module adds TeadsId to the User ID module
3
 * The {@link module:modules/userId} module is required
4
 * @module modules/teadsIdSystem
5
 * @requires module:modules/userId
6
 */
7

8
import {isStr, isNumber, logError, logInfo, isEmpty, timestamp} from '../src/utils.js'
9
import {ajax} from '../src/ajax.js';
10
import {submodule} from '../src/hook.js';
11
import {getStorageManager} from '../src/storageManager.js';
12
import {MODULE_TYPE_UID} from '../src/activities/modules.js';
13

14
/**
15
 * @typedef {import('../modules/userId/index.js').Submodule} Submodule
16
 * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig
17
 * @typedef {import('../modules/userId/index.js').ConsentData} ConsentData
18
 * @typedef {import('../modules/userId/index.js').IdResponse} IdResponse
19
 */
20

21
const MODULE_NAME = 'teadsId';
1✔
22
const GVL_ID = 132;
1✔
23
const FP_TEADS_ID_COOKIE_NAME = '_tfpvi';
1✔
24
const EXPIRED_COOKIE_DATE = 'Thu, 01 Jan 1970 00:00:01 GMT';
1✔
25

26
export const gdprStatus = {
1✔
27
  GDPR_DOESNT_APPLY: 0,
28
  CMP_NOT_FOUND_OR_ERROR: 22,
29
  GDPR_APPLIES_PUBLISHER: 12,
30
};
31

32
export const gdprReason = {
1✔
33
  GDPR_DOESNT_APPLY: 0,
34
  CMP_NOT_FOUND: 220,
35
  GDPR_APPLIES_PUBLISHER_CLASSIC: 120,
36
};
37

38
export const storage = getStorageManager({moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME});
1✔
39

40
/** @type {Submodule} */
41
export const teadsIdSubmodule = {
1✔
42
  /**
43
   * used to link submodule with config
44
   * @type {string}
45
   */
46
  name: MODULE_NAME,
47
  /**
48
   * Vendor id of Teads
49
   * @type {number}
50
   */
51
  gvlid: GVL_ID,
52
  /**
53
   * decode the stored id value for passing to bid requests
54
   * @function
55
   * @param {string} value
56
   * @returns {{teadsId:string}}
57
   */
58
  decode(value) {
59
    return {teadsId: value}
×
60
  },
61
  /**
62
   * performs action to obtain id and return a value in the callback's response argument
63
   * @function
64
   * @param {SubmoduleConfig} [submoduleConfig]
65
   * @param {ConsentData} [consentData]
66
   * @returns {IdResponse|undefined}
67
   */
68
  getId(submoduleConfig, consentData) {
69
    const resp = function (callback) {
5✔
70
      const url = buildAnalyticsTagUrl(submoduleConfig, consentData);
5✔
71

72
      const callbacks = {
5✔
73
        success: (bodyResponse, responseObj) => {
74
          if (responseObj && responseObj.status === 200) {
4✔
75
            if (isStr(bodyResponse) && !isEmpty(bodyResponse)) {
3✔
76
              const cookiesMaxAge = getTimestampFromDays(365); // 1 year
2✔
77
              const expirationCookieDate = getCookieExpirationDate(cookiesMaxAge);
2✔
78
              storage.setCookie(FP_TEADS_ID_COOKIE_NAME, bodyResponse, expirationCookieDate);
2✔
79
              callback(bodyResponse);
2✔
80
            } else {
81
              storage.setCookie(FP_TEADS_ID_COOKIE_NAME, '', EXPIRED_COOKIE_DATE);
1✔
82
              callback();
1✔
83
            }
84
          } else {
85
            logInfo(`${MODULE_NAME}: Server error while fetching ID`);
1✔
86
            callback();
1✔
87
          }
88
        },
89
        error: error => {
90
          logError(`${MODULE_NAME}: ID fetch encountered an error`, error);
1✔
91
          callback();
1✔
92
        }
93
      };
94

95
      ajax(url, callbacks, undefined, {method: 'GET'});
5✔
96
    };
97
    return {callback: resp};
5✔
98
  },
99
  eids: {
100
    teadsId: {
101
      source: 'teads.com',
102
      atype: 1
103
    }
104
  }
105
};
106

107
/**
108
 * Build the full URL from the Submodule config & consentData
109
 * @param submoduleConfig
110
 * @param consentData
111
 * @returns {string}
112
 */
113
export function buildAnalyticsTagUrl(submoduleConfig, consentData) {
114
  const pubId = getPublisherId(submoduleConfig);
6✔
115
  const teadsViewerId = getTeadsViewerId();
6✔
116
  const status = getGdprStatus(consentData?.gdpr);
6✔
117
  const gdprConsentString = getGdprConsentString(consentData?.gdpr);
6✔
118
  const ccpaConsentString = getCcpaConsentString(consentData?.usp);
6✔
119
  const gdprReason = getGdprReasonFromStatus(status);
6✔
120
  const params = {
6✔
121
    analytics_tag_id: pubId,
122
    tfpvi: teadsViewerId,
123
    gdpr_consent: gdprConsentString,
124
    gdpr_status: status,
125
    gdpr_reason: gdprReason,
126
    ccpa_consent: ccpaConsentString,
127
    sv: 'prebid-v1',
128
  };
129

130
  const url = 'https://at.teads.tv/fpc';
6✔
131
  const queryParams = new URLSearchParams();
6✔
132

133
  for (const param in params) {
6✔
134
    queryParams.append(param, params[param]);
42✔
135
  }
136

137
  return url + '?' + queryParams.toString();
6✔
138
}
139

140
/**
141
 * Extract the Publisher ID from the Submodule config
142
 * @returns {string}
143
 * @param submoduleConfig
144
 */
145
export function getPublisherId(submoduleConfig) {
146
  const pubId = submoduleConfig?.params?.pubId;
16✔
147
  const prefix = 'PUB_';
16✔
148
  if (isNumber(pubId)) {
16✔
149
    return prefix + pubId.toString();
2✔
150
  }
151
  if (isStr(pubId) && parseInt(pubId)) {
14✔
152
    return prefix + pubId;
1✔
153
  }
154
  return '';
13✔
155
}
156

157
/**
158
 * Extract the GDPR status from the given consentData
159
 * @param consentData
160
 * @returns {number}
161
 */
162
export function getGdprStatus(consentData) {
163
  const gdprApplies = consentData?.gdprApplies;
18✔
164
  if (gdprApplies === true) {
18✔
165
    return gdprStatus.GDPR_APPLIES_PUBLISHER;
2✔
166
  } else if (gdprApplies === false) {
16✔
167
    return gdprStatus.GDPR_DOESNT_APPLY;
1✔
168
  } else {
169
    return gdprStatus.CMP_NOT_FOUND_OR_ERROR;
15✔
170
  }
171
}
172

173
/**
174
 * Extract the GDPR consent string from the given consentData
175
 * @param consentData
176
 * @returns {string}
177
 */
178
export function getGdprConsentString(consentData) {
179
  const consentString = consentData?.consentString;
15✔
180
  if (isStr(consentString)) {
15✔
181
    return consentString;
2✔
182
  } else {
183
    return '';
13✔
184
  }
185
}
186

187
/**
188
 * Map the GDPR reason from the given GDPR status
189
 * @param status
190
 * @returns {number}
191
 */
192
function getGdprReasonFromStatus(status) {
193
  switch (status) {
6!
194
    case gdprStatus.GDPR_DOESNT_APPLY:
195
      return gdprReason.GDPR_DOESNT_APPLY;
×
196
    case gdprStatus.CMP_NOT_FOUND_OR_ERROR:
197
      return gdprReason.CMP_NOT_FOUND;
5✔
198
    case gdprStatus.GDPR_APPLIES_PUBLISHER:
199
      return gdprReason.GDPR_APPLIES_PUBLISHER_CLASSIC;
1✔
200
    default:
201
      return -1;
×
202
  }
203
}
204

205
/**
206
 * Return the well formatted CCPA consent string
207
 * @param ccpaConsentString
208
 * @returns {string|*}
209
 */
210
export function getCcpaConsentString(ccpaConsentString) {
211
  if (isStr(ccpaConsentString)) {
11✔
212
    return ccpaConsentString;
1✔
213
  } else {
214
    return '';
10✔
215
  }
216
}
217

218
/**
219
 * Get the cookie expiration date string from a given Date and a max age
220
 * @param {number} maxAge
221
 * @returns {string}
222
 */
223
export function getCookieExpirationDate(maxAge) {
224
  return new Date(timestamp() + maxAge).toUTCString()
4✔
225
}
226

227
/**
228
 * Get cookie from Cookie or Local Storage
229
 * @returns {string}
230
 */
231
function getTeadsViewerId() {
232
  const teadsViewerId = readCookie()
6✔
233
  if (isStr(teadsViewerId)) {
6!
234
    return teadsViewerId
×
235
  } else {
236
    return '';
6✔
237
  }
238
}
239

240
function readCookie() {
241
  return storage.cookiesAreEnabled(null) ? storage.getCookie(FP_TEADS_ID_COOKIE_NAME, null) : null;
6!
242
}
243

244
/**
245
 * Return a number of milliseconds from given days number
246
 * @param days
247
 * @returns {number}
248
 */
249
export function getTimestampFromDays(days) {
250
  return days * 24 * 60 * 60 * 1000;
4✔
251
}
252
submodule('userId', teadsIdSubmodule);
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc