Requesting ads
As product ads and banners are generated on the same endpoint, if your placement's context is the same, you are able to request product ads in the same request as banners.
The number of products ads you may receive is configured by defining the maxNumberOfAds
parameter. The number of banner ads you may receive can be configured with the maxNumberOfAds
property per unique slotId
All banner ad requests require the contentStandardId
and the bannerSlots
you are requesting ads for. In addition, your banner call should include the context's customerId
,sessionId
,placement
, and catalogId
.
You might notice some changes here!
We're introducing a change to how you request banner ads from CitrusAd. If you are already integrated, you might request with a property called
bannerSlotIds
. We've superseded this with our newbannerSlots
capability. If you'd like to review how to request ads with thebannerSlotIds
property, please navigate to the bottom of this page.This
bannerSlots
capability was rolled out in September, 2022.
Search placements
Search placements are typically the easiest to request. They require a searchTerm
to be specified in the request, like the example below:
POST $BASE_URL/v1/ads/generate HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic <API_KEY>
{
"customerId": "wertg5432a",
"sessionId": "ec9-4e07-881d-3e9",
"dtmCookieId": "AAAF8xLBTA968AB6TOthAAAAAAE",
"placement": "search",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"searchTerm": "chocolate",
"options": {
"filterMode": "AndOr"
},
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"bannerSlots": [
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 1
},
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 2
}
],
"maxNumberOfAds": 3
}
Category placements
Category placements require productFilters
to be specified in the request. Below is an example of where you would send the category filters:
POST $BASE_URL/v1/ads/generate HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic <API_KEY>
{
"customerId": "wertg5432a",
"sessionId": "ec9-4e07-881d-3e9",
"dtmCookieId": "AAAF8xLBTA968AB6TOthAAAAAAE",
"placement": "category",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"productFilters": [
["category:Cupboard/Snacks"]
],
"options": {
"filterMode": "AndOr"
},
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"bannerSlots": [
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 1
},
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 2
}
],
"maxNumberOfAds": 3
}
As additional categories are perused, you should update your API call accordingly.
Cross-sell category placements
Cross-sell category placements have a very similar request to category placements. You will want to specify the exact category you are requesting ads for. This is typically the page you are on. Specify the category in the productFilters
of the request. The example below shows where you would send the category filters:
POST $BASE_URL/v1/ads/generate HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic <API_KEY>
{
"customerId": "wertg5432a",
"sessionId": "ec9-4e07-881d-3e9",
"dtmCookieId": "AAAF8xLBTA968AB6TOthAAAAAAE",
"placement": "category-cross-sell",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"productFilters": [
["category:Cupboard/Snacks"]
],
"options": {
"filterMode": "AndOr"
},
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"bannerSlots": [
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 1
},
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 2
}
],
"maxNumberOfAds": 3
}
As additional categories are perused, you need to update your API call accordingly.
Merging organic and cross-sell category targeting?
If you're looking to merge an organic and cross-sell category ad request into a single placement, you will need to implement merging and delivery logic to your customers. This is the integator's responsibility, though CitrusAd are happy to be consulted.
In general, we advise that you show organic category ads, and position and category cross-sell advertisements after the organic placements.
Broad match placements
Broad placements such as home or checkout pages do not require any productFilters
to be specified in the request. Any filters the retailer would like to specify (on offer, new, etc) can be specified in the productFilters
to ensure CitrusAd only serve ads within the requirements, like the example below:
POST $BASE_URL/v1/ads/generate HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic <API_KEY>
{
"customerId": "wertg5432a",
"sessionId": "ec9-4e07-881d-3e9",
"dtmCookieId": "AAAF8xLBTA968AB6TOthAAAAAAE",
"placement": "home",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"productFilters": [
[]
],
"options": {
"filterMode": "AndOr"
},
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"bannerSlots": [
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 1
},
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 2
}
],
"maxNumberOfAds": 3
}
Request enhancements
We advise you to consider the below enhancements to improve your user experience.
Filtered searches
If your customer filters their search, you can extend your context to provide productFilters
. Below is an example where the customer is filtering by the category "Cupboard" and the dietary restriction "Gluten-free". This same principle can be applied to any category or broad match placement.
POST $BASE_URL/v1/ads/generate HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic <API_KEY>
{
"customerId": "wertg5432a",
"sessionId": "ec9-4e07-881d-3e9",
"dtmCookieId": "AAAF8xLBTA968AB6TOthAAAAAAE",
"placement": "search",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"searchTerm": "chocolate",
"productFilters": [
["category:Cupboard"],["dietary:Gluten-free"]
],
"options": {
"filterMode": "AndOr"
},
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"bannerSlots": [
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 1
},
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 2
}
],
"maxNumberOfAds": 3
}
Filtering by location
If you are synchronising location filters in your catalog, you can extend your context to provide the customer's store location in the productFilters
, like the example below:
POST $BASE_URL/v1/ads/generate HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic <API_KEY>
{
"customerId": "wertg5432a",
"sessionId": "ec9-4e07-881d-3e9",
"dtmCookieId": "AAAF8xLBTA968AB6TOthAAAAAAE",
"placement": "search",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"searchTerm": "chocolate",
"productFilters": [
["category:Cupboard"],["dietary:Gluten-free"],["location:Westenbury"]
],
"options": {
"filterMode": "AndOr"
},
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"bannerSlots": [
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 1
},
{
"slotId": "<SLOT_ID>",
"maxNumberOfAds": 2
}
],
"maxNumberOfAds": 3
}
Using the bannerSlotIds parameter (legacy)
If you're already integrated, you might be requesting ads with bannerSlotIds
instead of bannerSlots
. This is an array of strings wherein you would specify the banner slots you require ads for. We've improved our capability so that you can request more than one ad for the same banner slot. If you are interested, you will need to enhance your integration to the bannerSlots
method outlined above.
POST $BASE_URL/v1/ads/generate HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic <API_KEY>
{
"customerId": "wertg5432a",
"sessionId": "ec9-4e07-881d-3e9",
"dtmCookieId": "AAAF8xLBTA968AB6TOthAAAAAAE",
"placement": "search",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"searchTerm": "chocolate",
"productFilters": [
["category:Cupboard"],["dietary:Gluten-free"],["location:Westenbury"]
],
"options": {
"filterMode": "AndOr"
},
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"bannerSlotIds": [
"<SLOT_ID>","<SLOT_ID>"
],
"maxNumberOfAds": 3
}
The banner ad response
All responses follow the same JSON format. If you are requesting product ads, the ads
array will be populated as per the example below. Banners populate the banners
array, so content is only returned for banner slots with ads.
{
"ads": [
{
"id": "display__QqHaKRrKlFm1Wxr9c_DXJN4HSE3NzMzNjM2",
"gtin": "7733636",
"discount": {
"amount": 0,
"minPrice": 0,
"maxPerCustomer": 0
},
"expiry": "2021-05-12T04:17:50.400902957Z",
"position": 1
},
{
"id": "display_NzsHqP0_iQedlo9VnrO2vqkwi_k3NzMzNjI4",
"gtin": "7733628",
"discount": {
"amount": 0,
"minPrice": 0,
"maxPerCustomer": 0
},
"expiry": "2021-05-12T04:17:50.400908257Z",
"position": 2
}
],
"banners": [
{
"id": "banner_XeemTeq59HapGSp4vccOYfBq_yvc3zMzNjM2",
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"slotId": "<SLOT_ID>",
"imageUrl": "https://cdn.flavedo.io/s/-oW-C3cEViSSO2krWkwOBUXOhvUdhHOySx-YQLGZ1lA=",
"linkUrl": "https://www.retailer.com/link",
"altText": "Your local ice cream",
"text": "",
"gtins": [
"7733628",
"7714107",
"7163379",
"7733636",
"7733657"
],
"expiry": "2021-05-17T01:49:17.75503253Z",
"tags": {},
"position": 1
},
{
"id": "banner_A0KA6mNmFs6sZPb_FvwWe5k6x6c3NzMzNjM3",
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"slotId": "<SLOT_ID>",
"imageUrl": "https://cdn.flavedo.io/s/-oW-dfsgrerWkwOBUXOhvUdhHOySx-YQLreGZ1lw=",
"linkUrl": "https://www.retailer.com/link",
"altText": "Advertisement for pet food.",
"text": "",
"gtins": [
"16309011",
"57312011",
"65250011"
],
"expiry": "2021-05-17T01:49:17.75503253Z",
"tags": {},
"position": 2
}
],
"products": [],
"memoryToken":"85ykKVv-luDHMWLZx2d6xcPq6sF7CgkJCSJDb3VudGVyIjogIjIiLAoJCQkiQWRzIjogWwoJCQkJImRpc3BsYXlfV05VV0NwQkRKMUpKNm5wdVZSVExvOU40TUxzNE1UWTBOemt5TWc9PSIsCgkJCQkiZGlzcGxheV9MME5NUHRxNmdCcVFvREJOd3J0dE9UTGJoWk0xTVRFeU9UYzRPUT09IiwKCQkJCSJkaXNwbGF5XzlCcEpmdUpaWk9VXzgyaWpFM3VCczgxd3VVczRNekkwTnpVeE5nPT0iLAoJCQkJImRpc3BsYXlfcW1VU1p4TkpMQ0lqeWQwdTFJRDk0RmxVZ0pnNE16STBOelV4Tnc9PSIsCgkJCQkiZGlzcGxheV9oeHlFZktCUnRrNWlxMThMQzE1SDJHcEN3QjgxTVRFeU9UYzVNQT09IiwKCQkJCSJkaXNwbGF5X1NkcjFEcU5aUEFtcGh0Q1FIUndoYUxFT1B0RXhNamsxT1RJNE5BPT0iLAoJCQkJImRpc3BsYXlfeVlSai1qV2Ntc2ozNzhrel9PMm0yOVlwTjhJeE5EazNPRE00TXc9PSIsCgkJCQkiZGlzcGxheV9Xbm9NZGZuLTRTVmhxcF9xQzVvLWxoT0paNm8xTkRJeE1UUTROdz09IgoJCQldLAoJCQkiVFRMIjogMTYyODk4NTYwMAoJCX0="
}
The id
field is your Ad ID used in impression and click reports. Please refer to the reference for more information on each string.
Marketplace sellerId
If onboarding marketplace sellers, you may see an additional sellerId
per ad in the response. This will only appear if the team that owns the campaign being served has a seller ID configured in the UI. The example below shows one ad with a sellerId, one without.
{
"ads": [
{
"id": "display_QqHaKRrKlFm1Wxr9c_DXJN4HSE3NzMzNjM2",
"gtin": "7733636",
"discount": {
"amount": 0,
"minPrice": 0,
"maxPerCustomer": 0
},
"expiry": "2021-05-12T04:17:50.400902957Z",
"position": 1
},
{
"id": "display_NzsHqP0_iQedlo9VnrO2vqkwi_k3NzMzNjI4",
"gtin": "7733628",
"sellerId": "2834-ascre-2wcr4",
"discount": {
"amount": 0,
"minPrice": 0,
"maxPerCustomer": 0
},
"expiry": "2021-05-12T04:17:50.400908257Z",
"position": 2
}
],
"banners": [
{
"id": "banner_XeemTeq59HapGSp4vccOYfBq_yvc3zMzNjM2",
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"slotId": "<SLOT_ID>",
"sellerId": "43d-w4-2wcr4",
"imageUrl": "https://cdn.flavedo.io/s/-oW-C3cEViSSO2krWkwOBUXOhvUdhHOySx-YQLGZ1lA=",
"linkUrl": "https://www.retailer.com/link",
"altText": "Your local ice cream",
"text": "",
"gtins": [
"7733628",
"7714107",
"7163379",
"7733636",
"7733657"
],
"expiry": "2021-05-17T01:49:17.75503253Z",
"tags": {},
"position": 1
},
{
"id": "banner_A0KA6mNmFs6sZPb_FvwWe5k6x6c3NzMzNjM3",
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"slotId": "<SLOT_ID>",
"imageUrl": "https://cdn.flavedo.io/s/-oW-dfsgrerWkwOBUXOhvUdhHOySx-YQLreGZ1lw=",
"linkUrl": "https://www.retailer.com/link",
"altText": "Advertisement for pet food.",
"text": "",
"gtins": [
"16309011",
"57312011",
"65250011"
],
"expiry": "2021-05-17T01:49:17.75503253Z",
"tags": {},
"position": 2
}
],
"products": [],
"memoryToken":"85ykKVv-luDHMWLZx2d6xcPq6sF7CgkJCSJDb3VudGVyIjogIjIiLAoJCQkiQWRzIjogWwoJCQkJImRpc3BsYXlfV05VV0NwQkRKMUpKNm5wdVZSVExvOU40TUxzNE1UWTBOemt5TWc9PSIsCgkJCQkiZGlzcGxheV9MME5NUHRxNmdCcVFvREJOd3J0dE9UTGJoWk0xTVRFeU9UYzRPUT09IiwKCQkJCSJkaXNwbGF5XzlCcEpmdUpaWk9VXzgyaWpFM3VCczgxd3VVczRNekkwTnpVeE5nPT0iLAoJCQkJImRpc3BsYXlfcW1VU1p4TkpMQ0lqeWQwdTFJRDk0RmxVZ0pnNE16STBOelV4Tnc9PSIsCgkJCQkiZGlzcGxheV9oeHlFZktCUnRrNWlxMThMQzE1SDJHcEN3QjgxTVRFeU9UYzVNQT09IiwKCQkJCSJkaXNwbGF5X1NkcjFEcU5aUEFtcGh0Q1FIUndoYUxFT1B0RXhNamsxT1RJNE5BPT0iLAoJCQkJImRpc3BsYXlfeVlSai1qV2Ntc2ozNzhrel9PMm0yOVlwTjhJeE5EazNPRE00TXc9PSIsCgkJCQkiZGlzcGxheV9Xbm9NZGZuLTRTVmhxcF9xQzVvLWxoT0paNm8xTkRJeE1UUTROdz09IgoJCQldLAoJCQkiVFRMIjogMTYyODk4NTYwMAoJCX0="
}
If you’re unsure about the strings in this section, please visit the Reference page.
Third-party tracking tags
For banner ads, CitrusAd supports the passing of third-party tracking tags to the retailer. These tags are used by advertisers to verify their performance by a trusted third party.
CitrusAd support the tracking tags below:
- DoubleVerify
- DCM Click
- DCM Impression
- IAS
If a campaign has a tracking tag configured, it will present as the relevant field in the tags
object below. Please note, if a campaign does not have a tag configured, the tags
object will remain empty.
{
"ads": [],
"banners": [
{
"id": "banner_XeemTeq59HapGSp4vccOYfBq_yvc3zMzNjM2",
"contentStandardId": "fec2ab89-7a29-42b5-b58a-5675688b52d9",
"slotId": "<SLOT_ID>",
"imageUrl": "https://cdn.flavedo.io/s/-oW-C3cEViSSO2krWkwOBUXOhvUdhHOySx-YQLGZ1lA=",
"linkUrl": "https://www.retailer.com/link",
"altText": "Your local ice cream",
"text": "",
"gtins": [
"7733628",
"7714107",
"7163379",
"7733636",
"7733657"
],
"expiry": "2021-05-17T01:49:17.75503253Z",
"tags": {
"dv": "<script src=\"https://cdn.doubleverify.com/dvtp_src.js?ctx=919421&cmp=1074060503&sid=1073907024&plc=1075810393&adsrv=115&btreg=&btadsrv=&crt=&tagtype=&dvtagver=6.1.src\" type=\"text/javascript\"></script>",
"dcmClick": "<script ..../>",
"dcmImpression": "<script.... />",
"ias": "<script.... />" }
}
],
"products": [],
"memoryToken":"85ykKVv-luDHMWLZx2d6xcPq6sF7CgkJCSJDb3VudGVyIjogIjIiLAoJCQkiQWRzIjogWwoJCQkJImRpc3BsYXlfV05VV0NwQkRKMUpKNm5wdVZSVExvOU40TUxzNE1UWTBOemt5TWc9PSIsCgkJCQkiZGlzcGxheV9MME5NUHRxNmdCcVFvREJOd3J0dE9UTGJoWk0xTVRFeU9UYzRPUT09IiwKCQkJCSJkaXNwbGF5XzlCcEpmdUpaWk9VXzgyaWpFM3VCczgxd3VVczRNekkwTnpVeE5nPT0iLAoJCQkJImRpc3BsYXlfcW1VU1p4TkpMQ0lqeWQwdTFJRDk0RmxVZ0pnNE16STBOelV4Tnc9PSIsCgkJCQkiZGlzcGxheV9oeHlFZktCUnRrNWlxMThMQzE1SDJHcEN3QjgxTVRFeU9UYzVNQT09IiwKCQkJCSJkaXNwbGF5X1NkcjFEcU5aUEFtcGh0Q1FIUndoYUxFT1B0RXhNamsxT1RJNE5BPT0iLAoJCQkJImRpc3BsYXlfeVlSai1qV2Ntc2ozNzhrel9PMm0yOVlwTjhJeE5EazNPRE00TXc9PSIsCgkJCQkiZGlzcGxheV9Xbm9NZGZuLTRTVmhxcF9xQzVvLWxoT0paNm8xTkRJeE1UUTROdz09IgoJCQldLAoJCQkiVFRMIjogMTYyODk4NTYwMAoJCX0="
}
As CitrusAd is a server-to-server integration, third-party tracking tags require additional development by the retailer. Contact your Technical Account Manager if you are looking to utilise this feature.