Dynamic Ads for Travel - Creating Ads

This guide assumes you have a catalog and product set ready, and have set up the required travel events on your website or in your mobile app. You also need a Facebook Page and an ad account.

Targeting Strategies

Dynamic Ads for Travel supports different targeting strategies. You can drive different business objectives by combining the right audience with the right product set:


Show relevant hotels, destinations or flights to people who have been to your website or app looking for hotels, destinations or flights.

Cross-sell and up-sell

Target people who have purchased a flight with relevant hotels, or up-sell priority boarding or seat selection.

Broad Audiences

Expand the reach of your ad and find new customers by targeting broad audiences.

Creating Dynamic Ads

Creating Dynamic Ads for Travel follows the same process you follow when you set up any other type of Facebook ad with the API.

Step 1. Create Campaign

Dynamic Ads for travel uses the PRODUCT_CATALOG_SALES objective. Specify a travel catalog in promoted_object at the campaign level:

use FacebookAds\Object\Campaign;
use FacebookAds\Object\Fields\CampaignFields;
use FacebookAds\Object\Values\CampaignObjectiveValues;

$campaign = new Campaign(null, 'act_<AD_ACCOUNT_ID>');
  CampaignFields::NAME => 'Product Catalog Sales Campaign',
  CampaignFields::OBJECTIVE => CampaignObjectiveValues::PRODUCT_CATALOG_SALES,
  CampaignFields::PROMOTED_OBJECT => array(
    'product_catalog_id' => <PRODUCT_CATALOG_ID>,

from facebookads.adobjects.campaign import Campaign

campaign = Campaign(parent_id='act_<AD_ACCOUNT_ID>')
campaign[Campaign.Field.name] = 'Product Catalog Sales Campaign'
objective = Campaign.Objective.product_catalog_sales
campaign[Campaign.Field.objective] = objective
campaign[Campaign.Field.promoted_object] = {
    'product_catalog_id': <PRODUCT_CATALOG_ID>,

    'status': Campaign.Status.paused,
Campaign campaign = new AdAccount(act_<AD_ACCOUNT_ID>, context).createCampaign()
  .setName("Product Catalog Sales Campaign Group")
  .setPromotedObject("{\"product_catalog_id\":\"" + <PRODUCT_CATALOG_ID> + "\"}")
String campaign_id = campaign.getId();
curl \
  -F 'name=Product Catalog Sales Campaign' \
  -F 'objective=PRODUCT_CATALOG_SALES' \
  -F 'promoted_object={"product_catalog_id":"<PRODUCT_CATALOG_ID>"}' \
  -F 'status=PAUSED' \
  -F 'access_token=<ACCESS_TOKEN>' \

Step 2. Create Ad Set

Once you have the campaign, and the campaign_id, you can create the ad set which defines the bidding and targeting options for your ads.


To retarget the website or app visitors, use a dynamic audience of the same type as the product set you are promoting; for example, promote a hotel set to a hotel audience, a flight set to a flight audience and a destination set to a destination audience.

Cross-sell and up-sell

To cross-sell and up-sell people that purchased on your website and/or app, use a dynamic audience that contains people that have made a purchase, and promote them travel options from another catalog, i.e. target a flight purchase audience with a hotel set or another flight set highlighting seat selection.

Broad Audiences

  • Create an audience using basic demographic targeting such as women in the US over 18.
  • Include customers targeted by existing retargeting campaigns, but consider excluding people who have purchased in the last 10 days.
  • Use a broad product set with over 100 hotels.
  • Optimize for OFFSITE_CONVERSIONS with stronger intent signals such as Purchase or InitiateCheckout.
  • See also Dynamic Ads, Broad Audience Targeting

Creating the Ad Set

use FacebookAds\Object\AdSet;
use FacebookAds\Object\Fields\AdSetFields;
use FacebookAds\Object\Fields\TargetingFields;
use FacebookAds\Object\Values\AdSetBillingEventValues;
use FacebookAds\Object\Values\AdSetOptimizationGoalValues;

$adset = new AdSet(null, 'act_<AD_ACCOUNT_ID>');

  AdSetFields::NAME => 'Product Catalog Sales Adset',
  AdSetFields::BID_AMOUNT => 3000,
  AdSetFields::BILLING_EVENT => AdSetBillingEventValues::IMPRESSIONS,
  AdSetFields::DAILY_BUDGET => 15000,
  AdSetFields::TARGETING => array(
    TargetingFields::GEO_LOCATIONS => array(
      'countries' => array('US'),
    TargetingFields::DYNAMIC_AUDIENCE_IDS => array(<DYNAMIC_AUDIENCE_ID>),
  AdSetFields::PROMOTED_OBJECT => array(
    'product_set_id' => <PRODUCT_SET_ID>,

from facebookads.adobjects.adset import AdSet
from facebookads.adobjects.targeting import Targeting

adset = AdSet(parent_id=ad_account_id)
adset[AdSet.Field.name] = 'Product Catalog Sales Adset'
adset[AdSet.Field.bid_amount] = 3000
adset[AdSet.Field.billing_event] = AdSet.BillingEvent.impressions
adset[AdSet.Field.optimization_goal] = \
adset[AdSet.Field.daily_budget] = 15000
adset[AdSet.Field.campaign_id] = campaign_id
adset[AdSet.Field.targeting] = {
    Targeting.Field.geo_locations: {
        Targeting.Field.countries: ['US'],
    Targeting.Field.dynamic_audience_ids: [
adset[AdSet.Field.promoted_object] = {
    'product_set_id': product_set_id,

AdSet adSet = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdSet()
  .setName("Product Catalog Sales Adset")
    new Targeting()
        new TargetingGeoLocation()
  .setPromotedObject("{\"product_set_id\":\"" + <PRODUCT_SET_ID> + "\"}")
String ad_set_id = adSet.getId();
curl \
  -F 'name=Product Catalog Sales Adset' \
  -F 'bid_amount=3000' \
  -F 'billing_event=IMPRESSIONS' \
  -F 'optimization_goal=OFFSITE_CONVERSIONS' \
  -F 'daily_budget=15000' \
  -F 'campaign_id=<CAMPAIGN_ID>' \
  -F 'targeting={ 
    "geo_locations": {"countries":["US"]}, 
    "dynamic_audience_ids": ["<DYNAMIC_AUDIENCE_ID>"] 
  }' \
  -F 'promoted_object={"product_set_id":"<PRODUCT_SET_ID>"}' \
  -F 'status=PAUSED' \
  -F 'access_token=<ACCESS_TOKEN>' \

Unlike Dynamic Ads, Dynamic Ads for Travel does not support inline dynamic audience targeting specs in the Ad Set. You must separately create an audience first.

Step 3. Create Ad Creative

You can use template tags in your ad creatives for Dynamic Ads for Travel. When Facebook displays your ad, we replace template tags with someone's actual travel choices. You can use template tags in the ad itself, as well as in the URL someone sees once they click on the ad.

Use the template_url_spec field to specify the URL that appears after someone clicks on the ad. If you do not provide it, or we cannot derive it when we render an ad, we display the URL from the catalog. With Dynamic Ads for Flight this field is required if you do not provide a URL in the catalog.

You can show a single item or a carousel with multiple items. For single-item ads, you can show multiple images of the same item in the carousel, assuming your catalog contains multiple images for each item. You can also display static cards in combination with dynamic cards. For more information about creative options, see Dynamic Ads, Building a Creative Template.

You cannot show multiple flights in a carousel. However, you can add multiple images per flight in the catalog and show multiple images for the same flight.

Below is an example to create a carousel creative for Dynamic Ads for Hotels. Dynamic Ads for Destinations and Dynamic Ads for Flights will have a similar setup.

use FacebookAds\Object\AdCreative;
use FacebookAds\Object\Fields\AdCreativeFields;
use FacebookAds\Object\Fields\AdCreativeLinkDataFields;
use FacebookAds\Object\Fields\AdCreativeObjectStorySpecFields;
use FacebookAds\Object\Values\AdCreativeCallToActionTypeValues;
use FacebookAds\Object\AdCreativeObjectStorySpec;
use FacebookAds\Object\AdCreativeLinkData;

$object_story_spec = new AdCreativeObjectStorySpec();
  AdCreativeObjectStorySpecFields::PAGE_ID => <PAGE_ID>,
  AdCreativeObjectStorySpecFields::TEMPLATE_DATA =>
    (new AdCreativeLinkData())->setData(array(
      AdCreativeLinkDataFields::MESSAGE =>
        'Book your upcoming stay in {{hotel.city}}',
      AdCreativeLinkDataFields::NAME => '{{hotel.name | titleize}}',
      AdCreativeLinkDataFields::LINK => '<LINK>',
      AdCreativeLinkDataFields::DESCRIPTION =>
      AdCreativeLinkDataFields::ADDITIONAL_IMAGE_INDEX => 0,
      AdCreativeLinkDataFields::CALL_TO_ACTION => array(
        'type' => AdCreativeCallToActionTypeValues::BOOK_TRAVEL,

$creative = new AdCreative(null, 'act_<AD_ACCOUNT_ID>');
  AdCreativeFields::NAME => 'Dynamic Ad Template Creative Sample',
  AdCreativeFields::OBJECT_STORY_SPEC => $object_story_spec,
  AdCreativeFields::TEMPLATE_URL_SPEC =>
      'config' => array(
        'app_id' => '123456789012345',
      'ios' => array(
        'url' => 'example://home/hotel'.
          '?id={{hotel.hotel_id | urlencode}}'.
          '&startDate={{trip.checkin_date date_format:Y-m-d | urlencode}}'.
          '&endDate={{trip.checkout_date date_format:Y-m-d | urlencode}}',
      'web' => array(
        'url' => 'http://www.example.com/hotel'.
          '?id={{hotel.hotel_id | urlencode}}'.
          '&startDate={{trip.checkin_date date_format:Y-m-d | urlencode}}'.
          '&endDate={{trip.checkout_date date_format:Y-m-d | urlencode}}',
  AdCreativeFields::PRODUCT_SET_ID => <PRODUCT_SET_ID>,

from facebookads.adobjects.adcreative import AdCreative
from facebookads.adobjects.adcreativeobjectstoryspec \
    import AdCreativeObjectStorySpec

story = AdCreativeObjectStorySpec()
story[story.Field.page_id] = <PAGE_ID>
story[story.Field.template_data] = {
    'message': 'Book your upcoming stay in {{hotel.city}}',
    'name': '{{hotel.name | titleize}}',
    'link': '<LINK>',
    'description': '{{hotel.description}}',
    'additional_image_index': 0,
    'call_to_action': {
        'type': 'BOOK_TRAVEL',

creative = AdCreative(parent_id='act_<AD_ACCOUNT_ID>')
creative[AdCreative.Field.name] = 'Dynamic Ad Template Creative Sample'
creative[AdCreative.Field.object_story_spec] = story
template_url = ('http://www.example.com/hotel.aspx?id={{hotel.hotel_id}}'
                '&startDate={{trip.checkin_date date_format:Y-m-d}}'
                '&endDate={{trip.checkout_date date_format:Y-m-d}}')
creative[AdCreative.Field.template_url] = template_url
creative[AdCreative.Field.product_set_id] = <PRODUCT_SET_ID>
curl \
  -F 'name=Dynamic Ad Template Creative Sample' \
  -F 'object_story_spec={ 
    "page_id": "<PAGE_ID>", 
    "template_data": { 
      "additional_image_index": 0, 
      "call_to_action": {"type":"BOOK_TRAVEL"}, 
      "description": "{{hotel.description}}", 
      "link": "<LINK>", 
      "message": "Book your upcoming stay in {{hotel.city}}", 
      "name": "{{hotel.name | titleize}}" 
  }' \
  -F 'template_url_spec={ 
    "config": {"app_id":"123456789012345"}, 
    "ios": { 
      "url": "example:\/\/home\/hotel?id={{hotel.hotel_id | urlencode}}&startDate={{trip.checkin_date date_format:Y-m-d | urlencode}}&endDate={{trip.checkout_date date_format:Y-m-d | urlencode}}" 
    "web": { 
      "url": "http:\/\/www.example.com\/hotel?id={{hotel.hotel_id | urlencode}}&startDate={{trip.checkin_date date_format:Y-m-d | urlencode}}&endDate={{trip.checkout_date date_format:Y-m-d | urlencode}}" 
  }' \
  -F 'product_set_id=<PRODUCT_SET_ID>' \
  -F 'access_token=<ACCESS_TOKEN>' \

Flight Up-sell (API v2.10+ only)

To up-sell options, such as seat selection or priority boarding to an audience that purchased flights:

  • Provide an audience by including only PURCHASE events.
  • In the ad creative's recommender_settings, specify PURCHASE events as the preferred way to recommend ads.
curl \
  -F 'name=Dynamic Ad Template Creative Up-sell Sample' \
  -F 'object_story_spec={ 
    "page_id": "<PAGE_ID>", 
    "template_data": { 
      "additional_image_index": 0, 
      "call_to_action": {"type":"LEARN_MORE"}, 
      "description": "{{flight.description}}", 
      "link": "<LINK>", 
      "message": "Book extra leg room on your flight from {{flight.origin_city}} to {{flight.destination_city}}", 
  }' \
  -F 'template_url_spec={ 
    "config": {"app_id":"<APP_ID>"}, 
    "ios": { 
      "url": "example:\/\/home\/flight?id={{flight.origin_airport}}&startDate={{trip.departing_departure_date date_format:Y-m-d | urlencode}}&endDate={{trip.returning_departure_date date_format:Y-m-d | urlencode}}" 
    "web": { 
      "url": "http:\/\/www.example.com\/flight?id={{flight.origin_airport}}&startDate={{trip.checkin_date date_format:Y-m-d | urlencode}}&endDate={{trip.returning_departure_date date_format:Y-m-d | urlencode}}" 
  }' \
  -F 'product_set_id=<FLIGHT_SET_ID>' \
  -F 'recommender_settings'={"preferred_events":["Purchase"]}\ 
  -F 'access_token=<ACCESS_TOKEN>' \

Overlay Design

Overlays allow advertisers to add pricing information (as a direct price or percentage off) for each item within a dynamic ad.

Overlay Options by Catalog Type

You can use the following overlay types depending on the catalog type you use in the ad set:

  • Hotel: price, strikethrough and % off
  • Destination: price
  • Flight: price

Note: All price-related template tags for each catalog type are supported for the overlay options above. To view template tags for each catalog type, see hotels, destinations and flights.

Overlay Design Options

The pricing information is pulled dynamically from the price and sale price columns of the feed. Advertisers can select from the following customizations for their dynamic ads overlay:

  • Shapes: Pill, Circle and Triangle.
  • Positions: 4 fixed corners: TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT and BOTTOM_RIGHT. For triangle, only the TOP_LEFT and TOP_RIGHT are supported.
  • Fonts: A list of preset fonts, such as Droid Serif, Open Sans, and so on.
  • Overlay types supported: price, strikethrough and % off. Note: strikethrough and % off are available for hotels only.

Learn more about how to add overlays.

Example—Price Overlay with Strikethrough for a Hotel Ad

curl \
  -F 'name=Test Templates in Overlay' \
  -F 'object_story_spec={
    "page_id": "<PAGE_ID>",
    "template_data": {
      "description": "Description",
      "link": "<LINK>", 
      "name": "Name: {{hotel.name}}",
      "message" : "Come visit {{hotel.city}}!",
      "image_overlay_spec": {
        "text_template_tags": ["{{hotel.price round}}", "{{hotel.sale_price round}}"],
  }' \
  -F 'product_set_id=<PRODUCT_SET_ID>' \
  -F 'template_url=http://www.example.com' \
  -F 'access_token=<ACCESS_TOKEN>' \

Use the ad_set_id and the creative_id to create the ad.

curl -X POST \ -F 'name=My Ad' \ -F 'adset_id=<AD_SET_ID>' \ -F 'creative={"creative_id":"<CREATIVE_ID>"}' \ -F 'status=PAUSED' \ -F 'access_token=<ACCESS_TOKEN>' \ https://graph.facebook.com/v3.0/act_<AD_ACCOUNT_ID>/ads
const adsSdk = require('facebook-nodejs-ads-sdk'); const AdAccount = adsSdk.AdAccount; const Ad = adsSdk.Ad; let access_token = '<ACCESS_TOKEN>'; let app_secret = '<APP_SECRET>'; let app_id = '<APP_ID>'; let id = '<ID>'; const api = adsSdk.FacebookAdsApi.init(access_token); const showDebugingInfo = true; // Setting this to true shows more debugging info. if (showDebugingInfo) { api.setDebug(true); } const fields = [ ]; const params = { 'name' : 'My Ad', 'adset_id' : '<adSetID>', 'creative' : {'creative_id':'<adCreativeID>'}, 'status' : 'PAUSED', }; (new AdAccount(id)).createAd( fields, params ) .then((result) => { ads_id = result.id; console.log(ads_id); }) .catch((error) => { console.log(error); });
require __DIR__ . '/vendor/autoload.php'; use FacebookAds\Object\AdAccount; use FacebookAds\Object\Ad; use FacebookAds\Api; use FacebookAds\Logger\CurlLogger; $access_token = '<ACCESS_TOKEN>'; $app_secret = '<APP_SECRET>'; $app_id = '<APP_ID>'; $id = '<ID>'; $api = Api::init($app_id, $app_secret, $access_token); $api->setLogger(new CurlLogger()); $fields = array( ); $params = array( 'name' => 'My Ad', 'adset_id' => '<adSetID>', 'creative' => array('creative_id' => '<adCreativeID>'), 'status' => 'PAUSED', ); echo json_encode((new AdAccount($id))->createAd( $fields, $params )->getResponse()->getContent(), JSON_PRETTY_PRINT);
from facebookads.adobjects.adaccount import AdAccount from facebookads.adobjects.ad import Ad from facebookads.api import FacebookAdsApi access_token = '<ACCESS_TOKEN>' app_secret = '<APP_SECRET>' app_id = '<APP_ID>' id = '<ID>' FacebookAdsApi.init(access_token=access_token) fields = [ ] params = { 'name': 'My Ad', 'adset_id': '<adSetID>', 'creative': {'creative_id':'<adCreativeID>'}, 'status': 'PAUSED', } print AdAccount(id).create_ad( fields=fields, params=params, )
import com.facebook.ads.sdk.*; import java.io.File; import java.util.Arrays; public class SAMPLE_CODE_EXAMPLE { public static void main (String args[]) throws APIException { String access_token = \"<ACCESS_TOKEN>\"; String app_secret = \"<APP_SECRET>\"; String app_id = \"<APP_ID>\"; String id = \"<ID>\"; APIContext context = new APIContext(access_token).enableDebug(true); new AdAccount(id, context).createAd() .setName(\"My Ad\") .setAdsetId(<adSetID>L) .setCreative( new AdCreative() .setFieldId(\"<adCreativeID>\") ) .setStatus(Ad.EnumStatus.VALUE_PAUSED) .execute(); } }
access_token = '<ACCESS_TOKEN>' app_secret = '<APP_SECRET>' app_id = '<APP_ID>' id = '<ID>' FacebookAds.configure do |config| config.access_token = access_token config.app_secret = app_secret end ad_account = FacebookAds::AdAccount.get(id) ad_account.ads.create({ name: 'My Ad', adset_id: '<adSetID>', creative: {'creative_id':'<adCreativeID>'}, status: 'PAUSED', })

Next Steps

Preview the Ad

You can generate a preview of your dynamic creative with the Ad Previews API. Include the product_item_ids parameter to specify which catalog items will display in the preview.

Generate a preview of your ad with the Ad Previews API. Include the product_item_ids to specify which catalog items appears in the preview, start_date and end_date to specify specific dates.

use FacebookAds\Object\AdCreative;
use FacebookAds\Object\Fields\AdPreviewFields;
use FacebookAds\Object\Values\AdPreviewAdFormatValues;

$creative = new AdCreative(<CREATIVE_ID>);
$preview = $creative->getPreviews(array(), array(
  AdPreviewFields::AD_FORMAT => AdPreviewAdFormatValues::DESKTOP_FEED_STANDARD,
  AdPreviewFields::PRODUCT_ITEM_IDS => array(
from facebookads.adobjects.adcreative import AdCreative
from facebookads.adobjects.adpreview import AdPreview

creative = AdCreative(<CREATIVE_ID>)
params = {
    'product_item_ids': [
preview = creative.get_previews(params=params)
curl -G \
  -d 'ad_format=DESKTOP_FEED_STANDARD' \
  -d 'product_item_ids=["<HOTEL_FBID>"]' \
  -d 'access_token=<ACCESS_TOKEN>' \


Field Name & Type Description


type: array[string]

  • Hotel: List of hotel FBID or Base64url-encoded hotel ID tokens. Each token is of the form hotel_catalog:{catalog_id}:{base64urlencode(hotel_id)}
  • Destination: List of destination FBID or Base64url-encoded destination ID tokens. Each token is of the form destination_catalog:{catalog_id}:{base64urlencode(destination_id)}
  • Flight: Flight FBID or Base64url-encoded flight ID token. Each token is of the form flight_catalog:{catalog_id}:{base64urlencode(destination_id)}


type: string

Render the preview with user's intent signal, e.g. 2016-12-24.

  • For hotel, this would be the value of trip.checkin_date
  • For destination, this would be the value of trip.travel_start
  • For flight, this would be the value of trip.departing_departure_date


type: string

Render the preview with user's intent signal, e.g. 2017-01-01.

  • For hotel, this would be the value of trip.checkout_date
  • For destination, this would be the value of trip.travel_end
  • For flight, this would be the value of trip.returning_departure_date

Fetch Travel Ad Insights & Statistics

To fetch ad Insights for a travel object, such as hotel, make a GET call to /insights. Remember to add product_id to the breakdown parameter. For hotel and destination, product id breakdown will be shown for each hotel_id or destination_id. For flight, product id breakdown will show origin_airport:destination_airport.

Fetch Comments and Likes

To retrieve comments or "Likes" of a Dynamic Ad, use the Dynamic Post API.