diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js index f606194e132..41ed2acce0e 100644 --- a/modules/yieldmoBidAdapter.js +++ b/modules/yieldmoBidAdapter.js @@ -18,6 +18,7 @@ import { import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {Renderer} from '../src/Renderer.js'; +import {coppaDataHandler} from '../src/adapterManager.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -70,6 +71,12 @@ export const spec = { * @return ServerRequest Info describing the request to the server. */ buildRequests: function (bidRequests, bidderRequest) { + // COPPA: Yieldmo does not serve child-directed inventory. When the request + // is flagged COPPA (regs.coppa, populated by core from config.getConfig('coppa')), + // discard it at the adapter — send no request so we never bid on it. + if (deepAccess(bidderRequest, 'ortb2.regs.coppa')) { + return []; + } const stage = isStage(bidderRequest); const bannerUrl = getAdserverUrl(BANNER_PATH, stage); const videoUrl = getAdserverUrl(VIDEO_PATH, stage); @@ -212,6 +219,11 @@ export const spec = { }, getUserSyncs: function(syncOptions, serverResponses, gdprConsent = {}, uspConsent = '') { + // COPPA: Yieldmo does not serve or track child-directed inventory — + // suppress cookie-sync pixels on COPPA traffic, mirroring the bid discard. + if (coppaDataHandler.getCoppa()) { + return []; + } const syncs = []; const gdprFlag = `&gdpr=${gdprConsent.gdprApplies ? 1 : 0}`; const gdprString = `&gdpr_consent=${encodeURIComponent((gdprConsent.consentString || ''))}`; diff --git a/test/spec/modules/yieldmoBidAdapter_spec.js b/test/spec/modules/yieldmoBidAdapter_spec.js index 4f4454c17ae..71a6c602192 100644 --- a/test/spec/modules/yieldmoBidAdapter_spec.js +++ b/test/spec/modules/yieldmoBidAdapter_spec.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { spec } from 'modules/yieldmoBidAdapter.js'; import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; /* eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */ // above is used for debugging purposes only @@ -462,6 +463,17 @@ describe('YieldmoAdapter', function () { expect(biddata[0].data.gpc).to.equal('1'); }); + it('should discard the banner request entirely when coppa is set', function () { + const requests = build([mockBannerBid()], mockBidderRequest({ ortb2: { regs: { coppa: 1 } } })); + expect(requests).to.deep.equal([]); + }); + + it('should build a normal banner request when coppa is not set', function () { + const requests = build([mockBannerBid()], mockBidderRequest()); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal(BANNER_ENDPOINT); + }); + it('should add eids to the banner bid request', function () { const params = { userIdAsEids: [{ @@ -758,6 +770,11 @@ describe('YieldmoAdapter', function () { expect(payload.regs.ext.gpc).to.equal('1'); }); + it('should discard the video request entirely when coppa is set', function () { + const requests = build([mockVideoBid()], mockBidderRequest({ ortb2: { regs: { coppa: 1 } } }, [mockVideoBid()])); + expect(requests).to.deep.equal([]); + }); + it('should add device info to payload if available', function () { let videoBidder = mockBidderRequest({ ortb2: { device: { @@ -946,5 +963,14 @@ describe('YieldmoAdapter', function () { it('should register no syncs', function () { expect(spec.getUserSyncs({})).to.deep.equal([]); }); + it('should register no syncs on COPPA (child-directed) traffic', function () { + config.setConfig({ coppa: true }); + try { + expect(spec.getUserSyncs({ iframeEnabled: true })).to.deep.equal([]); + expect(spec.getUserSyncs({ pixelEnabled: true })).to.deep.equal([]); + } finally { + config.resetConfig(); + } + }); }); });