Hotel Ads - Catalogs & Feed

To promote your hotel inventory on Facebook, you have to share information about your hotels with Facebook. You do this by creating a hotel catalog and then filling it with hotels. There are two ways to fill your catalog and keep it up to date

  1. Upload CSV or XML files for 'hotel feeds' with your hotel inventory
  2. Create and manage hotels directly in API

You can create and manage your hotel catalogs in your catalog manager. To use the API to manage your catalog:

  1. Create a hotel catalog
  2. Upload your feed to Facebook
  3. Create product sets out of your hotel catalog
  4. Associate the catalog to your event sources

Hotel Feeds - Upload Your Hotels to Facebook

A hotel feed is a file with your hotel inventory. Every line or item in the file represents a single hotel. You can use one or more hotel feeds, as long as all feeds together contain your full hotel inventory.

Supported Hotel Feed Formats

CSV

CSV sample | TSV sample (flattened) | TSV sample (JSON style)

  • The first row must list the chosen field names in the order the values are given. Subsequent rows then supply the corresponding values for each hotel.
  • 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 labeled using JSON-path syntax, such as 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

XML sample

  • 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.

The feed parser automatically detects UTF8, UTF16 or UTF32 text-encodings, and defaults to to LATIN1 if it encounters an unexpected byte sequences. You can provide text in field values in any language, however field names must be given exactly as below, in English.

Hotel Feed Fields

Field Name and TypeDescription

hotel_id

type: string

Required.

Max length: 1000

Your unique identifier for the hotel within the catalog. This ID is matched with any content_ids provided in your hotel app and pixel events.

name

type: string

Required.

The most common name of the hotel.

image

type: object

Required.

Max items: 20

Image data for this hotel. You can provide up to 20 images for the 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 4 MB in size.

See Image Object Parameters

url

type: string

Required.

Link to the external site where you can book a hotel room. You can also specify a URL on ad level using template_url_spec. URLs on the ad level take precedence over URLs in the feed.

address

type: object

Required.

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

See Address Object Parameters

neighborhood

type: string

Required.

Max items: 20

One or more neighborhoods for the hotel.

Examples:

  • Soho
  • Las Vegas Strip

latitude

type: float

Required.

The latitude of the hotel.

Example: 37.484100

longitude

type: float

Required.

The longitude of the hotel.

Example: -122.148252

brand

type: string

Required.

Brand of the hotel chain.

base_price

type: string

Required.

Base price per night for this hotel. You must specify the value with currency.

Example: 199.99 USD

description

type: string

Required.

Max size: 5000

A short paragraph describing the hotel.

sale_price

type: string

Sale price per night for this hotel. You must specify the value with currency. Make sure the sale_price of a hotel is lower than its base_price.

Example: 179.99 USD.

guest_ratings

type: object

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

See Guest Ratings Object Parameters

star_rating

type: float

Hotel star rating. The valid values are between 1 to 5 and should be a multiple of 0.5.

Example: 3, 4.5

loyalty_program

type: string

The loyalty program you can get points for by staying in this hotel.

Example: Premium program

margin_level

type: integer

An indicator of the profitability of the hotel; value from 1 to 10.

phone

type: string

Phone number

applink

type: object

Deep link straight to the hotel details page in your mobile app using App Links. You can specify deep links in order of precedence, highest to lowest:

  1. On ad level using template_url_spec
  2. Here in the feed using an Applink Object
  3. By adding App Link meta tags to your website.

Image Object Parameters

Field Name and TypeDescription

url

type: string

Required.

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

tag

type: string

A string that represents what's in the image. There can be multiple tags associated with an image.

Examples:

  • Fitness Center
  • Swimming Pool

Optional. INSTAGRAM_STANDARD_PREFERRED - Allows advertisers to tag a specific image in their feed as the default image that will be used for Instagram. This tag is case sensitive.

Address Object Parameters

Field Name and TypeDescription

addr1

type: string

Required.

Street address of hotel.

Example: 675 El Camino Real

city

type: string

Required.

City where hotel is located.

Example: Palo Alto

region

type: string

Required.

State, county, region or province for hotel.

Example: California

country

type: string

Required.

Country of the hotel.

Example: United States

postal_code

type: string

Postal or zip code of the hotel. Required unless country does not have a postal code system.

Examples:

  • 94125
  • NW1 3FG

city_id

type: string

Value to use in deep link URL, template_url, in ad creative.

Guest_ratings Object Parameters

Field Name and TypeDescription

score
type: float

Required.

Value for the hotel rating score.

Example: 7.8

number_of_reviewers
type: int

Required. Number of people who have rated this hotel.

Example: 300

rating_system

type: string

Required.

Specify the system the guest_rating is based on.

Examples:

  • Expedia
  • TripAdvisor

max_score

