Integration Checklist

This page is intended as a ‘Quick Start’ guide and overview of how CitrusAd can be integrated with your system. This will help to explain the initial integration steps and how to achieve them.

Integration Steps

If you are used to an advertising strategy which uses content injection based off a simple tag on your website, our integration will seem quite foreign - however each of the steps to go live are not complex. The integration will be more involved than simply adding a tag to a page, but the results will be exponentially more valuable to both the retailer and the supplier; as well as being more scalable in the long term.

The steps for an MVP integration with CitrusAd are:

  • Create Catalog

  • Upload Product Data to CitrusAdd

  • Request Product Ads when loading a page

  • Display selected ads when loading a page

  • Create Banner Ad Content Standard

  • Request and Display Banner ads when loading page

  • Send impressions and clicks to CitrusAd for reporting

  • Send order data to CitrusAD for reporting

Step 1: Create Catalog

The first step to integrating CitrusAd is to create a catalog that you can upload your products to. This can be done with a simple one-time API call.

If you are wishing to segment your catalogs into different stores, territories, or countries, you may need to create multiple catalogs.

More information can be found here:

An example request for creating a catalog can be seen below:

HTTP
cURL
HTTP
POST $BASE_URL/v1/catalogs?teamId=44d25f70-b520-40de-8329-0781a9ebcdc8 HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic 4ww25f70-b52s-40de-8f29-07b139b5cdc8
{
"catalogs": [
{
"teamId": "4ww25f70-b52s-40de-8f29-07b139b5cdc8",
"name": "Retailer A Catalog"
}
]
}
cURL
curl -iX POST "$BASE_URL/v1/catalogs?teamId=44d25f70-b520-40de-8329-0781a9ebcdc8" \
-H "accept: application/json" \
-H "content-type: application/json" \
-H "Authorization: 4ww25f70-b52s-40de-8f29-07b139b5cdc8" \
-d \
'{
"catalogs": [
{
"teamId": "4ww25f70-b52s-40de-8f29-07b139b5cdc8",
"name": "Retailer Catalog"
}
]
}'

Step 2: Upload product data to CitrusAd

To return product ads, CitrusAd needs to know what products are in stock. Regular product syncing enables CitrusAd to maintain track of all products in an integrator's catalog. Each product's prices and product codes, as well as stock levels and category information are needed to ensure ads remain relevant.

There are two different ways you can upload your catalog to us. Which way you choose is dependant on the existing capabilities and architecture of your system. CitrusAd recommend syncing data via file. It is easier to troubleshoot and resolve issues. You can view the pros and cons of each way on the Syncing Data page:

Option 1: Upload via API

HTTP
cURL
HTTP
POST $BASE_URL/v1/catalog-products?teamId=e8158f9b-bbb9-49fb-93fe-3ad481ca8450 HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic 4ww25f70-b52s-40de-8f29-07b139b5cdc8
{
"catalogProducts": [
{
"teamId": "e8158f9b-bbb9-49fb-93fe-3ad481ca8450",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"gtin": "23556578965543",
"inventory": 50,
"price": "19.99",
"categoryHierarchy": [
"Health&Beauty", "Cosmetics", "Foundation&Powders", "Foundation"
],
"groups": [
"Cosmetics", "Foundations", "Covergirl", "Natural", "Lasting", "Dry Skin", "Beige"
],
"tags": [
"Natural", "Lasting", "Dry Skin", "Beige"
],
"filters": [
"imageurl:https://your.image.host.com/image.jpg","name:Covergirl Clean 120 Creamy Natural Liquid Foundation30mL","Brand:Covergirl","Category:11753","category:Health&Beauty","category:Grocery","Special_Flag:0"
],
"profit": "1.50"
}
]
}
cURL
curl -iX POST "$BASE_URL/v1/catalog-products?teamId=e8158f9b-bbb9-49fb-93fe-3ad481ca8450" \
-H "accept: application/json" \
-H "content-type: application/json" \
-H "Authorization: Basic 4ww25f70-b52s-40de-8f29-07b139b5cdc8" \
-d \
'{
"catalogProducts": [
{
"teamId": "e8158f9b-bbb9-49fb-93fe-3ad481ca8450",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"gtin": "23556578965543",
"inventory": 50,
"price": "19.99",
"categoryHierarchy": [
"Health&Beauty", "Cosmetics", "Foundation&Powders", "Foundation"
],
"groups": [
"Cosmetics", "Foundations", "Covergirl", "Natural", "Lasting", "Dry Skin", "Beige"
],
"tags": [
"Natural", "Lasting", "Dry Skin", "Beige"
],
"filters": [
"imageurl:https://your.image.host.com/image.jpg","name:Covergirl Clean 120 Creamy Natural Liquid Foundation30mL","Brand:Covergirl","Category:11753","category:Health&Beauty","category:Grocery","Special_Flag:0"
],
"profit": "1.50"
}
]
}'

