Dynamic Ads for Travel

Automatically promote your travel inventory on Facebook. Use cross-device intent signals from people to automatically promote relevant travel options from your inventory with unique creative on Facebook.

High-Level Steps

  1. Set up your Hotel, Destination or Flight Catalog
  2. Build your Audience for Travel
  3. Create and deliver ads for your hotels, destinations or flights
  4. Get delivery information to see how people on Facebook are engaging in you ads, see Ads Insights
  5. Use debugging tools to diagnose and resolve problems. See Dynamic Ads Debugging Tools.

Catalog Setup

To set up Dynamic Ads for Travel, you need a travel catalog:

  • Hotel catalog for remarketing hotels
  • Flight catalog for remarketing flights
  • Destination catalog to display travel destination creative to inspire people to click an ad and see more about the destination

Catalogs list items such as hotel, destination, and flights to advertise. Each item has information to create customized ads for a specific item. You can constantly update catalogs through various options. If you batch upload content, you can also use a partial upload option, which enables you to only create or update items that have changed, see Batch Upload. This is available for all Dynamic Ads areas.

The current version of Dynamic Ads for travel enables you to advertise multiple hotels; future releases can also support other travel options, such as flights, and vacation package.

To set up catalogs, see:

Hotel Catalog

Step 1: Create Hotel Catalog

You need the appropriate Marketing API Access Level and accept the Terms of Service by creating your first catalog through Business Manager.

A hotel catalog contains a list of hotels that you would like to advertise. To create a hotel catalog, set vertical to hotels:

use FacebookAds\Object\ProductCatalog;
use FacebookAds\Object\Fields\ProductCatalogFields;
use FacebookAds\Object\Values\ProductCatalogVerticalValues;

$product_catalog = new ProductCatalog(null, <BUSINESS_ID>);

$product_catalog->setData(array(
  ProductCatalogFields::NAME => "Hotel Catalog",
  ProductCatalogFields::VERTICAL => ProductCatalogVerticalValues::HOTELS,
));

$product_catalog->create();
from facebookads.adobjects.productcatalog import ProductCatalog

product_catalog = ProductCatalog(parent_id=<BUSINESS_ID>)

product_catalog[ProductCatalog.Field.name] = 'Hotel Catalog'
product_catalog[ProductCatalog.Field.vertical] = 'hotels'

product_catalog.remote_create()
curl \
  -F 'name=Hotel Catalog' \
  -F 'vertical=hotels' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<BUSINESS_ID>/product_catalogs

Step 2: Setup Hotel and Pricing

There are two types of hotel information: static hotel feed or room and pricing. Static hotel feed should not change frequently, such as hotel name and location of the hotel. Room and pricing is for information that frequently changes such as pricing and availability.


Hotel Feed

This is set of hotels uploaded or fetched from your business. An item is a single hotel from your website or app. Use a single feed for all the hotels in your catalog, or use multiple feeds where one feed represents hotels in a single country or for a single hotel brand.

Supported Hotel Feed Formats

You must provide this feed in one of these formats:

File Format Description Sample File

CSV, TSV

A simple, compact tabular format you can edit and export by spreadsheet applications. The first row must list your chosen field names in the same order that values appear. Following rows contain corresponding values for each hotel. You should enclose whitespace or commas in "double quotes". You can use JSON-encoded values or a set of flattened, plain-text columns labeled with JSON-path syntax for nested or multi-value. For example you can represent address, neighborhood or image with this format: address.city, neighborhood[0], image[0].url, image[0].tag[0], image[0].tag[1]). Both conventions can be used interchangeably in the same file.

XML

Format typically from an automated feed provider system. A root <listings> XML node encloses a set of <listing> nodes, each of which represents a hotel. The file must begin with a valid <?xml declaration tag.

Download

Facebook's feed parser automatically detect UTF8, UTF16 or UTF32 text-encodings, defaulting to LATIN1 if we find an unexpected byte sequence. Text in field values can be given in any language, field names must be given exactly as below, in English.

Name Type Description Required

hotel_id


Max size: 100

string

Your unique identifier for a hotel in the catalog. We match this with any content_ids provided in your hotel app and pixel events.

Yes

name

string

The most common name of the hotel.

Yes

image


Max items: 20

object

Image for this hotel. You can provide up to 20 images for a hotel. Each image contains two fields: url and tag. You can have multiple tags associated with an image. You must provide at least one image. Each image can be up to 4MB.

Yes

image.url

string

URL of the hotel image. To use carousel ads, provide a square 1:1 aspect ratio image which is 600x600px. To show single hotel ads provide images with 1.91:1 aspect ratio image at 1200x630px.

Yes

image.tag

string

String describing the image. You can have multiple tags per image, such as Fitness Center, Swimming Pool.

No

url

string

Link to the external site where you can book a hotel room

Yes

address

object

Complete address for the hotel that can resolve to its location.

Yes

address.addr1

string

Street address of hotel, such as 675 El Camino Real.

Yes

address.city

string

City hotel is in, such as Palo Alto.

Yes

address.city_id

string

City ID to use in template_url for ad creative if available. For example, if city_id for London is 12345 then template_url is www.example.com/12345/hotels.

No

address.region

string

State, county, region or province for hotel: California.

Yes

address.postal_code

string

Postal or zip-code of the hotel: 94125 or NW1 3FG. Do not omit unless the hotel's country has no postal-code system.

No

address.country

string

