diff --git a/floxis-backport-kit/INTEGRATION.md b/floxis-backport-kit/INTEGRATION.md index b01e2bc4f97..9e824af07b6 100644 --- a/floxis-backport-kit/INTEGRATION.md +++ b/floxis-backport-kit/INTEGRATION.md @@ -113,7 +113,23 @@ pbjs.setConfig({ Floxis syncs entirely, exclude `floxis` from both `iframe` and `image`; `userSync.syncEnabled: false` disables syncs for all bidders. -## 5. Verification & troubleshooting +## 5. Enable first-party fallback id (recommended) + +The adapter mints a random UUID in the publisher's own page context (`localStorage` + cookie, scoped to the publisher's origin) and sends it at `user.ext.floxisId`. This is an identity-of-last-resort for Safari, Firefox and other browsers where the Floxis third-party cookie (`__fxId`) is blocked — it does not affect Chrome/Edge, where the third-party cookie takes precedence on the backend. + +Since Prebid.js 7.x, bidder-level storage access is **denied by default**. Without the opt-in below, no id is generated and no storage is touched — a safe no-op, not an error. To enable it: + +```javascript +pbjs.bidderSettings = { + floxis: { + storageAllowed: true + } +}; +``` + +This is scoped to the Floxis bidder only and does not affect storage permissions for your other SSPs. Storage access is further gated by Prebid.js core's `deviceAccess` config and GDPR purpose-1 consent under Floxis's registered gvlid (1609). + +## 6. Verification & troubleshooting - **Enable debugging:** `pbjs.setConfig({ debug: true })` and watch the console. - **Module check:** confirm `floxisBidAdapter` appears in `pbjs.installedModules`. diff --git a/floxis-backport-kit/modules/floxisBidAdapter.js b/floxis-backport-kit/modules/floxisBidAdapter.js index bde6cbe1d11..fe70a0c4a67 100644 --- a/floxis-backport-kit/modules/floxisBidAdapter.js +++ b/floxis-backport-kit/modules/floxisBidAdapter.js @@ -1,8 +1,9 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import { ortbConverter } from '../libraries/ortbConverter/converter.js'; -import { triggerPixel, mergeDeep, replaceAuctionPrice } from '../src/utils.js'; +import { triggerPixel, mergeDeep, replaceAuctionPrice, generateUUID } from '../src/utils.js'; import { politeTriggerPixel } from '../libraries/floxisUtils/politePixel.js'; +import { getStorageManager } from '../src/storageManager.js'; const BIDDER_CODE = 'floxis'; const GVLID = 1609; @@ -12,6 +13,11 @@ const DEFAULT_NET_REVENUE = true; const DEFAULT_REGION = 'us-e'; const DEFAULT_PARTNER = BIDDER_CODE; const SYNC_PATH = '/sync'; +const FLOXIS_ID_KEY = 'flx_uid'; +const FLOXIS_ID_COOKIE_EXP = 2592000000; // 30 days +const UUID_LENGTH = 36; + +export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); // Server-echo user-sync: the /pbjs response carries seat + region in this header (on bid and no-bid // alike), so getUserSyncs derives sync targets from serverResponses statelessly — no module state that // could leak across concurrent auctions. Absent header (older backend) => no sync, a safe no-op. @@ -89,6 +95,40 @@ function normalizeBidParams(params = {}) { }; } +function isValidFloxisId(id) { + return typeof id === 'string' && id.length === UUID_LENGTH; +} + +// Neither store available => null, not a freshly minted id we can't persist (would defeat stability). +function getOrCreateFloxisId() { + if (typeof window === 'undefined') return null; + try { + const localOk = storage.localStorageIsEnabled(); + const cookieOk = storage.cookiesAreEnabled(); + if (!localOk && !cookieOk) return null; + + let id = localOk ? storage.getDataFromLocalStorage(FLOXIS_ID_KEY) : null; + if (!isValidFloxisId(id) && cookieOk) { + id = storage.getCookie(FLOXIS_ID_KEY); + } + if (!isValidFloxisId(id)) { + id = generateUUID(); + } + + if (localOk) { + storage.setDataInLocalStorage(FLOXIS_ID_KEY, id); + } + if (cookieOk) { + const expires = new Date(Date.now() + FLOXIS_ID_COOKIE_EXP).toUTCString(); + storage.setCookie(FLOXIS_ID_KEY, id, expires); + } + + return id; + } catch (e) { + return null; + } +} + // Parse the server-echoed sync header (`seat=®ion=