This option allows you to sync up your catalog to us via an API call. This means that your back end is pushing each product to us individually to store (although you can do these in batches and don’t actually have to upload each product one at a time).

If you are looking to upload via API, see:

Option 2: Upload via File

The other option for uploading your catalog is to create a catalog file that we can download off your servers. For file catalogs, we support TSV (Tab Separated Values) and XML file formats. Once you have created the catalog file and given us access to download the file, we will store it on our servers and be able to reference it for ad generation.

An example with a heading row and a data row in a TSV file:

product_code

inventory

category_hierachy

filter:category

filter:brand_name

80591101

20

["department:spirits", "productName:Green Fairy Absinth Gift Pack 500mL", "varietal:absinthe", "webcountryoforigin:czech-republic"]

absinthe

green-fairy

Example XML Document Snippet:

<rss>
<item>
<id>80591011</id>
<title>Melissa &amp; Doug Dinosaur Stamp Set, 4yrs+</title>
<description>Imagine a rugged landscape littered with volcanoes, and full of dinosaurs roaming around</description>
<image_link>https://www.retailer.com/productImages/image1.jpg</image_link>
<price>&pound;9.99</price>
<product_type>Food Cupboard</product_type>
<availability>10</availability>
</item>
<item>
<id>87086011</id>
<title>Waitrose Splits Strawberry Ice Lollies</title>
<description>Strawberry splits; Suitable for vegetarians. Strawberry splits vanilla flavoured ice cream with a fruity strawberry ice coating. Our fundamental belief is that few things in life are more important than the food you buy. Good quality is essential.</description>
<image_link>https://www.retailer.com/productImages/image2.jpg</image_link>
<price>&pound;1.25</price>
<product_type>Frozen Ice Cream Ice Cream Lollies</product_type>
<availability>20</availability>
<brand>Waitrose</brand>
</item>
<rss>

If you are looking to upload via API, see:

Step 3 Requesting product ads when loading a page

There are many different places in which you can be requesting ads, including category pages, search term results pages, the homepage, specials pages etc. Below we will use a simple ‘search term result’ page context. Context is an important part of ad generation as it gives us valuable information about the customer and the page they are on.

This is an example request for an ad on a search term results page:

HTTP
cURL
HTTP
POST $BASE_URL/v1/ads/generate?teamId=44d25f70-b520-40de-8329-0781a9ebcdc8 HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic 4ww25f70-b52s-40de-8f29-07b139b5cdc8
{
"pageType": "Search",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"searchTerm": "Wine",
"productFilters": [
["category:RedWine", "category:Shiraz"]
],
"maxNumberOfAds": 3
}
cURL
curl -iX POST "$BASE_URL/v1/ads/generate?teamId=44d25f70-b520-40de-8329-0781a9ebcdc8" \
-H "accept: application/json" \
-H "content-type: application/json" \
-H "Authorization: Basic 4ww25f70-b52s-40de-8f29-07b139b5cdc8" \
-d \
'{
"pageType": "Search",
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"searchTerm": "Wine",
"productFilters": [
["category:RedWine", "category:Shiraz"]
],
"maxNumberOfAds": 3
}'

As you can see from the above request, only basic information is required for us to serve ads; although the more information you can give us in the context, the more targeted our relevancy algorithm can be in returning ads.

This is an example returned object from an ad request:

HTTP
cURL
HTTP
HTTP/2 200
{
"ads": [
{
"id": "display_ZFwfo0Mi2AhFBxUBHpXnICvV2j8zNTcxNzExUA==",
"gtin": "3571711P",
"discount": {
"amount": 0,
"minPrice": 0,
"maxPerCustomer": 0
},
"expiry": "2019-12-10T01:51:07.936105529Z"
},
{
"id": "display_VpFfnPOnaG4MZh43ckQjufmGAzwzNTcxOTkyUA==",
"gtin": "3571992P",
"discount": {
"amount": 0,
"minPrice": 0,
"maxPerCustomer": 0
},
"expiry": "2019-12-10T01:51:07.936111787Z"
},
{
"id": "display_vRHRnkTXbbssVwiem8jDrmOp2FM2Mzg3NTkyUA==",
"gtin": "6387592P",
"discount": {
"amount": 0,
"minPrice": 0,
"maxPerCustomer": 0
},
"expiry": "2019-12-10T01:51:07.936117921Z"
},
],
"banners": [],
"products": []
}
cURL
{
"ads": [
{
"id": "display_ZFwfo0Mi2AhFBxUBHpXnICvV2j8zNTcxNzExUA==",
"gtin": "3571711P",
"discount": {
"amount": 0,
"minPrice": 0,
"maxPerCustomer": 0
},
"expiry": "2019-12-10T01:51:07.936105529Z"
},
{
"id": "display_VpFfnPOnaG4MZh43ckQjufmGAzwzNTcxOTkyUA==",
"gtin": "3571992P",
"discount": {
"amount": 0,
"minPrice": 0,
"maxPerCustomer": 0
},
"expiry": "2019-12-10T01:51:07.936111787Z"
},
{
"id": "display_vRHRnkTXbbssVwiem8jDrmOp2FM2Mzg3NTkyUA==",
"gtin": "6387592P",
"discount": {
"amount": 0,
"minPrice": 0,
"maxPerCustomer": 0
},
"expiry": "2019-12-10T01:51:07.936117921Z"
},
],
"banners": [],
"products": []
}

The discount and products fields are legacy and can be ignored

In the above response you can see that there is an ‘AdID” that we use for tracking, a ‘gtin’ which is the product code that you use in your catalog, and an expiry.

For more information, see:

Step 4: Display selected ads when loading a page

As CitrusAd are only sending product information to your back end, you will have to merge our product ad IDs with the organic search results, and then display all of the content on the page. In general we recommend displaying the products that are returned from CitrusAd in priority over the organic search results - as this is what advertisers are used to and expect. Depending on how many ads are requested and how many are returned by CitrusAd, you might be displaying no sponsored products, or any number up to an entire page worth of sponsored listings. Generally on a page that has been targeted by advertisers; there will be some middle-ground where you request say ‘4’ ads and these are placed into the top row of the results based on the order that they are returned from Citrus. Here are some example product pages with sponsored ads displayed from CitrusAd:

Step 5: Create banner ad content standard

For banner ads, you will need to specify to CitrusAd what spaces you have available for advertisers to target. Whether this is a header banner on a category page, or a double tile type banner on a product list page, we need to have dimensions and locations of all the banner slots that you wish to open up to advertisers. The way that we do this is by working with retailers to create a ‘Content Standard’. The Content Standard documents all the specific locations and sizes where banners can be displayed on your site and will be given to the suppliers so that they can create campaigns that target one or more of these locations on your site.

More information about Content Standards can be found here:

Step 6: Request and display banner ads when loading a page

Similar to Product Ads, when you request a Banner Ad we require you to send a ‘context’ which will tell us what page the customer is on, what banner slots are available, what filters have been applied and any customer information (if available).

An example of a Banner Ad request can be seen below:

HTTP
cURL
HTTP
POST $BASE_URL/v1/ads/generate?teamId=44d25f70-b520-40de-8329-0781a9ebcdc8 HTTP/1.1
accept: application/json
content-type: application/json
Authorization: Basic 4ww25f70-b52s-40de-8f29-07b139b5cdc8
{
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"customerId": "3g4e33rr45s3",
"searchTerm": "Laptop",
"productFilters": [
[
"Computers&Laptops"
]
],
"pageType": "CATEGORY",
"maxNumberOfAds": 0,
"contentStandardId": "contentStandardId1",
"bannerSlotIds": ["Category_Banner"]
}
cURL
curl -iX POST "$BASE_URL/v1/ads/generate?teamId=44d25f70-b520-40de-8329-0781a9ebcdc8" \
-H "accept: application/json" \
-H "content-type: application/json" \
-H "Authorization: Basic 4ww25f70-b52s-40de-8f29-07b139b5cdc8" \
-d \
'x{
"catalogId": "628dbe95-2ec9-4e07-881d-3e9f92ab2e0b",
"customerId": "3g4e33rr45s3",
"searchTerm": "Laptop",
"productFilters": [
[
"Computers&Laptops"
]
],
"categoryHierarchy": [
"Search", "Technology", "Computers&Laptops"
],
"pageType": "CATEGORY",
"maxNumberOfAds": 0,
"contentStandardId": "contentStandardId1",
"bannerSlotIds": ["Category_Banner"]
}'

In the shown case, the important information is the PageType, the ContentStandardId, and the BannerSlotIds. These give us the basic context of what page the customer is on and what size banner to return for this request. An example response for that request can be seen below:

HTTP
cURL
HTTP
HTTP/2 200
{
"ads": [ ],
"banners": [
{
"id": "display_GPZmwLMUH9n0_zfZTfn8UcmAShRlZmx",
"slotId": "Category_Banner",
"imageUrl": "https://assets.example.com/q/mdNYanp7zYVG6h4zYlSduXfadhNUctYG_9gsNlPHQ9t=",
"linkUrl": "https://www.retailer.com/p/product-471697300-652936600",
"altText": "An image of a brand xxx laptop with price $990 and shop now button.",
"expiry": "2002-10-02T15:00:00.05Z"
}
]
}
cURL
{
"ads": [ ],
"banners": [
{
"id": "display_GPZmwLMUH9n0_zfZTfn8UcmAShRlZmx",
"slotId": "Category_Banner",
"imageUrl": "https://assets.example.com/q/mdNYanp7zYVG6h4zYlSduXfadhNUctYG_9gsNlPHQ9t=",
"linkUrl": "https://www.retailer.com/p/product-471697300-652936600",
"altText": "An image of a brand xxx laptop with price $990 and shop now button.",
"expiry": "2002-10-02T15:00:00.05Z"
}
]
}

As you can see from the response, we only return an imgUrl and a linkUrl. This means that on your site you will need to insert that image into the page with the link attached. We also provide alternate text in the case that you are not be able to render the banner image. That completes a basic integration for a Banner Ad.

In more complex scenarios you can request multiple banners to display on a single page (header, product tile banner, footer) but the structure of the calls and responses will not change.

More information can be found here:

What happens if no banner ads are returned?

What happens if no banner ads are returned? This is a case that should definitely be considered, if a Banner Ad is not returned there should be an elegant fallback on the page which doesn’t leave a large blank space. Below is an example of a graceful fallback for a situation where no banner ads are returned or displayed.

An example of a Banner Ad correctly displayed:

A successfully served Banner Ad

An example of the Banner Ad not displayed:

A Banner Ad not being served, with the empty area effectively hidden

Step 7: Send impressions and clicks to CitrusAd for reporting

One of the most critical parts of the integration is making sure that all impressions and clicks are recorded on your pages so that we can collate these into metrics for all parties. To do this we have created a simple to implement JavaScript Library that you install on your pages. Once that is complete, all clicks and impressions can be sent to CitrusAd for reporting purposes.

More information can be found at:

Step 8: Sending order sales data to CitrusAd for reporting

With regards to the reporting of sales, you will need to save our Ad ID against a product in your cart and send us that information in the ‘order sync’. The ‘order sync’ is a list of all of your orders that you send to us, some products will have Ad IDs, and some will not. We will attribute sales to orders which have Ad IDs for conversion and ROAS reporting; and we will be able to use the other order data to improve our relevancy algorithms for future targeting.

The order sync can be done either via API or File Upload similar to the Catalog Upload.

Below is an example API upload:

HTTP
cURL
HTTP
POST $BASE_URL/v1/orders?teamId=e8158f9b-bbb9-49fb-93fe-3ad481ca8450 HTTP/1.1
accept: application/json
content-type: application/json
Authorization: 4ww25f70-b52s-40de-8f29-07b139b5cdc8
{
"orders": [
{
"id": "64965-5dvrt-5eds3-3wefw",
"teamId": "e8158f9b-bbb9-49fb-93fe-3ad481ca8450",
"customerId": "b1445104-1c4a-4c4c-a0a9-6cbc12482c56",
"orderDate": "2018-04-30T01:14:99.832ZD",
"orderItems": [
{
"gtin": "88560901388694",
"quantity": "5",
"RegularUnitPrice": "9.99",
"totalOrderItemPriceAfterDiscounts": "49.95"
"adId": "1985988a-6f9f-4ce8-8d4a-0a4b559206ca",
}
]
"adIds": [
"display_8d6bd7aa780d2278cf743d95cbdcfb7d262c5ba0575446cba91b628720975ob",
"display_8d6bd7aa780d2278cf745t45tb4h5bgfu4ba0575446cba91b628720975ob",
"display_8d6bd7aa780d2278cf743d95cbdcfb7d262c5ba0575446cba91b628720975ob",
"display_8d6bd7aa780d2278cf743d95cbdcfb7d262c5b4564h654hb6h45b645ob"
]
}
]
}
cURL
curl -iX POST "$BASE_URL/v1/orders?teamId=e8158f9b-bbb9-49fb-93fe-3ad481ca845" \
-H "accept: application/json" \
-H "content-type: application/json" \
-H "Authorization: 4ww25f70-b52s-40de-8f29-07b139b5cdc8" \
'{
"orders": [
{
"id": "64965-5dvrt-5eds3-3wefw",
"teamId": "e8158f9b-bbb9-49fb-93fe-3ad481ca8450",
"customerId": "b1445104-1c4a-4c4c-a0a9-6cbc12482c56",
"orderDate": "2018-04-30T01:14:99.832ZD",
"orderItems": [
{
"gtin": "88560901388694",
"quantity": "5",
"RegularUnitPrice": "9.99",
"totalOrderItemPriceAfterDiscounts": "49.95"
"adId": "1985988a-6f9f-4ce8-8d4a-0a4b559206ca",
}
]
"adIds": [
"display_8d6bd7aa780d2278cf743d95cbdcfb7d262c5ba0575446cba91b628720975ob",
"display_8d6bd7aa780d2278cf745t45tb4h5bgfu4ba0575446cba91b628720975ob",
"display_8d6bd7aa780d2278cf743d95cbdcfb7d262c5ba0575446cba91b628720975ob",
"display_8d6bd7aa780d2278cf743d95cbdcfb7d262c5b4564h654hb6h45b645ob"
]
}
]
}'

For more information visit:

Below is an example snippet of an order sync file:

order_id

customer_id

quantity

product_code

price_with_discounts

ad_id

ad_ids

order_date

1343321

5721

1

DM_357480

469

banner_Z2YcoG5Pqe1uTCsz3Lk5WE3sBmExNjI4NjAxNDA

2019-03-15

6845353

4234

4

4153234

191.8

display_4fy5MPixTU-cKAWimSlHsLkfrUZCV1NfNzM1NTM=

2019-03-15T17:06:17+00:06

6845353

4234

1

BWS_73553

6

display_IDI0Ks_vmSyeLUmDaa1UCCGJ_chCV1NfNzM1NTM=

2018-03-15T17:06:17+00:06

6845353

4234

3

BWS_74549

18

display_IDI054g4_vmSyeLUmDaa1UCCGJ_chCV1NfNzM1NTM, display_IDI0Ks_vmSyeLUmDaa1UCCfyn34ox8zn29rc3d44z8cn, banner_Z2YcoG5Pqe1uTCsz3Lkcxy342omcx4832mx4433x,

banner_33r3Csz3Lk5WE3sBmExNjI4x3yzcj38ccdh43ycxui3

2018-03-15T17:06:17+00:06

For more information visit:

If you have completed all of the steps, you should be ready to serve ads.

The steps for an MVP integration with CitrusAd are:

  • Create Catalog

  • Upload Product Data to Citrus

  • Request Product Ads when loading a page

  • Display selected ads when loading a page

  • Create Banner Ad Content Standard

  • Request and Display Banner ads when loading page

  • Send impressions and clicks to CitrusAd for reporting

  • Send order data to CitrusAd for reporting

Serving your first ad

To serve your first Ad, you will need to set up a campaign. To do this Log In to your account and select ‘Create Campaign’ in the top right corner.

The steps to create your fight campaign are:

  • Give your campaign a name

  • Decide on an activity period

  • Select Product/s to promote

  • Select bidding strategy (CPC/Fixed)

  • Targeting search terms

  • Review and Launch Campaign

Step 1: Give your campaign a name

You will need to give your campaign a name, we suggest something that is easily referenced and relevant to the products that you will be advertising or the overall campaign strategy goals.

Step 2: Decide on an activity period

The next step is to optionally choose whether or not your campaign will have a specific activity period. This is dependant on your marketing efforts, but in the case of your first campaign, just select ‘No’.

Step 3: Select products to promote

Assuming you have set up your catalog, you should be able to see and search through all of your products here to select which products to promote in your campaign.

Note: ensure your selected products are available in your testing environment, and are currently in stock

Step 4: Select bidding strategy

Bidding strategy in this case is either Cost Per Click or fixed ad rank. Generally if a retailer is setting up a campaign they will set a fixed ad rank, and if a supplier is setting up a campaign they will be using a Cost Per Click strategy. In this case select “Fixed ad rank” and select “Position 1” from the dropdown.

Step 5: Targeting search terms

You have the option of targeting search terms here, and if you do that means that when a customer is searching for those terms you are bidding on a position or placing your products in a position on the results page. If you wish to test search terms, select ‘Yes’. In this case we will skip this step and select ‘No’

Step 6: Review and launch campaign

That’s it! You have now got your first campaign set up, all you have to do is make sure all the details are correct, agree to the Terms and Conditions, and launch the campaign.

You should be able to see the campaign live in your testing environment when on relevant pages.