Production-ready guidelines for integrating with the Ad Decision Engine.
Use POST Method for Production
Recommendation: Always use POST method in production.
Why:
- Handles larger requests (no URL length limits)
- Better for multiple impressions
- Cleaner implementation
- Better security (params not in URL)
Example:
// Recommended
fetch('https://csr.onet.pl/7012768/bid', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(bidRequest)
});
// Not recommended for production
fetch(`https://csr.onet.pl/7012768/bid?data=${encoded}`);Generate Unique Request IDs
Recommendation: Include timestamp and random component in request IDs.
Why: Enables request tracing, debugging, and deduplication.
Examples:
// Good: Timestamp + random
const requestId = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
// Example: "1734523456789-k3x9m2p"
// Good: UUID
const requestId = crypto.randomUUID();
// Example: "550e8400-e29b-41d4-a716-446655440000"
// Avoid: Sequential numbers
const requestId = "1"; // Bad - no uniqueness guaranteeBatch Multiple Impressions
Recommendation: Request multiple ad slots in a single API call.
Why: Reduces latency, improves performance, fewer HTTP connections.
Example:
{
"id": "batch-request",
"imp": [
{"id": "header", "banner": {"format": [{"w": 728, "h": 90}]}},
{"id": "sidebar", "banner": {"format": [{"w": 300, "h": 250}]}},
{"id": "footer", "banner": {"format": [{"w": 728, "h": 90}]}}
],
"site": {
"id": "HOMEPAGE",
"domain": "example.com"
}
}Performance gain: 3 separate requests → 1 request = 67% fewer HTTP calls.
Implement Retry Logic
Recommendation: Retry on server errors (5xx) and timeouts.
Why: Temporary failures can succeed on retry.
Rules:
- ✅ Retry: 500, 502, 503, 504 errors
- ❌ Don't retry: 400, 401, 403, 404 errors
- ✅ Retry: Network timeouts
- ❌ Don't retry: 204 (No bids)
Example:
async function requestBidWithRetry(bidRequest, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch('https://csr.onet.pl/7012768/bid', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(bidRequest)
});
// Don't retry client errors
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
throw new Error(`Client error: ${response.status}`);
}
// Success or no bids
if (response.ok || response.status === 204) {
return response;
}
// Retry on server errors
if (attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
await sleep(delay);
continue;
}
throw new Error(`Max retries exceeded`);
} catch (error) {
if (attempt === maxRetries - 1) throw error;
await sleep(Math.pow(2, attempt) * 1000);
}
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}Backoff schedule: 1s → 2s → 4s
Handle No Bid Responses
Recommendation: Always have fallback content for 204 responses.
Why: No bids can happen anytime (budget exhausted, no matching campaigns).
Example:
async function displayAd(bidRequest) {
const response = await fetch('https://csr.onet.pl/7012768/bid', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(bidRequest)
});
if (response.status === 204) {
// No bids available - show fallback
showHouseAd();
return;
}
const data = await response.json();
renderBid(data);
}
function showHouseAd() {
document.getElementById('ad-container').innerHTML = `
<a href="/advertise">
<img src="/images/house-ad.jpg" alt="Advertise with us" />
</a>
`;
}Respect Privacy Regulations
Recommendation: Always include GDPR and DSA flags for EU users.
Why: Legal compliance, user trust.
Example:
{
"user": {
"ext": {
"npa": false
}
},
"regs": {
"gdpr": 1,
"ext": {
"dsa": 1
}
}
}When to set npa: true:
- User opted out of personalization
- No consent for personalized ads
- Privacy mode enabled
- Children's content (COPPA)
DSA compliance:
- Required for EU users
- Response includes
ext.dsaurl - Display link near ad: "Why this ad?"
Fire Impression Tracking
Recommendation: Always fire impression tracking URL when ad is displayed.
Why: Required for billing, campaign reporting, analytics.
Critical: Without firing tracking, impressions won't be counted and you won't receive credit.
Provide Site Context
Recommendation: Always include page URL and keywords when available.
Why: Improves targeting, increases bid prices, better ad relevance.
Example:
{
"site": {
"id": "TECH_SECTION",
"domain": "example.com",
"page": "https://example.com/articles/latest-smartphone-review",
"ext": {
"area": "TECH",
"kwrd": "smartphone+review+technology+gadgets"
}
}
}Impact: Up to 30% higher CPMs with good contextual data.
Include User Identifiers
Recommendation: Send user IDs when available (with consent).
Why: Enables frequency capping, better targeting, personalization.
Example:
{
"user": {
"ext": {
"ids": {
"lu": "202408221036415499301131",
"aid": "hashed-email-or-user-id"
}
}
}
}Best practices:
- Always hash logged-in user IDs before sending
- Store
luin first-party cookie - Don't send if user opted out
- Use consistent format across requests
Set Security Flag
Recommendation: Always require HTTPS creatives for secure sites.
Why: Prevents mixed content warnings, better security.
Example:
{
"imp": [{
"id": "1",
"secure": 1,
"banner": {
"format": [{"w": 300, "h": 250}]
}
}]
}Rule: If your site is HTTPS, always set secure: 1.
Support Multiple Ad Sizes
Recommendation: Provide multiple size options for better fill rates.
Why: More sizes = more ad inventory matches = higher fill rates.
Example:
{
"imp": [{
"id": "flexible-banner",
"banner": {
"format": [
{"w": 728, "h": 90},
{"w": 970, "h": 90},
{"w": 970, "h": 250}
]
}
}]
}Impact: 15-25% higher fill rates with flexible sizing.
Cache Bids Appropriately
Recommendation: Cache bids for short periods only.
Why: Fresh bids = better prices, current campaigns.
Rules:
- ✅ Cache: 30-60 seconds max
- ❌ Don't cache: Longer than 5 minutes
- ✅ Cache key: Include page URL, user ID, timestamp bucket
Enable Compression
Recommendation: Use gzip/deflate compression for requests and responses.
Why: Reduces bandwidth, faster transfers.
Example:
curl -X POST "https://csr.onet.pl/7012768/bid" \
-H "Content-Type: application/json" \
-H "Accept-Encoding: gzip, deflate" \
--compressedfetch('https://csr.onet.pl/7012768/bid', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept-Encoding': 'gzip, deflate'
},
body: JSON.stringify(bidRequest)
});Impact: 60-80% smaller response size.
Validate Requests Before Sending
Recommendation: Validate request structure before sending.
Why: Catch errors early, reduce 400 errors, better performance.
Validation checklist:
function validateBidRequest(request) {
// Required fields
if (!request.id) throw new Error('Missing id');
if (!request.imp || request.imp.length === 0) throw new Error('Missing impressions');
if (!request.site) throw new Error('Missing site');
// Impression validation
request.imp.forEach((imp, i) => {
if (!imp.id) throw new Error(`Impression ${i} missing id`);
if (!imp.banner && !imp.video && !imp.native) {
throw new Error(`Impression ${i} missing format`);
}
});
// Site validation
if (!request.site.id) throw new Error('Missing site.id');
if (!request.site.domain) throw new Error('Missing site.domain');
return true;
}
// Use before sending
try {
validateBidRequest(bidRequest);
const response = await fetch('...', {body: JSON.stringify(bidRequest)});
} catch (error) {
console.error('Invalid request:', error);
}Use Connection Pooling
Recommendation: Reuse HTTP connections (keep-alive).
Why: Reduces connection overhead, faster requests.
Node.js example:
const https = require('https');
const agent = new https.Agent({
keepAlive: true,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000
});
fetch('https://csr.onet.pl/7012768/bid', {
method: 'POST',
agent: agent,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(bidRequest)
});Impact: 20-30% faster subsequent requests.
Test with Demo Network
Recommendation: Use demo network ID for testing.
Demo Network ID: 7012768
Why: Always has active campaigns, safe for testing.
Example:
const NETWORK_ID = process.env.NODE_ENV === 'production'
? '7890123' // Production network
: '7012768'; // Demo network
const url = `https://csr.onet.pl/${NETWORK_ID}/bid`;