type: int

Required.


Max value for the hotel rating score. Must be greater than or equal to 0, and less than or equal to 100.


Example: 10

If you have separate apps for iPhone and iPad, specify iPhone and iPad specific information. Otherwise specify only iOS information.

Field Name and TypeDescription

ios_url

type: string

A custom scheme for the iOS app.

Example: example-ios://electronic

ios_app_store_id

type: string

The app ID for the App Store.

Example: 1234

ios_app_name

type: string

The name of the app (suitable for display).

Example: Electronic Example iOS

iphone_url

type: string

A custom scheme for the iPhone app.

Example: example-iphone://electronic

iphone_app_store_id

type: string

The app ID for the App Store.

Example: 5678

iphone_app_name

type:string

The name of the app (suitable for display).

Example: Electronic Example iPhone

ipad_url

type: string

A custom scheme for the iPhone app.

Example: example-ipad://electronic

ipad_app_store_id

type: string

The app ID for the App Store.

Example: 9010

ipad_app_name

type: string

The name of the app (suitable for display).

Example: Electronic Example iPad

android_url

type: string

A custom scheme for the Android app.

Example: example-android://electronic

android_package

type: string

A fully-qualified package name for intent generation.

Exammple: com.electronic

android_class

type: string

A fully-qualified Activity class name for intent generation.

Example: com.electronic.Example

android_app_name

type: string

The name of the app (suitable for display).

Example: Electronic Example Android

Hotel API - Create and Manage Hotels Directly

You can use the Hotel API to directly add, edit, and remove hotels in your catalog. Use the Hotel API Reference for more information on how to manage hotels using the API.

The following sections are only relevant to manage your catalogs using this API.

Create a Hotel Catalog Using the API

A hotel catalog is a container for your hotel inventory. To use the catalog API, 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.

To create a hotel catalog for hotel ads, set vertical to hotels:

curl -X POST \ -F 'name="Test Hotel Catalog"' \ -F 'vertical="hotels"' \ -F 'access_token=<ACCESS_TOKEN>' \ https://graph.facebook.com/v3.2/{business-id}/owned_product_catalogs
'use strict'; const bizSdk = require('facebook-nodejs-business-sdk'); const Business = bizSdk.Business; const ProductCatalog = bizSdk.ProductCatalog; const access_token = '<ACCESS_TOKEN>'; const app_secret = '<APP_SECRET>'; const app_id = '<APP_ID>'; const id = '<ID>'; const api = bizSdk.FacebookAdsApi.init(access_token); const showDebugingInfo = true; // Setting this to true shows more debugging info. if (showDebugingInfo) { api.setDebug(true); } const logApiCallResult = (apiCallName, data) => { console.log(apiCallName); if (showDebugingInfo) { console.log('Data:' + JSON.stringify(data)); } }; let fields, params; fields = [ ]; params = { 'name' : 'Test Hotel Catalog', 'vertical' : 'hotels', }; const owned_product_catalogs = (new Business(id)).createOwnedProductCatalog( fields, params ); logApiCallResult('owned_product_catalogs api call complete.', owned_product_catalogs);
require __DIR__ . '/vendor/autoload.php'; use FacebookAds\Object\Business; use FacebookAds\Object\ProductCatalog; 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' => 'Test Hotel Catalog', 'vertical' => 'hotels', ); echo json_encode((new Business($id))->createOwnedProductCatalog( $fields, $params )->exportAllData(), JSON_PRETTY_PRINT);
from facebook_business.adobjects.business import Business from facebook_business.adobjects.productcatalog import ProductCatalog from facebook_business.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': 'Test Hotel Catalog', 'vertical': 'hotels', } print Business(id).create_owned_product_catalog( 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 Business(id, context).createOwnedProductCatalog() .setName(\"Test Hotel Catalog\") .setVertical(ProductCatalog.EnumVertical.VALUE_HOTELS) .execute(); } }
require 'facebook_ads' 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 business = FacebookAds::Business.get(id) owned_product_catalogs = business.owned_product_catalogs.create({ name: 'Test Hotel Catalog', vertical: 'hotels', })

Upload Your Hotel Feeds via the API

Once you've created the catalog, you must upload your hotel feed(s) to Facebook. Use the API to create a feed object for every feed you want to upload. We support scheduled and direct uploads.

For scheduled uploads, specify a schedule when you create the feed. For non scheduled uploads, don't specify a schedule.

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.11/<PRODUCT_CATALOG_ID>/product_feeds

In either case, the response is:

{ "id" : <PRODUCT_FEED_ID> }

Once you have created the feed (with or without schedule), you can do a one time upload of your feed using the PRODUCT_FEED_ID:

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

Filter Hotel Catalog to Hotel Sets

Reference Docs

