Skip to content

Commit

Permalink
Lucead Bid Adapter: Update (prebid#11488)
Browse files Browse the repository at this point in the history
* Lucead Bid Adapter: Support Single Request Architecture mode + enhanced reporting + updated PAAPI auction config

* PB9 compliance

* Added TCF Global Vendor List ID

* Add GVLID to Lucead RTD Provider

* Add domain in impression tracking

* remove RTD related files

* remove useless code

* remove lucead from adloader
  • Loading branch information
aymeric45 authored and zkosanovic committed May 29, 2024
1 parent a72ef9f commit 5eaf093
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 133 deletions.
167 changes: 98 additions & 69 deletions modules/luceadBidAdapter.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
/**
* @module modules/luceadBidAdapter
*/

import {ortbConverter} from '../libraries/ortbConverter/converter.js';
import {loadExternalScript} from '../src/adloader.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {getUniqueIdentifierStr, logInfo, deepSetValue} from '../src/utils.js';
import {getUniqueIdentifierStr, deepSetValue, logInfo} from '../src/utils.js';
import {fetch} from '../src/ajax.js';

const gvlid = 1309;
const bidderCode = 'lucead';
const bidderName = 'Lucead';
let baseUrl = 'https://lucead.com';
let staticUrl = 'https://s.lucead.com';
let companionUrl = 'https://cdn.jsdelivr.net/gh/lucead/prebid-js-external-js-lucead@master/dist/prod.min.js';
let endpointUrl = 'https://prebid.lucead.com/go';
const defaultCurrency = 'EUR';
const defaultTtl = 500;
const aliases = ['adliveplus'];
const defaultRegion = 'eu';
const domain = 'lucead.com'
let baseUrl = `https://${domain}`;
let staticUrl = `https://s.${domain}`;
let endpointUrl = baseUrl;

function isDevEnv() {
return location.hash.includes('prebid-dev') || location.href.startsWith('https://ayads.io/test');
return location.hash.includes('prebid-dev');
}

function isBidRequestValid(bidRequest) {
return !!bidRequest?.params?.placementId;
}

export function log(msg, obj) {
logInfo(`${bidderName} - ${msg}`, obj);
}

function buildRequests(bidRequests, bidderRequest) {
const region = bidRequests[0]?.params?.region || defaultRegion;
endpointUrl = `https://${region}.${domain}`;

if (isDevEnv()) {
baseUrl = location.origin;
staticUrl = baseUrl;
companionUrl = `${staticUrl}/dist/prebid-companion.js`;
endpointUrl = `${baseUrl}/go`;
endpointUrl = `${baseUrl}`;
}

log('buildRequests', {
logInfo('buildRequests', {
bidRequests,
bidderRequest,
});
Expand All @@ -50,107 +52,134 @@ function buildRequests(bidRequests, bidderRequest) {
getUniqueIdentifierStr,
ortbConverter,
deepSetValue,
is_sra: true,
region,
};

loadExternalScript(companionUrl, bidderCode, () => window.ayads_prebid && window.ayads_prebid(companionData));
window.lucead_prebid_data = companionData;
const fn = window.lucead_prebid;

if (fn && typeof fn === 'function') {
fn(companionData);
}

return bidRequests.map(bidRequest => ({
return {
method: 'POST',
url: `${endpointUrl}/prebid/sub`,
url: `${endpointUrl}/go/prebid/sra`,
data: JSON.stringify({
request_id: bidderRequest.bidderRequestId,
domain: location.hostname,
bid_id: bidRequest.bidId,
sizes: bidRequest.sizes,
media_types: bidRequest.mediaTypes,
fledge_enabled: bidderRequest.fledgeEnabled,
enable_contextual: bidRequest?.params?.enableContextual !== false,
enable_pa: bidRequest?.params?.enablePA !== false,
params: bidRequest.params,
bid_requests: bidRequests.map(bidRequest => {
return {
bid_id: bidRequest.bidId,
sizes: bidRequest.sizes,
media_types: bidRequest.mediaTypes,
placement_id: bidRequest.params.placementId,
schain: bidRequest.schain,
};
}),
}),
options: {
contentType: 'text/plain',
withCredentials: false
},
}));
};
}

function interpretResponse(serverResponse, bidRequest) {
// @see required fields https://docs.prebid.org/dev-docs/bidder-adaptor.html
const response = serverResponse.body;
const bidRequestData = JSON.parse(bidRequest.data);

const bids = response.enable_contextual !== false ? [{
requestId: response?.bid_id || '1', // bid request id, the bid id
cpm: response?.cpm || 0,
width: (response?.size && response?.size?.width) || 300,
height: (response?.size && response?.size?.height) || 250,
currency: response?.currency || defaultCurrency,
ttl: response?.ttl || defaultTtl,
creativeId: response.ssp ? `ssp:${response.ssp}` : (response?.ad_id || '0'),
netRevenue: response?.netRevenue || true,
ad: response?.ad || '',
const response = serverResponse?.body;
const bidRequestData = JSON.parse(bidRequest?.data);

const bids = (response?.bids || []).map(bid => ({
requestId: bid?.bid_id || '1', // bid request id, the bid id
cpm: bid?.cpm || 0,
width: (bid?.size && bid?.size?.width) || 300,
height: (bid?.size && bid?.size?.height) || 250,
currency: bid?.currency || defaultCurrency,
ttl: bid?.ttl || defaultTtl,
creativeId: bid?.ssp ? `ssp:${bid.ssp}` : `${bid?.ad_id || 0}:${bid?.ig_id || 0}`,
netRevenue: bid?.net_revenue || true,
ad: bid?.ad || '',
meta: {
advertiserDomains: response?.advertiserDomains || [],
advertiserDomains: bid?.advertiser_domains || [],
},
}] : null;

log('interpretResponse', {serverResponse, bidRequest, bidRequestData, bids});

if (response.enable_pa === false) { return bids; }

const fledgeAuctionConfig = {
seller: baseUrl,
decisionLogicUrl: `${baseUrl}/js/ssp.js`,
interestGroupBuyers: [baseUrl],
perBuyerSignals: {},
auctionSignals: {
size: bidRequestData.sizes ? {width: bidRequestData?.sizes[0][0] || 300, height: bidRequestData?.sizes[0][1] || 250} : null,
},
};
}));

const fledgeAuctionConfigs = [{bidId: response.bid_id, config: fledgeAuctionConfig}];
logInfo('interpretResponse', {serverResponse, bidRequest, bidRequestData, bids});

if (response?.enable_pa === false) { return bids; }

const fledgeAuctionConfigs = (response.bids || []).map(bid => ({
bidId: bid?.bid_id,
config: {
seller: baseUrl,
decisionLogicUrl: `${baseUrl}/js/ssp.js`,
interestGroupBuyers: [baseUrl],
requestedSize: bid?.size,
auctionSignals: {
size: bid?.size,
},
perBuyerSignals: {
[baseUrl]: {
prebid_paapi: true,
prebid_bid_id: bid?.bid_id,
prebid_request_id: bidRequestData.request_id,
placement_id: bid.placement_id,
// floor,
is_sra: true,
endpoint_url: endpointUrl,
},
}
}
}));

return {bids, fledgeAuctionConfigs};
}

function report(type = 'impression', data = {}) {
function report(type, data) {
// noinspection JSCheckFunctionSignatures
return fetch(`${endpointUrl}/report/${type}`, {
body: JSON.stringify(data),
return fetch(`${endpointUrl}/go/report/${type}`, {
body: JSON.stringify({
...data,
domain: location.hostname,
}),
method: 'POST',
contentType: 'text/plain'
contentType: 'text/plain',
});
}

function onBidWon(bid) {
log('Bid won', bid);
logInfo('Bid won', bid);

let data = {
bid_id: bid?.bidId,
placement_id: bid?.params ? bid?.params[0]?.placementId : 0,
placement_id: bid.params ? (bid?.params[0]?.placementId || '0') : '0',
spent: bid?.cpm,
currency: bid?.currency,
};

if (bid.creativeId) {
if (bid.creativeId.toString().startsWith('ssp:')) {
data.ssp = bid.creativeId.split(':')[1];
if (bid?.creativeId) {
const parts = bid.creativeId.toString().split(':');

if (parts[0] === 'ssp') {
data.ssp = parts[1];
} else {
data.ad_id = bid.creativeId;
data.ad_id = parts[0]
data.ig_id = parts[1]
}
}

return report(`impression`, data);
return report('impression', data);
}

function onTimeout(timeoutData) {
log('Timeout from adapter', timeoutData);
logInfo('Timeout from adapter', timeoutData);
}

export const spec = {
code: bidderCode,
// gvlid: BIDDER_GVLID,
gvlid,
aliases,
isBidRequestValid,
buildRequests,
Expand Down
54 changes: 33 additions & 21 deletions modules/luceadBidAdapter.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
# Overview
# Lucead Bid Adapter

Module Name: Lucead Bidder Adapter
- Module Name: Lucead Bidder Adapter
- Module Type: Bidder Adapter
- Maintainer: prebid@lucead.com

Module Type: Bidder Adapter
## Description

Maintainer: prebid@lucead.com
Module that connects to Lucead demand source.

# Description
## Adapter configuration

Module that connects to Lucead demand source to fetch bids.
## Ad units parameters

# Test Parameters
### Type definition

```typescript
type Params = {
placementId: string;
region?: 'eu' | 'us' | 'ap';
};
```
const adUnits = [
{
code: 'test-div',
sizes: [[300, 250]],
bids: [
{
bidder: 'lucead',
params: {
placementId: '2',
}
}
]
}
];

### Example code
```javascript
const adUnits=[
{
code:'test-div',
sizes:[[300,250]],
bids:[
{
bidder: 'lucead',
params:{
placementId: '1',
region: 'us', // optional: 'eu', 'us', 'ap'
}
}
]
}
];
```
1 change: 0 additions & 1 deletion src/adloader.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ const _approvedLoadExternalJSList = [
'tncId',
'ftrackId',
'id5',
'lucead',
'51Degrees',
];

Expand Down
Loading

0 comments on commit 5eaf093

Please sign in to comment.