Country of the hotel: United States.

Yes

neighborhood

Max items: 20

string

One or more neighborhoods for the hotel: Soho or Las Vegas Strip.

Yes

latitude

float

The latitude of the hotel: 37.484100.

Yes

longitude

float

The longitude of the hotel, such as -122.148252.

Yes

brand

string

Brand of the hotel chain.

Yes

base_price

string

Base price per night for this hotel. You must specify the value with a currency, such as 199.99 USD.

Yes

description

Max size: 5000

string

Describes the hotel.

Yes

sale_price

string

Sale price per night for this hotel. You must specify the value with currency, such as 179.99 USD.

No

guest_ratings

object

Guest ratings for the hotel. If specified, you must provide score, number_of_reviewers and rating_system.

No

guest_ratings.score

float

Value for the hotel rating score: 7.8

No

guest_ratings.number_of_reviewers

int

Number of people who have rated this hotel, such as 300.

No

guest_ratings.rating_system

string

System that provides guest_rating, such as Expedia or TripAdvisor

No

star_rating

float

Hotel star rating. Calid values are between 1 to 5 and should be multiples of 0.5, such as 3 or 4.5

No

loyalty_program

string

Loyalty program for hotel, such as Premium Program

No

margin_level

integer

Indicates profitability of the hotel, value from 1 to 10.

No

phone

string

Phone number

No

applink

element

Applink information. You can provide deep-links for the hotel and display a specific hotel in your mobile app if someone wants more information about it. To do this use App Links. Deep-links in the hotel feed takes precedence over any information in App Links metadata from Facebook's web crawler and from webpages. If you already have deep-link information set up with App Links, you do not need to specify this information in the Hotel Feed. Instead Facebook uses the collected information to display the correct link. To setup deep links in the ad creative see Dynamic Ads For Travel, Ads Management.

No

applink.ios_url

string

A custom scheme for the iOS app: example-ios://electronic

No

applink.ios_app_store_id

string

The app ID for the App Store, such as 1234

No

applink.ios_app_name

string

Name of the app, suitable for display: Electronic Example iOS

No

applink.iphone_url

string

A custom scheme for the iPhone app, such as example-iphone://electronic

No

applink.iphone_app_store_id

string

The app ID for the App Store, such as 5678

No

applink.iphone_app_name

string

The name of the app, suitable for display: Electronic Example iPhone

No

applink.ipad_url

string

A custom scheme for the iPhone app: example-ipad://electronic

No

applink.ipad_app_store_id

string

App ID for the App Store, such as 9010

No

applink.ipad_app_name

string

Name of the app, suitable for display, such as Electronic Example iPad

No

applink.android_url

string

A custom scheme for the Android app: example-android://electronic

No

applink.android_package

string

A fully-qualified package name for intent generation, such as com.electronic

No

applink.android_class

string

A fully-qualified Activity class name for intent generation. For example com.electronic.Example

No

applink.android_app_name

string

The name of the app, suitable for display, such as Electronic Example Android

No

If your business has an iOS app you only need to specify iPhone or iPad app information if they are different apps from your general iOS app


Hotel Room and Pricing

Besides base_price in the hotel feed, you can optionally update hotel room type and pricing based on check-in dates and length of stay.

Name Type Description Required

hotel_id

string

Unique identifier for hotel provided by advertiser. Appears as hotel_id in the hotel feed

Yes

room_id

string

Unique identifier of the room type provided by advertiser

Yes

name

string

Name of the hotel room type

Yes

description

string

Description of the hotel room type

base_price

float

The lowest price of the hotel room, such as 159

Yes

currency

string

Currency used for base_price, price, sale_price, fees, tax and sale_price_tax. Use ISO 4217 currency codes, such as USD

Yes

url

string

Link to the hotel room page

checkin_date

date

Check in date for the price. We support up to 180 days from the date the feed is uploaded. Use ISO‑8601, namely YYYY‑MM‑DD

Yes

length_of_stay

int

Number of nights staying in the hotel for the price. Max value: 14

Yes

price

float

Price based on checkin_date and length_of_stay, such as 180

Yes

tax

float

Tax value for the price

Yes

fees

float

Applicable fee for the price

Yes

sale_price

float

The discounted price if available: 159

sale_price_tax

float

Tax for the sale_price

See Batch Upload Hotel Room Types and Pricing variables to create hotel room types and pricing in batch mode.

Step 3: Update Options

You can refresh hotel information in a catalog these ways:

  1. Scheduled Hotel Feed Fetches
  2. Direct Upload a Hotel Feed
  3. Batch Upload Hotel Room Types
  4. Batch Upload Pricing Variables
  5. Create Hotel through API
  6. Create Hotel Room and Pricing through API

Scheduled Hotel Feed Fetches

Facebook can fetch hotel feeds from your system according to a schedule you define:

use FacebookAds\Object\ProductFeed;
use FacebookAds\Object\Fields\ProductFeedFields;
use FacebookAds\Object\Fields\ProductFeedScheduleFields;

$product_feed = new ProductFeed(null, <PRODUCT_CATALOG_ID>);

$product_feed->setData(array(
  ProductFeedFields::NAME => 'Test Feed',
  ProductFeedFields::SCHEDULE => array(
    ProductFeedScheduleFields::INTERVAL => 'DAILY',
    ProductFeedScheduleFields::URL =>'http://www.example.com/sample_feed.tsv',
    ProductFeedScheduleFields::HOUR => 22,
  ),
));

