Skip to content

Commit f49bd50

Browse files
Floxis Bid Adapter: initial release (#13934)
* Floxis Bid Adapter : initial release * Added ORTB parameters for blocking * Adjusted documentation with maintainer info * Added more validations, extracted converter to a const * Floxis Bid Adapter: redesign to seat-based architecture with ortbConverter Major rewrite replacing teqblazeUtils with ortbConverter for ORTB 2.x compliance. Changes: - New params: seat (required), region (required), partner (required) - Endpoint URL: https://{subdomain}.floxis.tech/pbjs?seat={seat} - subdomain = region for 'floxis' partner - subdomain = {partner}-{region} for white-label partners - ORTB-native implementation with Floors Module support - 40 comprehensive tests with full code coverage - Updated documentation with examples Addresses all PR #13934 review comments from @osazos * Rename FloxisBidAdapter.md to floxisBidAdapter.md * Code review adjustments --------- Co-authored-by: Patrick McCann <pmccann@cafemedia.com>
1 parent 956dea0 commit f49bd50

File tree

3 files changed

+709
-0
lines changed

3 files changed

+709
-0
lines changed

modules/floxisBidAdapter.js

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { registerBidder } from '../src/adapters/bidderFactory.js';
2+
import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
3+
import { ortbConverter } from '../libraries/ortbConverter/converter.js';
4+
import { triggerPixel, mergeDeep } from '../src/utils.js';
5+
6+
const BIDDER_CODE = 'floxis';
7+
const DEFAULT_BID_TTL = 300;
8+
const DEFAULT_CURRENCY = 'USD';
9+
const DEFAULT_NET_REVENUE = true;
10+
const DEFAULT_REGION = 'us-e';
11+
const DEFAULT_PARTNER = BIDDER_CODE;
12+
const PARTNER_REGION_WHITELIST = {
13+
[DEFAULT_PARTNER]: [DEFAULT_REGION],
14+
};
15+
16+
function isAllowedPartnerRegion(partner, region) {
17+
return PARTNER_REGION_WHITELIST[partner]?.includes(region) || false;
18+
}
19+
20+
function getEndpointUrl(seat, region, partner) {
21+
if (!isAllowedPartnerRegion(partner, region)) return null;
22+
const host = partner === BIDDER_CODE
23+
? `${region}.floxis.tech`
24+
: `${partner}-${region}.floxis.tech`;
25+
return `https://${host}/pbjs?seat=${encodeURIComponent(seat)}`;
26+
}
27+
28+
function normalizeBidParams(params = {}) {
29+
return {
30+
seat: params.seat,
31+
region: params.region ?? DEFAULT_REGION,
32+
partner: params.partner ?? DEFAULT_PARTNER
33+
};
34+
}
35+
36+
const CONVERTER = ortbConverter({
37+
context: {
38+
netRevenue: DEFAULT_NET_REVENUE,
39+
ttl: DEFAULT_BID_TTL,
40+
currency: DEFAULT_CURRENCY
41+
},
42+
imp(buildImp, bidRequest, context) {
43+
const imp = buildImp(bidRequest, context);
44+
imp.secure = bidRequest.ortb2Imp?.secure ?? 1;
45+
46+
let floorInfo;
47+
if (typeof bidRequest.getFloor === 'function') {
48+
try {
49+
floorInfo = bidRequest.getFloor({
50+
currency: DEFAULT_CURRENCY,
51+
mediaType: '*',
52+
size: '*'
53+
});
54+
} catch (e) { }
55+
}
56+
const floor = floorInfo?.floor;
57+
const floorCur = floorInfo?.currency || DEFAULT_CURRENCY;
58+
if (typeof floor === 'number' && !isNaN(floor)) {
59+
imp.bidfloor = floor;
60+
imp.bidfloorcur = floorCur;
61+
}
62+
63+
return imp;
64+
},
65+
request(buildRequest, imps, bidderRequest, context) {
66+
const req = buildRequest(imps, bidderRequest, context);
67+
mergeDeep(req, {
68+
at: 1,
69+
ext: {
70+
prebid: {
71+
adapter: BIDDER_CODE,
72+
version: '$prebid.version$'
73+
}
74+
}
75+
});
76+
return req;
77+
}
78+
});
79+
80+
export const spec = {
81+
code: BIDDER_CODE,
82+
supportedMediaTypes: [BANNER, VIDEO, NATIVE],
83+
84+
isBidRequestValid(bid) {
85+
const params = bid?.params;
86+
if (!params) return false;
87+
const { seat, region, partner } = normalizeBidParams(params);
88+
if (typeof seat !== 'string' || !seat.length) return false;
89+
if (!isAllowedPartnerRegion(partner, region)) return false;
90+
return true;
91+
},
92+
93+
buildRequests(validBidRequests = [], bidderRequest = {}) {
94+
if (!validBidRequests.length) return [];
95+
const filteredBidRequests = validBidRequests.filter((bidRequest) => spec.isBidRequestValid(bidRequest));
96+
if (!filteredBidRequests.length) return [];
97+
98+
const bidRequestsByParams = filteredBidRequests.reduce((groups, bidRequest) => {
99+
const { seat, region, partner } = normalizeBidParams(bidRequest.params);
100+
const key = `${seat}|${region}|${partner}`;
101+
groups[key] = groups[key] || [];
102+
groups[key].push({
103+
...bidRequest,
104+
params: {
105+
...bidRequest.params,
106+
seat,
107+
region,
108+
partner
109+
}
110+
});
111+
return groups;
112+
}, {});
113+
114+
return Object.values(bidRequestsByParams).map((groupedBidRequests) => {
115+
const { seat, region, partner } = groupedBidRequests[0].params;
116+
const url = getEndpointUrl(seat, region, partner);
117+
if (!url) return null;
118+
return {
119+
method: 'POST',
120+
url,
121+
data: CONVERTER.toORTB({ bidRequests: groupedBidRequests, bidderRequest }),
122+
options: {
123+
withCredentials: true,
124+
contentType: 'text/plain'
125+
}
126+
};
127+
}).filter(Boolean);
128+
},
129+
130+
interpretResponse(response, request) {
131+
if (!response?.body || !request?.data) return [];
132+
return CONVERTER.fromORTB({ request: request.data, response: response.body })?.bids || [];
133+
},
134+
135+
getUserSyncs() {
136+
return [];
137+
},
138+
139+
onBidWon(bid) {
140+
if (bid.burl) {
141+
triggerPixel(bid.burl);
142+
}
143+
if (bid.nurl) {
144+
triggerPixel(bid.nurl);
145+
}
146+
}
147+
};
148+
149+
registerBidder(spec);

modules/floxisBidAdapter.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Overview
2+
3+
```
4+
Module Name: Floxis Bidder Adapter
5+
Module Type: Bidder Adapter
6+
Maintainer: admin@floxis.tech
7+
```
8+
9+
# Description
10+
11+
The Floxis Bid Adapter enables integration with the Floxis programmatic advertising platform via Prebid.js. It supports banner, video (instream and outstream), and native formats.
12+
13+
**Key Features:**
14+
- Banner, Video and Native ad support
15+
- OpenRTB 2.x compliant
16+
- Privacy regulation compliance (GDPR, USP, GPP, COPPA)
17+
- Prebid.js Floors Module support
18+
19+
## Supported Media Types
20+
- Banner
21+
- Video
22+
- Native
23+
24+
## Floors Module Support
25+
The Floxis Bid Adapter supports the Prebid.js [Floors Module](https://docs.prebid.org/dev-docs/modules/floors.html). Floor values are automatically included in the OpenRTB request as `imp.bidfloor` and `imp.bidfloorcur`.
26+
27+
## Privacy
28+
Privacy fields (GDPR, USP, GPP, COPPA) are handled by Prebid.js core and automatically included in the OpenRTB request.
29+
30+
## Example Usage
31+
```javascript
32+
pbjs.addAdUnits([
33+
{
34+
code: 'adunit-1',
35+
mediaTypes: { banner: { sizes: [[300, 250]] } },
36+
bids: [{
37+
bidder: 'floxis',
38+
params: {
39+
seat: 'testSeat',
40+
region: 'us-e',
41+
partner: 'floxis'
42+
}
43+
}]
44+
}
45+
]);
46+
```
47+
48+
# Configuration
49+
50+
## Parameters
51+
52+
| Name | Scope | Description | Example | Type |
53+
| --- | --- | --- | --- | --- |
54+
| `seat` | required | Seat identifier | `'testSeat'` | `string` |
55+
| `region` | required | Region identifier for routing | `'us-e'` | `string` |
56+
| `partner` | required | Partner identifier | `'floxis'` | `string` |
57+
58+
## Testing
59+
Unit tests are provided in `test/spec/modules/floxisBidAdapter_spec.js` and cover validation, request building, response interpretation, and bid-won notifications.

0 commit comments

Comments
 (0)