Facebook Conversions Cloud Mode Integration
11 minute read
RudderStack supports sending event data to Facebook Conversions only in cloud mode.
Page
RudderStack sends the page call to Facebook Pixel with the event type as pageView.
You can also pass properties in your page call - RudderStack automatically sends them along with the event ID to Facebook.
A sample page call is shown:
rudderanalytics.page()Track
This destination does not strictly adhere to the RudderStack Ecommerce Event Spec.
You can use the track call to custom events as they occur in your web application.
A sample track call is shown:
rudderanalytics.track("Product Added", {
order_ID: "123",
category: "boots",
product_name: "pink_boots",
price: 49.99,
currency: "EUR",
checkinDate: "Thu Mar 24 2018 17:46:45 GMT+0000 (UTC)",
})data object format
Whenever you make a track call, RudderStack sends a request to Facebook’s /events endpoint with a data object.
A sample data object is shown:
data = [{
"event_name": "Product Purchased",
"event_time": 1697553987,
"user_data": {
"em": [
"309a0a5c3e211326ae75ca18196d301a9bdbd1a882a4d2569511033da23f0abd"
],
"ph": [
"254aa248acb47dd654ca3ea53f48c2c26d641d23d7e2e93a1ec56258df7674c4",
"6f4fcb9deaeadc8f9746ae76d97ce1239e98b404efe5da3ee0b7149740f89ad6"
],
"client_ip_address": "<ip>",
"client_user_agent": "$CLIENT_USER_AGENT",
"fbc": "fb.1.1554763741205.AbCdEfGhIjKlMnOpQrStUvWxYz1234567890",
"fbp": "fb.1.1558571054389.1098115397"
},
"custom_data": {
"currency": "USD",
"value": 123.45,
"contents": [{
"id": "product123",
"quantity": 1,
"delivery_category": "home_delivery"
}]
},
"event_source_url": "http://example.com/product/123",
"action_source": "website"
}]The data object has the following parts:
Common data
The common data parameters are set at the root level of the data object sent as a part of the event payload.
The following table lists the mappings between the RudderStack properties and the Facebook properties included in common_data:
| RudderStack property | Facebook property |
|---|---|
eventRequired | event_name |
timestamporiginalTimestampRequired | event_time |
context.page.urlproperties.url | event_source_url |
traits.opt_outcontext.traits.opt_outproperties.opt_out | opt_out |
traits.event_idcontext.traits.event_idproperties.event_idmessageId | event_id |
traits.action_sourcecontext.traits.action_sourceproperties.action_source | action_source |
RudderStack expects the timestamp and originalTimestamp fields at the root level of the track event payload in the ISO 8601 format (for example, 2024-04-22T12:34:56.789Z).
Important considerations
When you connect a Reverse ETL source to this destination and map your warehouse columns using the JSON mapper, the
timestamp/originalTimestampfields get placed inside thepropertiesobject. In this case, you need to use a transformation and move them to the root level so RudderStack can map them correctly to Facebook’sevent_time.If your event does not contain any of
traits.action_source,context.traits.action_source, orproperties.action_source, then RudderStack falls back to the value specified in the Action Source dashboard setting.Do not set
action_sourceto any value other than the following - otherwise you will get a Invalid Action Source type error:emailwebsitephone_callchatphysical_storesystem_generatedapp, andother
User data
The following table lists the mappings between the RudderStack properties and the Facebook properties included in user_data:
| RudderStack property | Facebook property | Hashing needed? |
|---|---|---|
userIdtraits.userIdcontext.traits.userIdtraits.idcontext.traits.idanonymousIdRequired | externalId | Yes |
traits.emailcontext.traits.email | em | Yes |
traits.phonecontext.traits.phone | ph | Yes |
traits.gendercontext.traits.gender | ge | Yes |
traits.birthdaycontext.traits.birthday | db | Yes |
traits.lastnametraits.lastNametraits.last_namecontext.traits.lastnamecontext.traits.lastNamecontext.traits.last_name | ln | Yes |
traits.firstnametraits.firstNametraits.first_namecontext.traits.firstnamecontext.traits.firstNamecontext.traits.first_name | fn | Yes |
traits.namecontext.traits.name | name | - |
traits.address.citycontext.traits.address.city | ct | Yes |
traits.address.statecontext.traits.address.state | st | Yes |
traits.address.zipcontext.traits.address.zip | zp | Yes |
traits.address.countrycontext.traits.address.country | country | Yes |
context.iprequest_up | client_ip_address | - |
context.userAgent | client_user_agent | - |
context.fbc | fbc | - |
context.fbp | fbp | - |
context.subscription_id | subscription_id | - |
context.lead_id | lead_id | - |
context.fb_login_id | fb_login_id | - |
context.device.advertisingId | madId | - |
properties.anon_idcontext.device.advertisingId | anon_id | - |
After the payload is formed, Facebook checks if name field exists. If yes, it is split into fn and ln fields. Facebook does not hash the values of user_data parameters if you send an integrations object in your event as below:
"integrations": {
"fb_conversions": {
"hashed": true
}
}RudderStack accepts any of the following names for Facebook Conversions in the
integrationsobject:
fb_conversionsfb conversionsFacebookConversionsFacebook ConversionsFB ConversionsFacebook_Conversions
Custom data
RudderStack flattens the custom_data object before sending it Facebook along with the user_data and common_data fields in the data object.
Note that:
- RudderStack sends the properties present in
custom_dataas is, without any change. - It also excludes
opt_out,event_id, andaction_sourcefrom the event properties.
The following table explains how RudderStack maps and sets the properties in the specific Facebook fields:
Each of the below parameters are applicable/valid only for certain events.
See Standard events mapping for more information on the properties mapped for each Facebook property according to the event.
| RudderStack property | Facebook property |
|---|---|
Array of product IDs from properties.products like product.product_id, product.sku, product.id. | content_ids |
Array of object containing id, quantity, and item_price formed for each product in properties.products. | contents |
properties.content_type | content_type |
properties.category | content_category |
| content_name |
properties.currency - defaulted to USD if no value is present. | currency |
properties.revenueproperties.valueproperties.priceproperties.total | value |
content_ids.length | num_items |
properties.query | search_string |
Note that content_category must be of type String. For more information on this field, see Facebook developer documentation.
- If
content_categoryis passed as an array, RudderStack merges the array elements as a comma-separated string. - If
content_categoryis passed as an object, RudderStack throws an error:"Category must be a string."
Allowlist/denylist PII
Facebook identifies the following standard fields as PII:
emailfirstNamelastNamefirst_namelast_namegendercitycountryphonestatezipbirthday
The PII allowlist/denylist checks (configurable via the Event mapping settings) apply only to the standard Facebook PII fields listed above. They do not affect any other properties or top-level RudderStack identifiers likeanonymousIdoruserId.
If any of the above PII properties are present in an event, RudderStack checks whether they are allowlisted or denylisted in the dashboard settings, and processes them accordingly:
If the property is not allowlisted, RudderStack drops it.
If the property is denylisted, RudderStack checks if the Hash Denylist PII Property toggle is enabled in the dashboard:
- If the toggle is disabled, RudderStack drops the property
- If the toggle is enabled, RudderStack hash-encrypts the property before sending it to Facebook
As mentioned above, if you send an integrations object within your event with hashed set to true, RudderStack does not hash the property again.
"integrations": {
"fb_conversions": {
"hashed": true
}
}App data
RudderStack includes this data only ifaction_sourcein thedata objectis set toapp.
The following table lists the mappings between the RudderStack properties and the Facebook properties:
| RudderStack property | Facebook property |
|---|---|
a2 if context.device.type = androidi2 if context.device.type = iosRequired | extinfo.0 |
context.device.adTrackingEnabledRequired | advertiser_tracking_enabled |
context.os.versionRequired | extinfo.4 |
properties.application_tracking_enabledRequired | application_tracking_enabled |
anonymousId | user_data.anon_id |
context.app.namespace | extinfo.1 |
context.app.build | extinfo.2 |
context.app.version | extinfo.3 |
context.device.model | extinfo.5 |
context.device.advertisingId | user_data.madid |
context.locale | extinfo.6 |
context.abv_timezone | extinfo.7 |
context.network_carrier | extinfo.8 |
context.screen_width | extinfo.9 |
context.screen_height | extinfo.10 |
context.screen_density | extinfo.11 |
context.cpu_cores | extinfo.12 |
context.ext_storage_size | extinfo.13 |
context.avl_storage_size | extinfo.14 |
context.timezone | extinfo.15 |
properties.campaignIdcontext.traits.campaignIdcontext.campaign.name | campaign_ids |
properties.install_referrer | install_referrer |
properties.installer_package | installer_package |
properties.url_schemes | url_schemes |
properties.windows_attribution_id | windows_attribution_id |
Standard events mapping
RudderStack maps the following events to the Facebook standard events by default:
| RudderStack Event | Facebook Standard Event |
|---|---|
Checkout Started | InitiateCheckout |
Order Completed | Purchase |
Product Added | AddToCart |
Product Added to Wishlist | AddToWishlist |
Payment Info Entered | AddPaymentInfo |
Product List Viewed | ViewContent |
Products Searched | Search |
Product Viewed | ViewContent |
You can also use the Custom Event Mapping dashboard setting to override the above default mappings.
See the Ecommerce Events Specification for more information on the above events.
Note that:
For the
Purchasestandard event (mapped toOrder Completedevent),properties.revenueis a required field. Also, RudderStack sends thedelivery_categoryfield along withid,item_priceandquantityas a part of thecustom_data.contentsobject.For the
Products Searchedevent, thequeryproperty must be a string.If you map an event with the
ViewContentstandard event using the RudderStack dashboard setting and don’t send theproductsarray in themessage.propertiesobject:javascript"properties": { "phone": 1-202-555-0146, "email": "alex@example.com", "category": "clothing", "list_id": "1234", "testDimension": true, "testMetric": true }Then,
content_idsis mapped toproperties.categoryvalue (clothingin this case) andquantityis set to1inside thecontentsobject.
The below table elaborates the property mappings between RudderStack and Facebook corresponding to the RudderStack event:
| RudderStack event | RudderStack property | Facebook property |
|---|---|---|
| Checkout Started | ||
products.$.product_id/products.$.sku/products.$.id | content_ids | |
categorycurrencyrevenue | content_categorycurrencyvalue | |
products.$.product_id/products.$.sku/products.$.idproducts.$.quantity/quantityproduct.$.price/price | contents.idcontents.quantitycontents.item_price | |
| Product List Viewed | ||
products.$.product_id/products.$.sku/products.$.id | content_ids | |
categorycontentNamecurrencyvalue | content_categorycontent_namecurrencyvalue | |
products.$.product_id/products.$.sku/products.$.idproducts.$.quantity/quantityproduct.$.price | contents.idcontents.quantitycontents.item_price | |
| Product Viewed | ||
product_id/sku/idproduct_name/namecategorycurrency | content_idscontent_namecontent_categorycurrency | |
product_id/sku/idquantityprice | contents.idcontents.quantitycontents.item_price | |
| Product Added | ||
product_id/sku/idproduct_name/namecurrency | content_idscontent_namecurrency | |
product_id/sku/idquantityprice | contents.idcontents.quantitycontents.item_price | |
| Order Completed | ||
products.$.product_id/products.$.sku/products.$.id | content_ids | |
contentNamecurrencyrevenue | content_namecurrencyvalue | |
products.$.delivery_category/properties.delivery_categoryproducts.$.product_id/products.$.sku/products.$.idproducts.$.quantity/quantityproduct.$.price/price | contents.delivery_categorycontents.idcontents.quantitycontents.item_price | |
| Products Searched | queryproduct_id/sku/idcategorycurrencyvalue | search_stringcontent_idscontent_categorycurrencyvalue |
product_id/sku/idquantityprice | contents.idcontents.quantitycontents.item_price | |
| Product Added to Wishlist | ||
products.$.product_id/products.$.sku/products.$.id | content_ids | |
categorycontentNamecurrencyvalue | content_categorycontent_namecurrencyvalue | |
products.$.product_id/products.$.sku/products.$.idproducts.$.quantity/quantityproduct.$.price/price | contents.idcontents.quantitycontents.item_price | |
| Payment Info Entered | ||
products.$.product_id/products.$.sku/products.$.id | content_ids | |
categorycurrencyvalue | content_categorycurrencyvalue | |
products.$.product_id/products.$.sku/products.$.idproducts.$.quantity/quantityproduct.$.price/price | contents.idcontents.quantitycontents.item_price |
For all the standard events mentioned above:
- Default values for the
currencyandquantityproperties areUSDand1respectively.content_idsfield is populated from theproductsarray. If theproductsarray is not present in theproperties,content_idsis set to an empty array resulting innum_itemsbeing set to0.
Other standard events
If you map your event to any of the following Facebook standard events, then RudderStack treats it as a standard event as well:
LeadCompleteRegistrationContactCustomizeProductDonateFindLocationScheduleStartTrialSubmitApplicationSubscribe
For any properties you want to send with these events, you must specify them in the Event Mapping settings.
For the above-mentioned events and custom events, RudderStack sendscontent_idsandnum_itemsto Facebook as a part ofpropertiesin the appropriate format.
Deduplication
Facebook allows you to send events via your web browser and your server via the Conversion API.
Depending on how you send your events with this dual setup, there is a possibility of Facebook receiving redundant/duplicate events. Hence, to get an accurate representation of your data, Facebook deduplicates the incoming events.
Using event_id
Facebook’s (and RudderStack’s) recommended deduplication strategy is to leverage the event_name and event_id properties. When two events coming into Facebook meet the following criteria, they are deduplicated.
- They are sent within 48 hours of each other.
- They are received by the same Facebook Pixel ID.
- They have the same
event_name, for example,Purchase. - They have the same
event_id.- The
event_idmust be unique to that specific event and same for both of the events. For example, theevent_idcould be a purchase order number.
- The
You can set the event_id as a unique identifier in the event’s traits, context.traits, or the properties object. RudderStack automatically picks up the event_name from the event.
If you don’t set theevent_id, RudderStack usesmessageIdand maps it to Facebook’seventId.
For more information on the event_id deduplication logic, see the Facebook developer documentation.
Using fbp and external_id
This deduplication strategy is not recommended as it has a few drawbacks:
- It will always discard the server event if Facebook identifies a redundant event.
- It only works for deduplicating events sent first from the browser and then the server.
- There is no deduplication if two consecutive browser events with the same information are sent to Facebook. The same is true if two server events with the same information are sent to Facebook.
For this approach, it is necessary to send an event, first from the browser and then from the server. Note that both events must have the same event_name, the same fbp parameter, and the same external_id.
If the browser event is received before the server event and both events have the same event_name and the same fbp and external_id, then the server event is discarded.
RudderStack maps the event_name from the event sent to Facebook. The fbp parameter is taken from the context.fbp key-value pair. Finally, the external_id will be the userId or anonymousId (if userId is not present).
For more information on the fbp and external_id deduplication logic, see the Facebook developer documentation.
Sending custom content_type
You can send a custom content_type field by specifying it in the properties.content_type field of your event.
RudderStack sets the value of content_type in the following priority order:
- It gives the highest priority to
properties.content_typein your event. - If
properties.content_typeis absent, RudderStack sets thecontent_typetoproductby default, except in the following cases:
- If Product List Viewed event is sent:
- with
productsarray, then thecontent_typeis set toproduct. - without the
productsarray, then thecontent_typeis set toproduct_group.
- with
- If Product Viewed event is not mapped in RudderStack dashboard (default mapping is set to View Content event) but is sent:
- with
productsarray, then thecontent_typeis set toproduct. - without the
productsarray, then thecontent_typeis set toproduct_group.
- with
- If any other event is mapped to the Facebook standard event View Content in the RudderStack dashboard and is sent:
- with
productsarray, then thecontent_typeis set toproduct. - without the
productsarray, then thecontent_typeis set toproduct_group.
- with
productandproduct_groupare the only two acceptable values forcontent_type.
FAQ
How can I view the conversion events in my Facebook Ads dashboard?
- Log in to your Facebook Ads Manager account.
- Click the All tools hamburger menu in the left sidebar.

- Select Events Manager.
- Select the data source associated with your ad campaign.

Here, you can view your conversion events tracked by Facebook Pixel, app, or offline event sets - this includes the standard and custom events that you have set up.
See the Events Manager documentation for more information on viewing and managing your events.