Building Bid Requests
This page is specific to the Headless workflow. The React Components, React Hooks, and Web Components workflows build and send bid requests for you internally — see Banners, Videos, Carousels, and Dynamic Zones.
Once the SDK is initialized, you build a bid request, send it, and parse the response. A single bid request can cover every impression opportunity on the page at once — multiple zones, multiple creative types, multiple sizes — so this is the standard way to request ads rather than making a separate request per placement.
Full example
/* const ads = await LoadSurfAdsCoreHeadless({ ... }) — see Initialization */
// 1. Build the request with every impression opportunity on the page
const request = ads.startRequest('your-zone-id')
.withImp('banner-zone-id')
.andBanner(4, 1)
.andBanner(8, 1)
.withImp('carousel-zone-id')
.andProductCards(ads.defaultNative())
.build();
const bidsRes = await ads.requestBids(request);
if (!bidsRes.ok) {
console.error(bidsRes.error);
return;
}
// 2. Parse all creatives from the bid response
const responsesRes = await ads.buildAllResponsesCore(bidsRes.value);
if (!responsesRes.ok) {
console.error(responsesRes.error);
return;
}
// 3. Handle each creative type
for (const creative of responsesRes.value) {
if (creative.type === 'banner') {
yourHandleBannerFunction(creative.adm);
} else if (creative.type === 'video') {
yourHandleVideoFunction(creative.video);
} else if (creative.type === 'simpleCarousel') {
yourHandleCarouselFunction(creative.products);
}
}
Step by step
1. Build the request
Each impression opportunity gets its own .withImp() call, chained one after another on the same request builder. Declare the creative type for an impression with the corresponding .and*() call, then finish with .build().
const request = ads.startRequest('your-zone-id')
.withImp('banner-zone-id')
.andBanner(4, 1)
.withImp('carousel-zone-id')
.andProductCards(ads.defaultNative())
.build();
You can also pass categories and keywords for targeting before calling .withImp():
const request = ads.startRequest('your-zone-id')
.withSurfCategory(['edibles'])
.withKeywords(['organic', 'sale'])
.withImp('banner-zone-id')
.andBanner(4, 1)
.withImp('carousel-zone-id')
.andProductCards(ads.defaultNative())
.build();
Multiple sizes on one impression
Call .andBanner() (or any other .and*() method) more than once on the same impression. The bidder returns whichever size it can fill.
const request = ads.startRequest('your-zone-id')
.withImp('banner-zone-id')
.andBanner(4, 1)
.andBanner(8, 1)
.withImp('carousel-zone-id')
.andProductCards(ads.defaultNative())
.build();
Mixed creative types on one impression
You can also mix creative types on the same impression — for example, asking for both a banner and a product card slot on the same imp:
const request = ads.startRequest('your-zone-id')
.withImp('your-zone-id')
.andBanner(8, 1)
.andProductCards(ads.defaultNative())
.build();
These patterns compose freely: each .withImp() in a request can independently ask for multiple sizes, mixed creative types, or both.
2. Send the request
Pass the built request to requestBids:
const bidsRes = await ads.requestBids(request);
if (!bidsRes.ok) {
console.error(bidsRes.error);
return;
}
3. Parse the creatives
buildAllResponsesCore takes the full bid response and inspects each bid to determine its creative type — banner, video, or native product card. It returns a single, unified array of typed creative objects no matter how many impressions or creative types the request asked for.
const responsesRes = await ads.buildAllResponsesCore(bidsRes.value);
if (!responsesRes.ok) {
console.error(responsesRes.error);
return;
}
4. Handle each type
Each creative in the response has a type field you can use to branch your handling. Use it as a discriminator:
for (const creative of responsesRes.value) {
if (creative.type === 'banner') {
yourHandleBannerFunction(creative.adm);
} else if (creative.type === 'video') {
yourHandleVideoFunction(creative.video);
} else if (creative.type === 'simpleCarousel') {
yourHandleCarouselFunction(creative.products);
}
}
type | Shape | Key field |
|---|---|---|
'banner' | IBuiltBannerResponse | adm — the banner HTML |
'video' | IBuiltVideoCore | video — the VAST XML string |
'simpleCarousel' | ISimpleBuiltCarousel | products — array of product cards |
For the request options and response fields specific to each creative type — banner dimensions and win notifications, carousel product tracking, video VAST details — see Banners, Carousels, and Videos.