Back to News for Developers

Introducing Dynamic Product Ads

February 17, 2015ByScott Carpenter

We recently announced the release of dynamic product ads, which change the way advertisers can promote products on Facebook. We are happy to announce that dynamic product ads are available to all users of the Marketing API, and are fully supported in our PHP and Python Marketing API SDKs.

Until now, effectively promoting your entire product catalog to drive conversions has been a difficult challenge. With the release of dynamic product ads, it is now possible to advertise your entire catalog of products on Facebook. You can do this across all devices and at large scale, using the latest ad units such as the Multi-Product Ad.

How does it work?

  1. Upload your Product Catalog to your Business Manager
  2. Include Product IDs in your Pixel and App events
  3. Create a Product Set and an ad template that will be dynamically rendered based on your product data
  4. The Dynamic Product Ad will render the right product(s) to the right person, regardless of the device they are using

Let's walk through the process!

Product Catalog Setup

Your Product Catalog will contain data about the products you sell. This will include fields such title, description, availability, and price. The catalog can contain all of your products, of which you can choose specific Product Sets to advertise.

You can create and upload a Product Catalog through Business Manager or via the Marketing API. The full documentation for the feed format and APIs to create and upload it are here.

First, make your feed available on an HTTP or FTP server:

<?xml version="1.0"?>
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
<channel>
<title>Jasper's Market</title>
<link>http://www.jaspers-market.com</link>
<description>Jasper's Market Items</description>
<item>
<g:id>item_1</g:id>
<g:title>Set of 5 White Ceramic White Bowls</g:title>
<g:link>http://www.jaspers-market.com/item_1.html</g:link>
...
<g:price>9.99 USD</g:price>
</item>
<item>
<g:id>item_2</g:id>
<g:title>White Ceramic Mortar and Pestle</g:title>
<g:link>http://www.jaspers-market.com/item_2.html</g:link>
...
<g:price>12.99 USD</g:price>
</item>
</channel>
</rss>

Then, create a Product Catalog and upload your Feed. You can set up an upload schedule, or initiate the upload on demand:

use FacebookAds\Object\ProductCatalog;
use FacebookAds\Object\Fields\ProductCatalogFields;
use FacebookAds\Object\ProductFeed;
use FacebookAds\Object\Fields\ProductFeedFields;
use FacebookAds\Object\Fields\ProductFeedScheduleFields;
use FacebookAds\Object\ProductSet;
use FacebookAds\Object\Fields\ProductSetFields;

// Step 1:  Create a Product Catalog
$catalog = new ProductCatalog(null, '<BUSINESS_ID>');
$catalog->setData(array(
ProductCatalogFields::NAME => 'My Catalog',
));
$catalog->save();

// Step 2:  Schedule the Feed
$feed = new ProductFeed(null, $catalog->id);
$feed->setData(array(
ProductFeedFields::NAME => 'My Daily Feed',
ProductFeedFields::FILE_NAME => 'products.xml',
ProductFeedFields::SCHEDULE => array(
ProductFeedScheduleFields::INTERVAL => 'DAILY',
ProductFeedScheduleFields::URL =>
'http://www.jaspers-market.com/products.xml',
ProductFeedScheduleFields::HOUR => 22
)
));
$feed->save();

// Step 3:  Create a Product Set (a set of products to advertise)
$product_set = new ProductSet(null, $catalog->id);
$product_set->setData(array(
ProductSetFields::NAME => 'All Products',
ProductSetFields::FILTER => array()
));
$product_set->save();

// Step 4:  Associate the catalog with a Website Custom Audience Pixel
$catalog->setExternalEventSources(array('<PIXEL_ID>'));
from facebookads.objects import ProductCatalog
from facebookads.objects import ProductFeed
from facebookads.objects import ProductSet

# Step 1:  Create a Product Catalog
catalog = ProductCatalog(parent_id='<BUSINESS_MANAGER_ID>')
catalog[ProductCatalog.Field.name] = 'My Catalog'
catalog.remote_create()