$product_feed->create();
from facebookads.adobjects.productfeed import ProductFeed

product_feed = ProductFeed(parent_id=<PRODUCT_CATALOG_ID>)

product_feed[ProductFeed.Field.name] = 'Test Feed'
product_feed[ProductFeed.Field.schedule] = {
    'interval': 'DAILY',
    'url': 'http://www.example.com/sample_feed.tsv',
    'hour': 22,
}

product_feed.remote_create()
ProductFeed productFeed = new ProductCatalog(<PRODUCT_CATALOG_ID>, context).createProductFeed()
  .setName("Test Feed")
  .setSchedule("{\"interval\":\"DAILY\",\"url\":\"http://www.example.com/sample_feed.tsv\",\"hour\":\"22\"}")
  .execute();
String product_feed_id = productFeed.getId();
curl \
  -F 'name=Test Feed' \
  -F 'schedule={ 
    "interval": "DAILY", 
    "url": "http:\/\/www.example.com\/sample_feed.tsv", 
    "hour": 22 
  }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<PRODUCT_CATALOG_ID>/product_feeds

The response is:

{ "id" : <PRODUCT_FEED_ID> }

Direct Upload a Hotel Feed

Along with scheduled feed fetches, you can manually do a one-time upload:

curl \
-F "url=http://www.example.com/sample_feed.xml" \
-F "access_token=<ACCESS_TOKEN>" \
https://graph.facebook.com/<API_VERSION>/<PRODUCT_FEED_ID>/uploads

Batch Upload Hotel Room Types

We support creating, updating and deleting room types through a batch upload API. This is the recommended method for uploading large set of room types.

For uploading room types using batch upload:

curl \
-X POST \
-F "standard=google" \
-F file=@hotel_rooms_data_xml.xml \
-F "access_token=<ACCESS_TOKEN>" \
https://graph.facebook.com/<API_VERSION>/<PRODUCT_CATALOG_ID>/hotel_rooms_batch

Supported Format

You can provide the room types in the following format:

File Format Description Sample File

XML

Each hotel is identied by <property> within <PropertyDataSet> XML node and the room type data are represented by <RoomData>. The file must begin with the <?xml declaration tag. Currently we support google complied XML format

Download

Please make sure the hotels you want to provide room types for already existed in the catalog before using the batch upload.

For more details on how to update and delete room types through batch, see Hotel Rooms Batch Reference.


Batch Upload Pricing Variables

We support creating, updating and deleting pricing variables for room types through batch upload API. This is the recommended method for uploading large pricing variables.

You can use this batch API to provide pricing variables even you don't have room types.

For uploading pricing variables, using batch upload:

curl \
-X POST \
-F "standard=google" \
-F file=@pricings_data_xml.xml \
-F "access_token=<ACCESS_TOKEN>" \
https://graph.facebook.com/<API_VERSION>/<PRODUCT_CATALOG_ID>/pricing_variables_batch

Supported Format

You can provide the pricing variables in the following format:

File Format Description Sample File

XML

Pricing variables for room types. You have already created room types for hotels, now you can specify pricing (<Baserate>) within each room type (<RoomBundle>) based on the combination of check in date (<Checkin>) and length of stay (<Nights>).


The file must begin with the <?xml declaration tag. Currently we support google complied XML format

Download

XML