A hotel set is a subset of your catalog. To set up hotel ads, you need a hotel set. Therefore, you need to create at least one.

Hotel sets are defined by filters that are applied to the hotel catalog. For example, you can create a hotel set with all hotels with a star_rating greater than 3. Note: You can also create a hotel set without any filters. In that case, the hotel set will contain all hotels in your catalog.

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

curl -X POST \ -F 'name="Test Hotel Set"' \ -F 'filter={ "brand": { "i_contains": "sample brand" } }' \ -F 'access_token=<ACCESS_TOKEN>' \ https://graph.facebook.com/v3.2/<PRODUCT_CATALOG_ID>/product_sets
'use strict'; const bizSdk = require('facebook-nodejs-business-sdk'); const ProductCatalog = bizSdk.ProductCatalog; const ProductSet = bizSdk.ProductSet; const access_token = '<ACCESS_TOKEN>'; const app_secret = '<APP_SECRET>'; const app_id = '<APP_ID>'; const id = '<ID>'; const api = bizSdk.FacebookAdsApi.init(access_token); const showDebugingInfo = true; // Setting this to true shows more debugging info. if (showDebugingInfo) { api.setDebug(true); } const logApiCallResult = (apiCallName, data) => { console.log(apiCallName); if (showDebugingInfo) { console.log('Data:' + JSON.stringify(data)); } }; let fields, params; fields = [ ]; params = { 'name' : 'Test Hotel Set', 'filter' : {'brand':{'i_contains':'sample brand'}}, }; const product_sets = (new ProductCatalog(id)).createProductSet( fields, params ); logApiCallResult('product_sets api call complete.', product_sets);
require __DIR__ . '/vendor/autoload.php'; use FacebookAds\Object\ProductCatalog; use FacebookAds\Object\ProductSet; 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' => 'Test Hotel Set', 'filter' => array('brand' => array('i_contains' => 'sample brand')), ); echo json_encode((new ProductCatalog($id))->createProductSet( $fields, $params )->exportAllData(), JSON_PRETTY_PRINT);
from facebook_business.adobjects.productcatalog import ProductCatalog from facebook_business.adobjects.productset import ProductSet from facebook_business.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': 'Test Hotel Set', 'filter': {'brand':{'i_contains':'sample brand'}}, } print ProductCatalog(id).create_product_set( 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 ProductCatalog(id, context).createProductSet() .setName(\"Test Hotel Set\") .setFilter(\"{\\"brand\\":{\\"i_contains\\":\\"sample brand\\"}}\") .execute(); } }
require 'facebook_ads' 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 product_catalog = FacebookAds::ProductCatalog.get(id) product_sets = product_catalog.product_sets.create({ name: 'Test Hotel Set', filter: {'brand':{'i_contains':'sample brand'}}, })

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

OperatorsThe type of filter

i_contains

Contains substring. Operator is case insensitive.

i_not_contains

Does not contain substring. Operator is case insensitive.

contains

Contains substring. Operator is case insensitive.

not_contains

Does not contain substring. Operator is case insensitive.

eq

Equal to. Operator is case insensitive.

neq

Not equal to. Operator is case insensitive.

lt

Less than. For numeric fields only.

lte

Less than or equal to. For numeric fields only.

gt

Greater than. For numeric fields only.

gte

Greater than or equal to. For numeric fields only.

DataThe data being filtered.

hotel_id

Your unique identifier for the hotel within the catalog.

brand

Brand of the hotel chain.

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 where hotel is located.

country

Country of the hotel.

name

The most common name of the hotel.

star_rating

Hotel star rating. The valid values are between 1 to 5 and should be a multiple of 0.5.

Associate the catalog to your event sources

To map the data from your event sources (your pixels and app events) to your catalog, every catalog must be associated with these event sources. You can do this by visiting your business manager's catalog page and clicking the 'Associate Sources' button. Make sure to select the app and pixel that are receiving the travel events. Alternatively, you can use the API.

use FacebookAds\Object\ProductCatalog;

$product_catalog = new ProductCatalog(<PRODUCT_CATALOG_ID>);
$product_catalog->createExternalEventSource(array(), array(
  'external_event_sources' => array(
    <PIXEL_ID>,
    <APP_ID>,
  ),
));
from facebookads.adobjects.productcatalog import ProductCatalog

product_catalog = ProductCatalog(<PRODUCT_CATALOG_ID>)
product_catalog.add_external_event_sources([
    <PIXEL_ID>,
    <APP_ID>,
])
curl \
  -F 'external_event_sources=["<PIXEL_ID>","<APP_ID>"]' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<PRODUCT_CATALOG_ID>/external_event_sources

When making the API call, specify the following parameters:

Parameter Name & TypeDescription

external_event_sources

type: int[]

A list of Pixel and App IDs to associate with the catalog.