# Step 2:  Schedule the Feed
feed = ProductFeed(parent_id=catalog.get_id())
feed[ProductFeed.Field.name] = 'My Daily Feed'
feed[ProductFeed.Field.file_name] = 'products.xml'
feed[ProductFeed.Field.schedule] = {
'interval': 'DAILY',
'url': 'http://www.jaspers-market.com/products.xml',
'hour': 22
}
feed.remote_create()

# Step 3:  Create a Product Set (a set of products to advertise)
product_set = ProductSet(parent_id=catalog.get_id())
product_set[ProductSet.Field.name] = 'All Products'
product_set[ProductSet.Field.filter] = []
product_set.remote_create()

# Step 4:  Associate the catalog with a Website Custom Audience Pixel
catalog.add_external_event_sources(['<PIXEL_ID>'])

Pixel and Audience Setup

When people interact with your products on your website, include the corresponding Product ID's from your catalog in those events. At a minimum, make sure to implement ViewContent, AddToCart and Purchase events on your website. Below is an example event, and you can find the complete documentation here

window._fbq = window._fbq || [];
window._fbq.push(['track', 'AddToCart', {
content_ids: ['item_1'],
content_type: 'product'
}]);

After your pixel is sending product-specific events, you can create a Product Audience (full documentation here). For example, to reach people that have viewed a product but not yet purchased it:

use FacebookAds\Object\Fields\ProductAudienceFields;
use FacebookAds\Object\ProductAudience;

$audience = new ProductAudience(null, 'act_<ACCOUNT_ID>');
$audience->setData(array(
ProductAudienceFields::NAME => 'Product Audience',
ProductAudienceFields::PRODUCT_SET_ID => '<PRODUCT_SET_ID>',
ProductAudienceFields::PIXEL_ID => '<PIXEL_ID>',
ProductAudienceFields::INCLUSIONS => array(array(
ProductAudienceFields::RETENTION_SECONDS => 86400,
ProductAudienceFields::RULE => array(
'event'=>array('eq'=>'ViewContent')
)
)),
ProductAudienceFields::EXCLUSIONS => array(array(
ProductAudienceFields::RETENTION_SECONDS => 172800,
ProductAudienceFields::RULE => array(
'event' => array('eq'=>'Purchase')
)
))
));
$audience->save();
from facebookads.objects import ProductAudience

audience = ProductAudience(parent_id='act_<ACCOUNT_ID>')
audience[ProductAudience.Field.name] = 'Product Audience'
audience[ProductAudience.Field.product_set_id] = '<PRODUCT_SET_ID>'
audience[ProductAudience.Field.pixel_id] = '<PIXEL_ID>'
audience[ProductAudience.Field.inclusions] = [{
'retention_seconds': 86400,
'rule': {'event': {'eq': 'ViewContent'}}
}]
audience[ProductAudience.Field.exclusions] = [{
'retention_seconds': 172800,
'rule': {'event': {'eq': 'Purchase'}}
}]
audience.remote_create()

Product Audiences will start populating from the moment they are created. Make sure to check your Product Audience size to confirm that it is set up and populating correctly.

Create your Dynamic Product Ad Campaign

Dynamic product ads use the PRODUCT_CATALOG_SALES objective. Create a new campaign and ad set using this objective:

New Fields in ad campaign and ad set: *

PROMOTED_OBJECT

for ad campaign which specifies a

product_catalog_id
product_set_id

specified in the ad set's

PROMOTED_OBJECT
DYNAMIC_AUDIENCE_IDS

in the

TargetingSpecs

use FacebookAds\Object\AdCampaign;
use FacebookAds\Object\Fields\AdCampaignFields;
use FacebookAds\Object\AdSet;
use FacebookAds\Object\Fields\AdSetFields;
use FacebookAds\Object\Values\AdObjectives;
use FacebookAds\Object\Values\BidTypes;
use FacebookAds\Object\Fields\AdGroupBidInfoFields;
use FacebookAds\Object\TargetingSpecs;
use FacebookAds\Object\Fields\TargetingSpecsFields;