Pricing variables without room types (i.e. you have already created hotels with base_price, but don't have room type informaiton, like airbnb). You can specify pricing (<Baserate>) for each combination of hotel id (<Property>), check in date (<Checkin>), and length of stay (<Nights>).


The file must begin with the <?xml declaration tag. Currently we support google complied XML format

Download

  • Please make sure the hotels and/or room types you want to provide pricing variables for already existed in the catalog before using the batch upload.

  • For batch APIs, please keep it up to 50MB per file (roughly 50,000 items in a file). We recommend frequent smaller updates for pricing variables.

For more details on how to update and delete pricing variables through batch, see Pricing Variable Batch Reference.


Create Hotel through API

To create a hotel item in your catalog through API:

use FacebookAds\Object\Hotel;
use FacebookAds\Object\Fields\HotelFields;

$hotel = new Hotel(null, <PRODUCT_CATALOG_ID>);

$hotel->setData(array(
  HotelFields::HOTEL_ID => 'h_1',
  HotelFields::NAME => 'Sample Hotel',
  HotelFields::DESCRIPTION => 'hotel description',
  HotelFields::BRAND => 'hotel brand',
  HotelFields::URL => 'http://www.example.com/samplehotel',
  HotelFields::IMAGES => array(
    array(
      'image_url' => 'http://www.example.com/pic1.jpg',
      'tags' => array('front view', 'balcony'),
    ),
    array(
      'image_url' => 'http://www.example.com/pic2.jpg',
      'tags' => array('lobby view'),
    ),
  ),
  HotelFields::ADDRESS => array(
    'street_address' => '1 Hacker Way',
    'city' => 'Menlo Park',
    'region' => 'California',
    'country' => 'United States',
    'postal_code' => '94025',
    'neighborhoods' => array('Palo Alto', 'Menlo Park'),
    'latitude' => 37.484116,
    'longitude' => -122.148244,
  ),
  HotelFields::GUEST_RATINGS => array(
    array(
      'score' => 7.8,
      'rating_system' => 'sample_rating',
      'number_of_raters' => 780,
    ),
  ),
  HotelFields::STAR_RATING => 4,
  HotelFields::PHONE => '+351234123456',
));

$hotel->create();
from facebookads.adobjects.hotel import Hotel

hotel = Hotel(None, <PRODUCT_CATALOG_ID>)
hotel.update({
    Hotel.Field.hotel_id: 'h_1',
    Hotel.Field.name: 'Sample Hotel',
    Hotel.Field.description: 'hotel description',
    Hotel.Field.brand: 'hotel brand',
    Hotel.Field.url: 'http://www.example.com/samplehotel',
    Hotel.Field.images: [
        {
            'image_url': 'http://www.example.com/pic1.jpg',
            'tags': ['front view','balcony'],
        },
        {
            'image_url': 'http://www.example.com/pic2.jpg',
            'tags': ['lobby view'],
        },
    ],
    Hotel.Field.address: {
        'street_address': '1 Hacker Way',
        'city': 'Menlo Park',
        'region': 'California',
        'country': 'United States',
        'postal_code': '94025',
        'neighborhoods': ['Palo Alto', 'Menlo Park'],
        'latitude': 37.484116,
        'longitude': -122.148244,
    },
    Hotel.Field.guest_ratings: [
        {
            'score': 7.8,
            'rating_system': 'sample_rating',
            'number_of_raters': 780,
        },
    ],
    Hotel.Field.star_rating: 4,
    Hotel.Field.phone: '+351234123456',
})

hotel.remote_create()
curl \
  -F 'hotel_id=h_1' \
  -F 'name=Sample Hotel' \
  -F 'description=hotel description' \
  -F 'brand=hotel brand' \
  -F 'url=http://www.example.com/samplehotel' \
  -F 'images=[ 
    { 
      "image_url": "http:\/\/www.example.com\/pic1.jpg", 
      "tags": ["front view","balcony"] 
    }, 
    {"image_url":"http:\/\/www.example.com\/pic2.jpg","tags":["lobby view"]} 
  ]' \
  -F 'address={ 
    "street_address": "1 Hacker Way", 
    "city": "Menlo Park", 
    "region": "California", 
    "country": "United States", 
    "postal_code": "94025", 
    "neighborhoods": ["Palo Alto","Menlo Park"], 
    "latitude": 37.484116, 
    "longitude": -122.148244 
  }' \
  -F 'guest_ratings=[ 
    { 
      "score": 7.8, 
      "rating_system": "sample_rating", 
      "number_of_raters": 780 
    } 
  ]' \
  -F 'star_rating=4' \
  -F 'phone=+351234123456' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<PRODUCT_CATALOG_ID>/hotels

For more details on how to update and delete a hotel, see Hotel Reference.


Create Hotel Room Type and Pricing through API

Optionally, you can update room type and pricing configurations more frequently to provide up-to-date pricing info.

To create a hotel room type and multiple pricing configurations:

use FacebookAds\Object\HotelRoom;
use FacebookAds\Object\Fields\HotelRoomFields;

$hotelroom = new HotelRoom(null, <HOTEL_ID>);
$hotelroom->setData(array(
  HotelRoomFields::ROOM_ID => 'r_3',
  HotelRoomFields::NAME => 'Sample room type',
  HotelRoomFields::DESCRIPTION => 'room type description',
  HotelRoomFields::URL => 'http://www.example.com/sampleroom',
  HotelRoomFields::BASE_PRICE => '15900',
  HotelRoomFields::CURRENCY => 'USD',
  'pricing_variables' => array(
    array(
      'checkin_date' => (new \DateTime("+3 day"))->format('Y-m-d'),
      'nights' => 1,
      'price' => 170,
      'fees' => 10,
      'tax' => 14,
    ),
    array(
      'checkin_date' => (new \DateTime("+3 day"))->format('Y-m-d'),
      'nights' => 2,
      'price' => 330,
      'fees' => 10,
      'tax' => 20,
    ),
    array(
      'checkin_date' => (new \DateTime("+4 day"))->format('Y-m-d'),
      'nights' => 1,
      'price' => 160,
      'fees' => 10,
      'tax' => 13,
    ),
  ),
));

$hotelroom->create();
from facebookads.adobjects.hotelroom import HotelRoom
import datetime

hotel_room = HotelRoom(None, hotel_fbid)
hotel_room.update({
    HotelRoom.Field.room_id: 'r_3',
    HotelRoom.Field.name: 'Sample room type',
    HotelRoom.Field.description: 'room type description',
    HotelRoom.Field.url: 'http://www.example.com/sampleroom',
    HotelRoom.Field.base_price: 15900,
    HotelRoom.Field.currency: 'USD',
    'pricing_variables': [
        {
            'checkin_date':
                str(datetime.date.today() + datetime.timedelta(days=3)),
            'nights': 1,
            'price': 170,
            'fees': 10,
            'tax': 14,
        },
        {
            'checkin_date':
                str(datetime.date.today() + datetime.timedelta(days=3)),
            'nights': 2,
            'price': 330,
            'fees': 10,
            'tax': 20,
        },
        {
            'checkin_date':
                str(datetime.date.today() + datetime.timedelta(days=4)),
            'nights': 1,
            'price': 160,
            'fees': 10,
            'tax': 13,
        },
    ],
})

hotel_room.remote_create()
curl \
  -F 'room_id=r_3' \
  -F 'name=Sample room type' \
  -F 'description=room type description' \
  -F 'url=http://www.example.com/sampleroom' \
  -F 'base_price=15900' \
  -F 'currency=USD' \
  -F 'pricing_variables=[ 
    { 
      "checkin_date": "2017-09-17", 
      "nights": 1, 
      "price": 170, 
      "fees": 10, 
      "tax": 14 
    }, 
    { 
      "checkin_date": "2017-09-17", 
      "nights": 2, 
      "price": 330, 
      "fees": 10, 
      "tax": 20 
    }, 
    { 
      "checkin_date": "2017-09-18", 
      "nights": 1, 
      "price": 160, 
      "fees": 10, 
      "tax": 13 
    } 
  ]' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<HOTEL_ID>/hotel_rooms

Please use different values for hotel_id and room_id as best practice

For more details on how to update and delete a hotel room type, see Hotel Room Reference.

Step 4: Filter Hotel Catalog to Hotel Sets

Reference Docs

A hotel set is a set of hotel items in a hotel catalog that you advertise in a dynamic ad. Each hotel catalog can have many hotel sets.

Hotel sets are defined by filters in a hotel catalog. For example, you can create a hotel set that matches hotels with star_rating greater than 3 or a hotel set that matches specific hotel IDs. Please note that regex_match filter rule is not supported for hotel set.

To create a hotel set containing all the hotels with 'sample brand' mentioned in the brand field:

use FacebookAds\Object\ProductSet;
use FacebookAds\Object\Fields\ProductSetFields;

$hotel_set = new ProductSet(null, <PRODUCT_CATALOG_ID>);

$hotel_set->setData(array(
  ProductSetFields::NAME => 'Test Hotel Set',
  ProductSetFields::FILTER => array(
    'brand' => array(
      'i_contains' => 'sample brand',
    ),
  ),
));

$hotel_set->create();
from facebookads.adobjects.productset import ProductSet

hotel_set = ProductSet(None, <PRODUCT_CATALOG_ID>)

hotel_set[ProductSet.Field.name] = 'Test Hotel Set'
hotel_set[ProductSet.Field.filter] = {
    'brand': {
        'i_contains': 'sample brand',
    },
}

hotel_set.remote_create()
curl \
  -F 'name=Test Hotel Set' \
  -F 'filter={"brand":{"i_contains":"sample brand"}}' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<PRODUCT_CATALOG_ID>/product_sets

The above filter is made up of the following operators and data:

Operators The type of filter

i_contains

Contains substring (case insensitive)

i_not_contains

Does not contain substring (case insensitive)

contains

Contains substring (case insensitive)

not_contains

Does not contain substring (case insensitive)

eq

Equal to (case insensitive)

neq

Not equal to (case insensitive)

lt

Less than (numeric fields only)

lte

Less than or equal to (numeric fields only)

gt

Greater than (numeric fields only)

gte

Greater than or equal to (numeric fields only)

Data The data being filtered.

hotel_id

Your unique identifer of the hotel in the catalog

brand

hotel brand

base_price_amount

Base price per night for this hotel. The price is in cents (4999 denotes $49.99).

sale_price_amount

Sale price per night for this hotel. The price is in cents (4999 denotes $49.99).

currency

Currency

city

City hotel is in, such as Palo Alto

country

Hotel address - country. E.g. United States

name

Hotel name

star_rating

Hotel star rating. The valid values are between 1 to 5, e.g. 4

Destination Catalog

Step 1: Create Destination Catalog

A destination catalog contains a list of destinations that you would like to advertise.

To create a destination catalog for Dynamic Ads for travel, set vertical to destinations:

use FacebookAds\Object\ProductCatalog;
use FacebookAds\Object\Fields\ProductCatalogFields;
use FacebookAds\Object\Values\ProductCatalogVerticalValues;

$product_catalog = new ProductCatalog(null, <BUSINESS_ID>);

$product_catalog->setData(array(
  ProductCatalogFields::NAME => "Destination Catalog",
  ProductCatalogFields::VERTICAL => ProductCatalogVerticalValues::DESTINATIONS,
));

$product_catalog->create();
from facebookads.adobjects.productcatalog import ProductCatalog

product_catalog = ProductCatalog(parent_id=<BUSINESS_ID>)

product_catalog[ProductCatalog.Field.name] = 'Destination Catalog'
product_catalog[ProductCatalog.Field.vertical] = 'destinations'

product_catalog.remote_create()
curl \
  -F 'name=Destination Catalog' \
  -F 'vertical=destinations' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<BUSINESS_ID>/product_catalogs

To use the product catalog API, please make sure you have the appropriate Marketing API Access Level and that you have accepted the Terms of Service by creating your first catalog through Business Manager.

Step 2: Setup Destination

Destination Feed

A destination feed is a set of destination items uploaded or fetched from your business. A destination item is a single destination presented in your website or app. You can have a single feed to provide information on all the destinations in your catalog. Or you can have multiple feeds where one feed represents destinations in a single country.

Supported Destination Feed Formats

You must provide the destination feed in one of these formats:

File Format Description Sample File

CSV, TSV

Comma/Tab separated file. The first row specifies the column header. Subsequent rows then supply the corresponding values for each destination. Fields containing whitespace or commas should be enclosed in "double quotes". Nested or multi-value fields such as address, neighborhood or image can be represented using JSON-encoded values or by a set of "flattened" plain-text columns labelled using JSON-path syntax (e.g. address.city, neighborhood[0], image[0].url, image[0].tag[0], image[0].tag[1]). Both conventions can be used interchangeably in the same file.

XML

A root <listings> XML node encloses a set of <listing> nodes, each of which represents a destination.


The file must begin with the <?xml declaration tag.

Download

The feed parser will automatically detect UTF8, UTF16 or UTF32 text-encodings, falling back to LATIN1 if an unexpected byte sequences is encountered. Whilst text in field values can be given in any language, field names/labels must be given exactly as below, in English.

Name Type Description Required

destination_id
Max size: 100

string

Your unique identifier for the destination within the catalog. This will be matched with any content_ids provided in your destination app and pixel events.

Yes

name

string

The most common name of the destination.

Yes

address

object

A complete address for the destination that must be resolvable to its location.

Yes

address.addr1

string

Street address of this destination, e.g. 675 El Camino Real.

No

address.city

string

City of this destination, e.g. Palo Alto.

Yes

address.region

string

State, county, region or province of this destination, e.g. California.

Yes

address.country

string

Country of the destination, e.g. United States.

Yes

address.postal_code

string

Postal or zip-code of the destination, e.g. 94125 or NW1 3FG. This is applicable for lower level destination, e.g. landmarks, and can be omitted for countries without a postal-code system.

No

latitude

float

The latitude of the destination, e.g. 37.484100.

No

longitude

float

The longitude of the destination, e.g. -122.148252.

No

neighborhood


Max items: 20

string

One or more neighborhood(s) for the destination, e.g. Soho or Las Vegas Strip.

No

image


Max items: 20

object

Image data for this destination. You can provide up to 20 images for the destination. Each image contains two fields: url and tag of the image. You can have multiple tags associated with an image. You must provide at least one image. Each image can be up to 4MB in size.

Yes

image.url

string

The url of the destination image. Note if you want to use carousel ads, provide a square 1:1 aspect ratio images which are 600x600px. To show single destination ads provide images with 1.91:1 aspect ratio image at 1200x630px

Yes

image.tag

string

A string that describes what\'s in the image. There can be multiple tags associated with an image, such as Land.

No

type


Max items: 20

string

The type(s) of destination , e.g. beach, city, food, sightseeing, culture, history, shopping, museum, tranquility, scenery, nature, architecture, business, friendly people, relaxation, night market, mountain, temple, hiking, snorkeling ...etc). There can be multiple types associated with a destination (i.e. a destination can have multiple attributes such as beach and sightseeing).

Yes

url

string

Link to the external site where you can view destination page.

Yes

price

string

Can be lowest or average price for this destination, such as "Hotels in NYC from $199.99", "Lowest airfare to this destination". You must specify the value with currency, such as 199.99 USD.

No

price_change

int

Specify the price change:

  • 0: No price change
  • -10: 10% price drop
  • 20: 20% price increase

This can be used for building product sets and in the ad creative (e.g. "average price in NYC dropped by X" or "average price in NYC dropped").

No

description


Max size: 5000

string

A short paragraph describing the destination.

No

applink

element

Applink information. You can provide deep link information about the hotel. This enables you to display a specific hotel in your mobile app if someone wants more information about it. To do this use App Links specification. Deep link information in the hotel feed takes precedence over any information that has been collected through App Links metadata by our web crawler from within webpages. If deep link information is already available via having implemented App Links, specifying this data in the Hotel Feed is not necessary as we will use the collected information to display the correct outbound link. To setup deep links in the ad creative see the Dynamic Creative document

No

applink.ios_url

string

A custom scheme for the iOS app. E.g. example-ios://electronic

No

applink.ios_app_store_id

string

The app ID for the App Store. E.g. 1234

No

applink.ios_app_name

string

The name of the app (suitable for display). E.g. Electronic Example iOS

No

applink.iphone_url

string

A custom scheme for the iPhone app. E.g. example-iphone://electronic

No

applink.iphone_app_store_id

string

The app ID for the App Store. E.g. 5678

No

applink.iphone_app_name

string

The name of the app (suitable for display). E.g. Electronic Example iPhone

No

applink.ipad_url

string

A custom scheme for the iPhone app. E.g. example-ipad://electronic

No

applink.ipad_app_store_id

string

The app ID for the App Store. E.g. 9010

No

applink.ipad_app_name

string

The name of the app (suitable for display). E.g. Electronic Example iPad

No

applink.android_url

string

A custom scheme for the Android app. E.g. example-android://electronic

No

applink.android_package

string

A fully-qualified package name for intent generation. E.g. com.electronic

No

applink.android_class

string

A fully-qualified Activity class name for intent generation. E.g. com.electronic.Example

No

applink.android_app_name

string

The name of the app (suitable for display). E.g. Electronic Example Android

No

If your business has an iOS app you only need to specify iPhone or iPad app information if they are different apps from your general iOS app

Step 3: Update Options

Scheduled Destination Feed Fetches

Similar to hotel feed, Facebook can fetch destination feeds from your system according to a schedule you define. More details here

Direct Upload a Destination Feed

Along with scheduled feed fetches, you can manually do a one-time upload. More details here.

Step 4: Filter Destination Catalog to Destination Sets

A destination set is a set of items in a destination catalog that you advertise in a dynamic ad. Each destination catalog can have many destination sets.

As with hotel sets, destination sets are defined by filters in a destination catalog. For example, you can create a destination set that matches destinations with price_change dropped more than 20%:

use FacebookAds\Object\ProductSet;
use FacebookAds\Object\Fields\ProductSetFields;

$destination_set = new ProductSet(null, <PRODUCT_CATALOG_ID>);

$destination_set->setData(array(
  ProductSetFields::NAME => 'Test Destination Set',
  ProductSetFields::FILTER => array(
    'price_change' => array(
      'lt' => -20,
    ),
  ),
));

$destination_set->create();
from facebookads.adobjects.productset import ProductSet

destination_set = ProductSet(None, <PRODUCT_CATALOG_ID>)

destination_set[ProductSet.Field.name] = 'Test Destination Set'
destination_set[ProductSet.Field.filter] = {
    'price_change': {
        'lt': -20,
    },
}

destination_set.remote_create()
curl \
  -F 'name=Test Destination Set' \
  -F 'filter={"price_change":{"lt":-20}}' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<PRODUCT_CATALOG_ID>/product_sets

The above filter is made up of the following operators and data:

Operators The type of filter

i_contains

Contains substring (case insensitive)

i_not_contains

Does not contain substring (case insensitive)

contains

Contains substring (case insensitive)

not_contains

Does not contain substring (case insensitive)

eq

Equal to (case insensitive)

neq

Not equal to (case insensitive)

lt

Less than (numeric fields only)

lte

Less than or equal to (numeric fields only)

gt

Greater than (numeric fields only)

gte

Greater than or equal to (numeric fields only)

Data The data being filtered

country

Country, e.g. United States

price

Price for this destination

currency

Currency

price_change

Price drop or increase. E.g. building a destination set whose average price is dropped

Flight Catalog

Step 1: Create Flight Catalog

A flight catalog contains a list of flights (routes) that you would like to advertise.

To create a flight catalog for Dynamic Ads for travel, set vertical to flights:

use FacebookAds\Object\ProductCatalog;
use FacebookAds\Object\Fields\ProductCatalogFields;
use FacebookAds\Object\Values\ProductCatalogVerticalValues;

$product_catalog = new ProductCatalog(null, <BUSINESS_ID>);

$product_catalog->setData(array(
  ProductCatalogFields::NAME => "Flight Catalog",
  ProductCatalogFields::VERTICAL => "flights",
));

$product_catalog->create();
from facebookads.adobjects.productcatalog import ProductCatalog

product_catalog = ProductCatalog(parent_id=<BUSINESS_ID>)

product_catalog[ProductCatalog.Field.name] = 'Flight Catalog'
product_catalog[ProductCatalog.Field.vertical] = 'flights'

product_catalog.remote_create()
curl \
  -F 'name=Flight Catalog' \
  -F 'vertical=flights' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<BUSINESS_ID>/product_catalogs

To use the product catalog API, please make sure you have the appropriate Marketing API Access Level and that you have accepted the Terms of Service by creating your first catalog through Business Manager.

Step 2: Setup Flight

Flight Feed

A flight feed is a set of flights(routes) uploaded or fetched from your business. A flight item is a single flight presented in your website or app. You can have a single feed to provide information on all the flights in your catalog or you can have multiple feeds where one feed represents flights to/from specific airport.

There are multiple ways to setup flight feeds into your catalog:

1. Upload flight feed

To set up flight feed, advertiser can upload flight feed using supported feed formats below

2. Use events activity to generate flight routes

Automatically populate flight feed routes using flight pixel / app events. See Generate feed using pixel / app events for details.

3. Combined catalog

You can choose to populate flight routes in feed by autogenerating flight route (using pixel / app events) and upload flight feed later. Alternate option is to start by uploading flight feed, run ads and autogenerate more flight routes using pixel / app events. Hence, use a combination of above options to create a combined flight feed using feed file upload + autogenerated routes from pixel / app events.

Upload flight feed - Supported Flight Feed Formats

You must provide the flight feed in one of these formats:

File Format Description Sample File

CSV, TSV

Comma/Tab separated file. The first row specifies the column header. Subsequent rows then supply the corresponding values for each route. Fields containing whitespace or commas should be enclosed in "double quotes". Nested or multi-value fields such as image can be represented using JSON-encoded values or by a set of "flattened" plain-text columns labelled using JSON-path syntax (e.g. image[0].url, image[0].tag[0], image[0].tag[1]). Both conventions can be used interchangeably in the same file.

XML

A root <listings> XML node encloses a set of <listing> nodes, each of which represents a route.


The file must begin with the <?xml declaration tag.

Download

The feed parser will automatically detect UTF8, UTF16 or UTF32 text-encodings, falling back to LATIN1 if an unexpected byte sequences is encountered. Whilst text in field values can be given in any language, field names/labels must be given exactly as below, in English.

Name Type Description Required

origin_airport

string

The IATA code for the origin, such as SFO

Yes

origin_city

string

Name of the origin city, such as San Francisco

No

destination_airport

string

The IATA code for the destination, such as JFK

Yes

destination_city

string

Name of the destination city, such as New York City

No

image


Max items: 20

object

Image data for this flight. You can provide up to 20 images for the flight. Each image contains two fields: url and tag of the image. You can have multiple tags associated with an image. You must provide at least one image. Each image can be up to 4MB in size.

Yes

image.url

string

The url of the flight image. Note if you want to use carousel ads, provide a square 1:1 aspect ratio images which are 600x600px. To show single flight ads provide images with 1.91:1 aspect ratio image at 1200x630px

Yes

image.tag

string

A string that describes what\'s in the image. There can be multiple tags associated with an image, such as Land.

No

description


Max size: 5000

string

A short paragraph describing the route.

No

price

string

Price of the flight.

No

url

string

Link to the external site where you can view flight page. Deep link in ad creative takes precedence if both provided.

No, unless you do not specify "Deep Link on Desktop" in Ads Manager or Power Editor or template_url_spec in API in ad creative.)

applink

element

Provide deep link information about the flight. This enables you to display a specific flight in your mobile app if someone wants more information. Use App Links. Deep link information in the flight feed takes precedence over any information in webpages collected in App Links metadata by our web crawler. If deep link information is available via App Links, you do not need to specify this data in the Flight Feed. We will use collected information to display the correct outbound link. To setup deep links in ad creative see Dynamic Creative

No

applink.ios_url

string

A custom scheme for the iOS app. E.g. example-ios://flight_search

No

applink.ios_app_store_id

string

The app ID for the App Store. E.g. 1234

No

applink.ios_app_name

string

The name of the app (suitable for display). E.g. Global Voyager Air App for iOS

No

applink.iphone_url

string

A custom scheme for the iPhone app. E.g. example-iphone://flight_search

No

applink.iphone_app_store_id

string

The app ID for the App Store. E.g. 5678

No

applink.iphone_app_name

string

The name of the app (suitable for display). E.g. Global Voyager Air App for iPhone

No

applink.ipad_url

string

A custom scheme for the iPhone app. E.g. example-ipad://flight_search

No

applink.ipad_app_store_id

string

The app ID for the App Store. E.g. 9010

No

applink.ipad_app_name

string

The name of the app (suitable for display). E.g. Global Voyager Air App for iPad

No

applink.android_url

string

A custom scheme for the Android app. E.g. example-android://flight_search

No

applink.android_package

string

A fully-qualified package name for intent generation. E.g. com.globalvoyager

No

applink.android_class

string

A fully-qualified Activity class name for intent generation. E.g. com.globalvoyager.Example

No

applink.android_app_name

string

The name of the app (suitable for display). E.g. Global Voyager Air App for Android

No

If your business has an iOS app only specify iPhone or iPad app information if they are different apps from your general iOS app.

Generate feed using pixel / app events

To generate flight feed routes using pixel / app events, advertiser must set up valid flight events. See Build Audience for flight events.

Advertiser can follow the steps below to autogenerate flight feed.

Set the 'generate_items_from_events' bool on the Flight Catalog

curl \
-F 'flight_catalog_settings={'generate_items_from_events'=1} \
-F 'access_token=<ACCESS_TOKEN>>' \
https://graph.facebook.com/<VERSION>/<CATALOG_ID>

You can provide a single image for all of your autogenerated flight routes hence a generic image should be used.

curl \
-F 'fallback_image_url=http://example.com/some.image_1.jpg' \
-F 'access_token=<ACCESS_TOKEN>' \
https://graph.facebook.com/<VERSION>/<CATALOG_ID>

After you associate Facebook pixel or App Events with your flight catalog, we start populating your catalog with flights generated from pixel or app data. See Build Audiences for details on setting up flight pixel events.

You can now query your catalog to to see added flights:

curl \
-F 'access_token=<ACCESS_TOKEN>' \
https://graph.facebook.com/<VERSION>/flights

Step 3: Update Options

Scheduled Flight Feed Fetches

Similar to hotel feed, Facebook can fetch flight feeds from your system according to a schedule you define. More details here

Direct Upload a Flight Feed

Along with scheduled feed fetches, you can manually do a one-time upload. More details here.

Step 4: Filter Flight Catalog to Flight Sets

A flight set is a set of items in a flight catalog that you advertise in a dynamic ad. Each flight catalog can have many flight sets.

use FacebookAds\Object\ProductSet;
use FacebookAds\Object\Fields\ProductSetFields;

$flight_set = new ProductSet(null, <PRODUCT_CATALOG_ID>);

$flight_set->setData(array(
  ProductSetFields::NAME => 'Test Flight Set',
  ProductSetFields::FILTER => array(
    'origin_airport' => array(
      'eq' => 'LHR',
    ),
  ),
));

$flight_set->create();
from facebookads.adobjects.productset import ProductSet

flight_set = ProductSet(None, <PRODUCT_CATALOG_ID>)

flight_set[ProductSet.Field.name] = 'Test Flights Set'
flight_set[ProductSet.Field.filter] = {
    'origin_airport': {
        'eq': 'SFO',
    },
}

flight_set.remote_create()
curl \
  -F 'name=Test Flight Set' \
  -F 'filter={"origin_airport":{"eq":"LHR"}}' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<PRODUCT_CATALOG_ID>/product_sets

Provide these operators and data in filter:

Operators Type of filter

i_contains

Contains substring, case-insensitive

i_not_contains

Does not contain substring, case-insensitive

contains

Contains substring, case-insensitive

not_contains

Does not contain substring, case-insensitive

eq

Equal to, case-insensitive

neq

Not equal to, case-insensitive

lt

Less than (numeric fields only)

lte

Less than or equal to. Numeric fields only

gt

Greater than. Numeric fields only

gte

Greater than or equal to. Numeric fields only

Data Data to filter

origin_airport

IATA code for flight departure, such as SFO

destination_airport

IATA code for destination. such as JFK

price

Flight price

description

Route description.