The Product Service
As part of commerce media, Surfside operates a product service which returns retailer-specific product information given a product ID. This feature enables advertisers to serve retail media advertising without having a first party relationship with the publisher those ads will display on.
Retail Media
Retail media is a form of advertising in which sponsored products are displayed on a retailer's website. These ads are typically shown in search results, on product detail pages, or in other high-traffic areas of the site. These creatives appear native to the site and are designed to blend in with the rest of the content, but are actually paid placements. Surfside's technology enables these kinds of creatives without advertisers needing to have a direct relationship with the retailer. When a native bid request is made, the Surfside bidder may return a product ID using a custom asset type ID in the native bid response. This product ID can then be used to fetch product information as a JSON payload from the Surfside product service.
Example
When a native request is built, a specific field called the "meta product" must be requested:
const request = new RequestBuilder()
.withNative(
JSON.stringify(
new NativeRequestBuilder()
.withTitle()
.withDescription()
.withMetaProduct() /* The meta product field must be explicitly requested */
.build()
)
)
.build();
This creates a native request for an asset with type ID 599, a custom ID which extends the OpenRTB 2.6 specification. When the bid response is returned, the product ID can be extracted from the meta product field. After parsing the bid response's ADM field, the payload may look like:
{
"native": {
"assets": [
{
"id": 1,
"required": 1,
"title": {
"text": "Product Title"
}
},
{
"id": 2,
"required": 1,
"data": {
"value": "Product Description"
}
},
{
"id": 599,
"required": 1,
"data": {
"value": "12345" /* Product ID */
}
}
]
}
}
This ID can then be passed (along with store details such as account ID) to the product service to fetch product information:
const { productFeed } = initSurfsideCore();
/* ... */
const product = await productFeed.getNativeProduct(accountId, siteId, locationId, productId);
console.log(product);
This will yield a large payload of product information, many fields of which may be empty depending on the original data source. Here is an example of a payload with all fields filled in:
{
"account_id": "iddqd",
"source_id": "ecf0f1",
"location_id": "h4m81n0",
"item_id": "304240",
"name": "Example Product",
"list": "Main Catalog",
"brand": "BrandName",
"category": "Electronics",
"variant": "Pro Model",
"price": "99.99",
"quantity": "50",
"coupon": "DISCOUNT10",
"position": "Top Seller",
"currency": "USD",
"product_type": "Gadget",
"product_category": "Home Electronics",
"color": "Black",
"size": "Medium",
"material": "Plastic",
"pattern": "Solid",
"condition": "New",
"cost_of_goods_sold": "50",
"shipping": "5.99",
"shipping_weight": "1.5",
"item_group_id": "Group123",
"gender": "Unisex",
"age_group": "Adult",
"adult": true,
"restricted": false,
"country": "USA",
"state": "CA",
"zip": "90210",
"description": "High-quality gadget.",
"link": "http://example.com",
"image_link": "http://example.com/assets/product.jpg",
"additional_image_link": "http://example.com/extra_img.jpg",
"model_3d_link": "http://example.com/model_3d",
"lifestyle_image_link": "http://example.com/lifestyle_img.jpg",
"availability": "In Stock",
"availability_date": "2024-06-01",
"expiration_date": "2024-12-31",
"sale_price": "79.99",
"sale_price_effective_date": "2024-05-01",
"mpn": "MPN123",
"gtin": "123456789012"
}
Each field should be null-tested before use, as some fields may be empty depending on the original data source. The product service will return a 404 if the product ID is not found in the product feed.
Full Example
From beginning to end, here's how to build a native request, extract the product ID, and fetch product information:
import { initSurfsideCore, RequestBuilder, NativeRequestBuilder } from '@surfside/ads-core';
/* Initialize Surfside Core */
const { bidder, productFeed, NativeAssetId } = initSurfsideCore();
/* Build the request */
const request = new RequestBuilder()
.withSurfContext(
accountId, /* Retail media campaigns target specific location IDs, */
siteId, /* so the surfside context is required */
locationId,
zoneId
)
.withNative(
JSON.stringify(
new NativeRequestBuilder()
.withTitle()
.withDescription()
.withMetaProduct() /* The meta product field must be explicitly requested */
.build()
)
)
.build();
const response = await bidder.requestBids(request);
/* Deserialize adm from JSON to native object */
const native = JSON.parse(response.seatBid[0].bid[0].adm);
const productId = native.assets
.find(asset => asset.id === NativeAssetId.SURF_META_PRODUCT)
.data
.value;
const product = await productFeed.getNativeProduct(
accountId,
siteId,
locationId,
productId
);
The product is then yours to do with as you please, but if you wish to use Surfside for rendering the product card or determining the appropriate clickthrough URL, then continue on to article on Templates and Clickthroughs