// Ad Campaign with the Product Catalog as the promoted object 
$campaign = new AdCampaign(null, 'act_<ACCOUNT_ID>');
$campaign->setData(array(
AdCampaignFields::NAME => 'DPA Campaign',
AdCampaignFields::OBJECTIVE => AdObjectives::PRODUCT_CATALOG_SALES,
AdCampaignFields::PROMOTED_OBJECT => 
array('product_catalog_id' => '<PRODUCT_CATALOG_ID>')
));
$campaign->save();

// Targeting Spec using our Dynamic Audience
$targeting = new TargetingSpecs();
$targeting->{TargetingSpecsFields::GEO_LOCATIONS} =
array('countries' => array('US'));
$targeting->{TargetingSpecsFields::DYNAMIC_AUDIENCE_IDS} =
array('<DYNAMIC_AUDIENCE_ID>');

// Ad Set with a Product Set as promoted object
$adset = new AdSet(null, 'act_<ACCOUNT_ID>');
$adset->setData(array(
AdSetFields::NAME => 'DPA Ad Set',
AdSetFields::BID_TYPE => BidTypes::BID_TYPE_CPC,
AdSetFields::BID_INFO => 
array(AdGroupBidInfoFields::CLICKS => 150),
AdSetFields::DAILY_BUDGET => 2000,
AdSetFields::CAMPAIGN_GROUP_ID => $campaign->id,
AdSetFields::TARGETING => $targeting,
AdsetFields::PROMOTED_OBJECT =>
array('product_set_id' => '<PRODUCT_SET_ID>')
));
$adset->save();
from facebookads.objects import AdCampaign
from facebookads.objects import AdSet
from facebookads.objects import TargetingSpecsField

# Ad Campaign with the Product Catalog as the promoted object 
campaign = AdCampaign(parent_id='act_<ACCOUNT_ID>')
campaign[AdCampaign.Field.name] = 'DPA Campaign'
campaign[AdCampaign.Field.objective] = 'PRODUCT_CATALOG_SALES'
campaign[AdCampaign.Field.promoted_object] = {
'product_catalog_id': '<PRODUCT_CATALOG_ID>'
}
campaign.remote_create()

# Ad Set with a Product Set as promoted object and targeting a Product Audience
adset = AdSet(parent_id='act_<ACCOUNT_ID>')
adset[AdSet.Field.name] = 'DPA Ad Set'
adset[AdSet.Field.bid_type] = AdSet.BidType.cpc
adset[AdSet.Field.bid_info] = {'CLICKS': 150}
adset[AdSet.Field.daily_budget] = 2000
adset[AdSet.Field.campaign_group_id] = campaign.get_id()
adset[AdSet.Field.targeting] = {
TargetingSpecsField.geo_locations:{'countries': ['US']},
TargetingSpecsField.dynamic_audience_ids: ['PRODUCT_AUDIENCE_ID']
}
adset[AdSet.Field.promoted_object] = {
'product_set_id': '<PRODUCT_SET_ID>'
}
adset.remote_create()

Finally, your Template and Dynamic Product Ad!

use FacebookAds\Object\AdCreative;
use FacebookAds\Object\ObjectStory\TemplateData;
use FacebookAds\Object\ObjectStorySpec;
use FacebookAds\Object\Values\CallToActionTypes;
use FacebookAds\Object\Fields\ObjectStory\TemplateDataFields;
use FacebookAds\Object\Fields\AdCreativeFields;
use FacebookAds\Object\Fields\ObjectStorySpecFields;
use FacebookAds\Object\AdGroup;
use FacebookAds\Object\Fields\AdGroupFields;
use FacebookAds\Object\Values\AdObjectives;

// Creative template to be dynamically rendered with product data
$template = new TemplateData();
$template->setData(array(
TemplateDataFields::DESCRIPTION => '{{product.description}}',
TemplateDataFields::LINK => 'http://jaspers-market.com/',
TemplateDataFields::MESSAGE => 'Jasper\'s is more than just groceries.  You can now find all of your cooking tools and utensils on our website',
TemplateDataFields::NAME => '{{product.name | titleize}}',
TemplateDataFields::MAX_PRODUCT_COUNT => 3, // enable Multi-Product Ads
TemplateDataFields::CALL_TO_ACTION => array(
'type' => CallToActionTypes::SHOP_NOW
)
));

$story = new ObjectStorySpec();
$story->setData(array(
ObjectStorySpecFields::PAGE_ID => '<PAGE_ID>',
ObjectStorySpecFields::TEMPLATE_DATA => $template,
));

// Ad creative is tied to a specific Product Set
$creative = new AdCreative(null, 'act_<ACCOUNT_ID>');
$creative->setData(array(
AdCreativeFields::NAME => 'DPA Creative 1',
AdCreativeFields::OBJECT_STORY_SPEC => $story,
AdCreativeFields::PRODUCT_SET_ID => '<PRODUCT_SET_ID>'
));
$creative->save();

// Ad Group using the PRODUCT_CATALOG_SALES objective
$adgroup = new AdGroup(null, 'act_<ACCOUNT_ID>');
$adgroup->setData(array(
AdGroupFields::NAME => 'DPA Ad 1',
AdGroupFields::CAMPAIGN_ID => '<AD_SET_ID>', // $adset->id from earlier
AdGroupFields::CREATIVE =>
array('creative_id' => $creative->id),
AdGroupFields::OBJECTIVE => AdObjectives::PRODUCT_CATALOG_SALES
));
$adgroup->save();
from facebookads.objects import AdCreative
from facebookads.specs import ObjectStorySpec
from facebookads.specs import TemplateData
from facebookads.objects import AdGroup

# Creative template to be dynamically rendered with product data
template = TemplateData()
template[TemplateData.Field.description] = '{{product.description}}'
template[TemplateData.Field.link] = 'http://jaspers-market.com/'
template[TemplateData.Field.message] = 'Jasper\'s is more than just groceries.  You can now find all of your cooking tools and utensils on our website'
template[TemplateData.Field.name] = '{{product.name | titleize}}'
template[TemplateData.Field.max_product_count] = 3 # enable Multi-Product Ads
template[TemplateData.Field.call_to_action] = {
'type': 'SHOP_NOW'
}

story = ObjectStorySpec()
story[ObjectStorySpec.Field.page_id] = '<PAGE_ID>'
story[ObjectStorySpec.Field.template_data] = template

# Ad creative is tied to a specific Product Set
creative = AdCreative(parent_id='act_<ACCOUNT_ID>')
creative[AdCreative.Field.name] = 'DPA Creative 1'
creative[AdCreative.Field.object_story_spec] = story
creative[AdCreative.Field.product_set_id] = '<PRODUCT_SET_ID>'
creative.remote_create()

# Ad Group using the PRODUCT_CATALOG_SALES objective
adgroup = AdGroup(parent_id='act_<ACCOUNT_ID>')
adgroup[AdGroup.Field.name] = 'DPA Ad 1'
adgroup[AdGroup.Field.campaign_id] = '<AD_SET_ID>' # adset.get_id() from earlier
adgroup[AdGroup.Field.creative] = {'creative_id':creative.get_id()}
adgroup[AdGroup.Field.objective] = 'PRODUCT_CATALOG_SALES'
adgroup.remote_create()

The above sample will create a templated ad:

Let Dynamic Product Ads Work

After the setup above, your Dynamic Product Ad can run "Always On" and will automatically show the right product to the right person, according to your audience rules. The ad will always be rendered at the time of the impression with the latest data from your product feed. Below is an example of the above templated ad rendered with three of the sample products:

Once your dynamic product ads are running, you can learn how individual products are performing by calling Ad Report Stats with a breakdown by Product ID.

The complete set of documentation is available here. Enjoy!


Tags: