template.tpl (885 lines of code) (raw):
___TERMS_OF_SERVICE___
By creating or modifying this file you agree to Google Tag Manager's Community
Template Gallery Developer Terms of Service available at
https://developers.google.com/tag-manager/gallery-tos (or such other URL as
Google may provide), as modified from time to time.
___INFO___
{
"type": "TAG",
"id": "cvt_temp_public_id",
"version": 1,
"securityGroups": [],
"displayName": "Conversions API Tag",
"brand": {
"id": "brand_dummy",
"displayName": ""
},
"description": "A server-side tag template that prepares information from your tagging server to be sent through Conversions API.",
"containerContexts": [
"SERVER"
]
}
___TEMPLATE_PARAMETERS___
[
{
"type": "TEXT",
"name": "pixelId",
"displayName": "Pixel ID",
"simpleValueType": true,
"valueValidators": [
{
"type": "NON_EMPTY"
}
]
},
{
"type": "TEXT",
"name": "apiAccessToken",
"displayName": "API Access Token",
"simpleValueType": true,
"valueValidators": [
{
"type": "NON_EMPTY"
}
],
"help": "To use the Conversions API, you need an access token. See \u003ca href\u003d\"https://developers.facebook.com/docs/marketing-api/conversions-api/get-started#access-token\"\u003ehere\u003c/a\u003e for generating an access token."
},
{
"type": "TEXT",
"name": "testEventCode",
"displayName": "Test Event Code",
"simpleValueType": true,
"help": "Code used to verify that your server events are received correctly by Conversions API. Use this code to test your server events in the Test Events feature in Events Manager. See \u003ca href\u003d\"https://developers.facebook.com/docs/marketing-api/conversions-api/using-the-api#testEvents\"\u003e Test Events Tool\u003c/a\u003e for an example."
},
{
"type": "SELECT",
"name": "actionSource",
"displayName": "Action Source",
"macrosInSelect": false,
"selectItems": [
{
"value": "website",
"displayValue": "Website"
},
{
"value": "email",
"displayValue": "Email"
},
{
"value": "app",
"displayValue": "App"
},
{
"value": "phone_call",
"displayValue": "Phone Call"
},
{
"value": "chat",
"displayValue": "Chat"
},
{
"value": "physical_store",
"displayValue": "Physical Store"
},
{
"value": "system_generated",
"displayValue": "System Generated"
},
{
"value": "other",
"displayValue": "Other"
}
],
"simpleValueType": true,
"help": "This field allows you to specify where your conversions occurred. Knowing where your events took place helps ensure your ads go to the right people. See \u003ca href\u003d\"https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/server-event#action-source\"\u003ehere\u003c/a\u003e for more information."
},
{
"type": "CHECKBOX",
"name": "extendCookies",
"checkboxText": "Extend Meta Pixel cookies (fbp/fbc)",
"simpleValueType": true
}
]
___SANDBOXED_JS_FOR_SERVER___
// Sandbox Javascript imports
const getAllEventData = require('getAllEventData');
const getType = require('getType');
const sendHttpRequest = require('sendHttpRequest');
const JSON = require('JSON');
const Math = require('Math');
const getTimestampMillis = require('getTimestampMillis');
const sha256Sync = require('sha256Sync');
const getCookieValues = require('getCookieValues');
const setCookie = require('setCookie');
const decodeUriComponent = require('decodeUriComponent');
const parseUrl = require('parseUrl');
const computeEffectiveTldPlusOne = require('computeEffectiveTldPlusOne');
// Constants
const API_ENDPOINT = 'https://graph.facebook.com';
const API_VERSION = 'v12.0';
const PARTNER_AGENT = 'gtmss-1.0.0-0.0.6';
const GTM_EVENT_MAPPINGS = {
"add_payment_info": "AddPaymentInfo",
"add_to_cart": "AddToCart",
"add_to_wishlist": "AddToWishlist",
"gtm.dom": "PageView",
"page_view": "PageView",
"purchase": "Purchase",
"search": "Search",
"begin_checkout": "InitiateCheckout",
"generate_lead": "Lead",
"view_item": "ViewContent",
"sign_up": "CompleteRegistration"
};
function isAlreadyHashed(input){
return input && (input.match('^[A-Fa-f0-9]{64}$') != null);
}
function setFbCookie(name, value, expire) {
setCookie(name, value, {
domain: 'auto',
path: '/',
samesite: 'Lax',
secure: true,
'max-age': expire || 7776000, // default to 90 days
httpOnly: false
});
}
function getFbcValue() {
let fbc = eventModel['x-fb-ck-fbc'] || getCookieValues('_fbc', true)[0];
const url = eventModel.page_location;
const subDomainIndex = url ? computeEffectiveTldPlusOne(url).split('.').length - 1 : 1;
const parsedUrl = parseUrl(url);
if (parsedUrl && parsedUrl.searchParams.fbclid) {
fbc = 'fb.' + subDomainIndex + '.' + getTimestampMillis() + '.' + decodeUriComponent(parsedUrl.searchParams.fbclid);
}
return fbc;
}
function hashFunction(input){
const type = getType(input);
if(type == 'undefined' || input == 'undefined') {
return undefined;
}
if(input == null || isAlreadyHashed(input)){
return input;
}
return sha256Sync(input.trim().toLowerCase(), {outputEncoding: 'hex'});
}
function getContentFromItems(items) {
return items.map(item => {
return {
"id": item.item_id,
"title": item.item_name,
"item_price": item.price,
"brand": item.item_brand,
"quantity": item.quantity,
"category": item.item_category,
};
});
}
function getFacebookEventName(gtmEventName) {
return GTM_EVENT_MAPPINGS[gtmEventName] || gtmEventName;
}
const eventModel = getAllEventData();
const event = {};
event.event_name = getFacebookEventName(eventModel.event_name);
event.event_time = eventModel.event_time || (Math.round(getTimestampMillis() / 1000));
event.event_id = eventModel.event_id;
event.event_source_url = eventModel.page_location;
if(eventModel.action_source || data.actionSource) {
event.action_source = eventModel.action_source ? eventModel.action_source : data.actionSource;
}
event.user_data = {};
// Default Tag Parameters
event.user_data.client_ip_address = eventModel.ip_override;
event.user_data.client_user_agent = eventModel.user_agent;
// Commmon Event Schema Parameters
event.user_data.em = eventModel['x-fb-ud-em'] ||
(eventModel.user_data != null ? hashFunction(eventModel.user_data.email_address) : null);
event.user_data.ph = eventModel['x-fb-ud-ph'] ||
(eventModel.user_data != null ? hashFunction(eventModel.user_data.phone_number) : null);
const addressData = (eventModel.user_data != null && eventModel.user_data.address != null) ? eventModel.user_data.address : {};
event.user_data.fn = eventModel['x-fb-ud-fn'] || hashFunction(addressData.first_name);
event.user_data.ln = eventModel['x-fb-ud-ln'] || hashFunction(addressData.last_name);
event.user_data.ct = eventModel['x-fb-ud-ct'] || hashFunction(addressData.city);
event.user_data.st = eventModel['x-fb-ud-st'] || hashFunction(addressData.region);
event.user_data.zp = eventModel['x-fb-ud-zp'] || hashFunction(addressData.postal_code);
event.user_data.country = eventModel['x-fb-ud-country'] || hashFunction(addressData.country);
// Conversions API Specific Parameters
event.user_data.ge = eventModel['x-fb-ud-ge'];
event.user_data.db = eventModel['x-fb-ud-db'];
event.user_data.external_id = eventModel['x-fb-ud-external_id'];
event.user_data.subscription_id = eventModel['x-fb-ud-subscription_id'];
event.user_data.fbp = eventModel['x-fb-ck-fbp'] || getCookieValues('_fbp', true)[0];
event.user_data.fbc = getFbcValue();
event.custom_data = {};
event.custom_data.currency = eventModel.currency;
event.custom_data.value = eventModel.value;
event.custom_data.search_string = eventModel.search_term;
event.custom_data.order_id = eventModel.transaction_id;
event.custom_data.content_category = eventModel['x-fb-cd-content_category'];
event.custom_data.content_ids = eventModel['x-fb-cd-content_ids'];
event.custom_data.content_name = eventModel['x-fb-cd-content_name'];
event.custom_data.content_type = eventModel['x-fb-cd-content_type'];
event.custom_data.contents = eventModel['x-fb-cd-contents'] ||
(eventModel.items != null ? getContentFromItems(eventModel.items) : null);
event.custom_data.num_items = eventModel['x-fb-cd-num_items'];
event.custom_data.predicted_ltv = eventModel['x-fb-cd-predicted_ltv'];
event.custom_data.status = eventModel['x-fb-cd-status'];
event.custom_data.delivery_category = eventModel['x-fb-cd-delivery_category'];
const eventRequest = {data: [event], partner_agent: PARTNER_AGENT};
if(eventModel.test_event_code || data.testEventCode) {
eventRequest.test_event_code = eventModel.test_event_code ? eventModel.test_event_code : data.testEventCode;
}
// Posting to Conversions API
const routeParams = 'events?access_token=' + data.apiAccessToken;
const graphEndpoint = [API_ENDPOINT,
API_VERSION,
data.pixelId,
routeParams].join('/');
const requestHeaders = {headers: {'content-type': 'application/json'}, method: 'POST'};
sendHttpRequest(
graphEndpoint,
(statusCode, headers, response) => {
if (statusCode >= 200 && statusCode < 300) {
if (data.extendCookies && event.user_data.fbc) {
setFbCookie('_fbc', event.user_data.fbc);
}
if (data.extendCookies && event.user_data.fbp) {
setFbCookie('_fbp', event.user_data.fbp);
}
data.gtmOnSuccess();
} else {
data.gtmOnFailure();
}
},
requestHeaders,
JSON.stringify(eventRequest)
);
___SERVER_PERMISSIONS___
[
{
"instance": {
"key": {
"publicId": "read_event_data",
"versionId": "1"
},
"param": [
{
"key": "eventDataAccess",
"value": {
"type": 1,
"string": "any"
}
}
]
},
"clientAnnotations": {
"isEditedByUser": true
},
"isRequired": true
},
{
"instance": {
"key": {
"publicId": "send_http",
"versionId": "1"
},
"param": [
{
"key": "allowedUrls",
"value": {
"type": 1,
"string": "specific"
}
},
{
"key": "urls",
"value": {
"type": 2,
"listItem": [
{
"type": 1,
"string": "https://graph.facebook.com/"
}
]
}
}
]
},
"clientAnnotations": {
"isEditedByUser": true
},
"isRequired": true
},
{
"instance": {
"key": {
"publicId": "get_cookies",
"versionId": "1"
},
"param": [
{
"key": "cookieAccess",
"value": {
"type": 1,
"string": "specific"
}
},
{
"key": "cookieNames",
"value": {
"type": 2,
"listItem": [
{
"type": 1,
"string": "_fbp"
},
{
"type": 1,
"string": "_fbc"
}
]
}
}
]
},
"clientAnnotations": {
"isEditedByUser": true
},
"isRequired": true
},
{
"instance": {
"key": {
"publicId": "set_cookies",
"versionId": "1"
},
"param": [
{
"key": "allowedCookies",
"value": {
"type": 2,
"listItem": [
{
"type": 3,
"mapKey": [
{
"type": 1,
"string": "name"
},
{
"type": 1,
"string": "domain"
},
{
"type": 1,
"string": "path"
},
{
"type": 1,
"string": "secure"
},
{
"type": 1,
"string": "session"
}
],
"mapValue": [
{
"type": 1,
"string": "_fbc"
},
{
"type": 1,
"string": "*"
},
{
"type": 1,
"string": "*"
},
{
"type": 1,
"string": "any"
},
{
"type": 1,
"string": "any"
}
]
},
{
"type": 3,
"mapKey": [
{
"type": 1,
"string": "name"
},
{
"type": 1,
"string": "domain"
},
{
"type": 1,
"string": "path"
},
{
"type": 1,
"string": "secure"
},
{
"type": 1,
"string": "session"
}
],
"mapValue": [
{
"type": 1,
"string": "_fbp"
},
{
"type": 1,
"string": "*"
},
{
"type": 1,
"string": "*"
},
{
"type": 1,
"string": "any"
},
{
"type": 1,
"string": "any"
}
]
}
]
}
}
]
},
"clientAnnotations": {
"isEditedByUser": true
},
"isRequired": true
},
]
___TESTS___
scenarios:
- name: on EventModel model data tag triggers to send to Conversions API
code: |-
// Act
runCode(testConfigurationData);
//Assert
assertApi('sendHttpRequest').wasCalledWith(requestEndpoint, actualSuccessCallback, requestHeaderOptions, JSON.stringify(requestData));
assertApi('gtmOnSuccess').wasCalled();
- name: on Event with common event schema triggers tag to send to Conversions API
code: |-
const preTagFireEventTime = Math.round(getTimestampMillis() / 1000);
const common_event_schema = {
event_name: testData.event_name,
client_id: 'client123',
ip_override: testData.ip_address,
user_agent: testData.user_agent,
};
mock('getAllEventData', () => {
return common_event_schema;
});
// Act
runCode(testConfigurationData);
//Assert
const actualTagFireEventTime = JSON.parse(httpBody).data[0].event_time;
assertThat(actualTagFireEventTime-preTagFireEventTime).isLessThan(1);
assertApi('gtmOnSuccess').wasCalled();
- name: on sending action source from Client, Tag overrides the preset configuration
code: |-
// Act
mock('getAllEventData', () => {
inputEventModel.action_source = testData.action_source;
return inputEventModel;
});
runCode(testConfigurationData);
//Assert
assertThat(JSON.parse(httpBody).data[0].action_source).isEqualTo(inputEventModel.action_source);
- name: on receiving event, if GTM Standard Event then Tag converts to corresponding
Conversions API Event, passes through as-is if otherwise
code: |-
// Act
mock('getAllEventData', () => {
inputEventModel.event_name = 'add_to_wishlist';
return inputEventModel;
});
runCode(testConfigurationData);
//Assert
assertThat(JSON.parse(httpBody).data[0].event_name).isEqualTo('AddToWishlist');
// Act
mock('getAllEventData', () => {
inputEventModel.event_name = 'custom_event';
return inputEventModel;
});
runCode(testConfigurationData);
//Assert
assertThat(JSON.parse(httpBody).data[0].event_name).isEqualTo('custom_event');
// Act
mock('getAllEventData', () => {
inputEventModel.event_name = 'generate_lead';
return inputEventModel;
});
runCode(testConfigurationData);
//Assert
assertThat(JSON.parse(httpBody).data[0].event_name).isEqualTo('Lead');
- name: On receiving event, hashes the the user_data fields if they are not already hashed
code: |-
// Un-hashed raw email_address from Common Event Schema is hashed before posted to Conversions API.
// Act
mock('getAllEventData', () => {
inputEventModel['x-fb-ud-em'] = null;
inputEventModel['x-fb-ud-ph'] = null;
inputEventModel['x-fb-ud-fn'] = null;
inputEventModel['x-fb-ud-ln'] = null;
inputEventModel['x-fb-ud-ct'] = null;
inputEventModel['x-fb-ud-st'] = null;
inputEventModel['x-fb-ud-zp'] = null;
inputEventModel['x-fb-ud-country'] = null;
inputEventModel.user_data = {};
inputEventModel.user_data.email_address = 'foo@bar.com';
inputEventModel.user_data.phone_number = '1234567890';
inputEventModel.user_data.address = {};
inputEventModel.user_data.address.first_name = 'Foo';
inputEventModel.user_data.address.last_name = 'Bar';
inputEventModel.user_data.address.city = 'Menlo Park';
inputEventModel.user_data.address.region = 'ca';
inputEventModel.user_data.address.postal_code = '12345';
inputEventModel.user_data.address.country = 'usa';
return inputEventModel;
});
runCode(testConfigurationData);
//Assert
assertThat(JSON.parse(httpBody).data[0].user_data.em).isEqualTo(hashFunction('foo@bar.com'));
assertThat(JSON.parse(httpBody).data[0].user_data.ph).isEqualTo(hashFunction('1234567890'));
assertThat(JSON.parse(httpBody).data[0].user_data.fn).isEqualTo(hashFunction('Foo'));
assertThat(JSON.parse(httpBody).data[0].user_data.ln).isEqualTo(hashFunction('Bar'));
assertThat(JSON.parse(httpBody).data[0].user_data.ct).isEqualTo(hashFunction('Menlo Park'));
assertThat(JSON.parse(httpBody).data[0].user_data.st).isEqualTo(hashFunction('ca'));
assertThat(JSON.parse(httpBody).data[0].user_data.zp).isEqualTo(hashFunction('12345'));
assertThat(JSON.parse(httpBody).data[0].user_data.country).isEqualTo(hashFunction('usa'));
// Un-hashed raw email_address in mixed-case is converted to lowercase, hashed and posted to Conversions API.
// Act
mock('getAllEventData', () => {
inputEventModel.user_data.email_address = 'FOO@BAR.com';
return inputEventModel;
});
runCode(testConfigurationData);
//Assert
assertThat(JSON.parse(httpBody).data[0].user_data.em).isEqualTo(hashFunction('foo@bar.com'));
// Already sha256(email_address) field from GA4 schema, is unchanged, is posted as-is to Conversions API.
// Act
mock('getAllEventData', () => {
inputEventModel.user_data.email_address = hashFunction('foo@bar.com');
return inputEventModel;
});
runCode(testConfigurationData);
//Assert
assertThat(JSON.parse(httpBody).data[0].user_data.em).isEqualTo(hashFunction('foo@bar.com'));
// Already null email field from GA4 schema, is sent as null to Conversions API.
// Act
mock('getAllEventData', () => {
inputEventModel.user_data.email_address = null;
return inputEventModel;
});
runCode(testConfigurationData);
//Assert
assertThat(JSON.parse(httpBody).data[0].user_data.em).isEqualTo(null);
- name: On receiving event with fbp/fbc cookies, it is sent to Conversions API
code: |-
// Act
mock('getAllEventData', () => {
inputEventModel['x-fb-ck-fbp'] = null;
inputEventModel['x-fb-ck-fbc'] = null;
return inputEventModel;
});
mock('getCookieValues', (cookieName) => {
if(cookieName === '_fbp') return ['fbp_cookie'];
if(cookieName === '_fbc') return ['fbc_cookie'];
});
runCode(testConfigurationData);
//Assert
assertThat(JSON.parse(httpBody).data[0].user_data.fbp).isEqualTo('fbp_cookie');
assertThat(JSON.parse(httpBody).data[0].user_data.fbc).isEqualTo('fbc_cookie');
- name: On receiving GA4 event, with the items info, tag parses them into Conversions API schema
code: |-
// Act
let items = [
{
item_id: '1',
item_name: 'item_1',
quantity: 5,
price: 123.45,
item_category: 'cat_1',
item_brand: 'brand_1',
},
{
item_id: '2',
item_name: 'item_2',
quantity: 10,
price: 123.45,
item_category: 'cat_2',
item_brand: 'brand_2',
}
];
mock('getAllEventData', () => {
inputEventModel['x-fb-cd-contents'] = null;
inputEventModel.items = items;
return inputEventModel;
});
runCode(testConfigurationData);
//Assert
let actual_contents = JSON.parse(httpBody).data[0].custom_data.contents;
assertThat(JSON.parse(httpBody).data[0].custom_data.contents.length).isEqualTo(items.length);
for( var i = 0; i < items.length; i++) {
assertThat(actual_contents[i].id).isEqualTo(items[i].item_id);
assertThat(actual_contents[i].item_price).isEqualTo(items[i].price);
assertThat(actual_contents[i].brand).isEqualTo(items[i].item_brand);
assertThat(actual_contents[i].quantity).isEqualTo(items[i].quantity);
assertThat(actual_contents[i].category).isEqualTo(items[i].item_category);
}
// Act
mock('getAllEventData', () => {
inputEventModel.items = null;
return inputEventModel;
});
runCode(testConfigurationData);
//Assert
assertThat(JSON.parse(httpBody).data[0].custom_data.contents).isEqualTo(null);
- name: When address is missing it skips parsing the nested fields
code: |
mock('getAllEventData', () => {
inputEventModel['x-fb-ud-em'] = null;
inputEventModel['x-fb-ud-ph'] = null;
inputEventModel['x-fb-ud-fn'] = null;
inputEventModel['x-fb-ud-ln'] = null;
inputEventModel['x-fb-ud-ct'] = null;
inputEventModel['x-fb-ud-st'] = null;
inputEventModel['x-fb-ud-zp'] = null;
inputEventModel['x-fb-ud-country'] = null;
inputEventModel.user_data = {};
inputEventModel.user_data.email_address = 'foo@bar.com';
inputEventModel.user_data.phone_number = '1234567890';
return inputEventModel;
});
runCode(testConfigurationData);
assertThat(JSON.parse(httpBody).data[0].user_data.em).isEqualTo(hashFunction('foo@bar.com'));
assertThat(JSON.parse(httpBody).data[0].user_data.ph).isEqualTo(hashFunction('1234567890'));
assertThat(JSON.parse(httpBody).data[0].user_data.fn).isUndefined();
assertThat(JSON.parse(httpBody).data[0].user_data.ln).isUndefined();
assertThat(JSON.parse(httpBody).data[0].user_data.ct).isUndefined();
assertThat(JSON.parse(httpBody).data[0].user_data.st).isUndefined();
assertThat(JSON.parse(httpBody).data[0].user_data.zp).isUndefined();
assertThat(JSON.parse(httpBody).data[0].user_data.country).isUndefined();
- name: When parameters are undefined skip parsing
code: |
mock('getAllEventData', () => {
inputEventModel['x-fb-ud-em'] = null;
inputEventModel['x-fb-ud-ph'] = null;
inputEventModel['x-fb-ud-fn'] = null;
inputEventModel['x-fb-ud-ln'] = null;
inputEventModel['x-fb-ud-ct'] = null;
inputEventModel['x-fb-ud-st'] = null;
inputEventModel['x-fb-ud-zp'] = null;
inputEventModel['x-fb-ud-country'] = null;
inputEventModel.user_data = {};
inputEventModel.user_data.email_address = undefined;
inputEventModel.user_data.phone_number = '1234567890';
inputEventModel.user_data.address = {};
inputEventModel.user_data.address.first_name = 'John';
inputEventModel.user_data.address.last_name = undefined;
inputEventModel.user_data.address.city = 'menlopark';
inputEventModel.user_data.address.region = 'ca';
inputEventModel.user_data.address.postal_code = '94025';
inputEventModel.user_data.address.country = 'usa';
return inputEventModel;
});
runCode(testConfigurationData);
assertThat(JSON.parse(httpBody).data[0].user_data.em).isUndefined();
assertThat(JSON.parse(httpBody).data[0].user_data.ph).isEqualTo(hashFunction('1234567890'));
assertThat(JSON.parse(httpBody).data[0].user_data.fn).isEqualTo(hashFunction('John'));
assertThat(JSON.parse(httpBody).data[0].user_data.ln).isUndefined();
assertThat(JSON.parse(httpBody).data[0].user_data.ct).isEqualTo(hashFunction('menlopark'));
assertThat(JSON.parse(httpBody).data[0].user_data.st).isEqualTo(hashFunction('ca'));
assertThat(JSON.parse(httpBody).data[0].user_data.zp).isEqualTo(hashFunction('94025'));
assertThat(JSON.parse(httpBody).data[0].user_data.country).isEqualTo(hashFunction('usa'));
- name: Set Meta cookies (fbp / fbc) if "extendCookies" checkbox is ticked
code: |
runCode({
pixelId: '123',
apiAccessToken: 'abc',
testEventCode: 'test123',
actionSource: 'source123',
extendCookies: true
});
//Assert
assertApi('setCookie').wasCalled();
assertApi('gtmOnSuccess').wasCalled();
- name: Do not set Meta cookies (fbp / fbc) if "extendCookies" checkbox is ticked
code: |
runCode({
pixelId: '123',
apiAccessToken: 'abc',
testEventCode: 'test123',
actionSource: 'source123',
extendCookies: false
});
//Assert
assertApi('setCookie').wasNotCalled();
assertApi('gtmOnSuccess').wasCalled();
setup: |-
// Arrange
const JSON = require('JSON');
const Math = require('Math');
const getTimestampMillis = require('getTimestampMillis');
const sha256Sync = require('sha256Sync');
// helper methods
function hashFunction(input) {
return sha256Sync(input.trim().toLowerCase(), {outputEncoding: 'hex'});
}
const testConfigurationData = {
pixelId: '123',
apiAccessToken: 'abc',
testEventCode: 'test123',
actionSource: 'source123'
};
const testData = {
event_name: "Test1",
event_time: "123456789",
test_event_code: "test123",
action_source: 'website',
user_data: {
ip_address: '1.2.3.4',
user_agent: 'Test_UA',
email: 'test@example.com',
phone_number: '123456789',
first_name: 'foo',
last_name: 'bar',
gender: 'm',
date_of_brith: '19910526',
city: 'menlopark',
state: 'ca',
country: 'us',
zip: '12345',
external_id: 'user123',
subscription_id: 'abc123',
fbp: 'test_browser_id',
fbc: 'test_click_id',
},
custom_data: {
currency: 'USD',
value: '123',
search_string: 'query123',
transaction_id: 'order_123',
content_category: 'testCategory',
content_ids: ['123', '456'],
content_name: 'Foo',
content_type: 'product',
contents: [{'id': '123', 'quantity': 2}, {'id': '456', 'quantity': 2}],
num_items: '4',
predicted_ltv: '10000',
delivery_category: 'home_delivery',
status: 'subscribed',
}
};
let inputEventModel = {
'event_name': testData.event_name,
'event_time': testData.event_time,
'ip_override': testData.user_data.ip_address,
'user_agent': testData.user_data.user_agent,
'test_event_code': testData.test_event_code,
'x-fb-ud-em': testData.user_data.email,
'x-fb-ud-ph': testData.user_data.phone_number,
'x-fb-ud-fn': testData.user_data.first_name,
'x-fb-ud-ln': testData.user_data.last_name,
'x-fb-ud-ge': testData.user_data.gender,
'x-fb-ud-db': testData.user_data.date_of_brith,
'x-fb-ud-ct': testData.user_data.city,
'x-fb-ud-st': testData.user_data.state,
'x-fb-ud-zp': testData.user_data.zip,
'x-fb-ud-country': testData.user_data.country,
'x-fb-ud-external_id': testData.user_data.external_id,
'x-fb-ud-subscription_id': testData.user_data.subscription_id,
'x-fb-ck-fbp': testData.user_data.fbp,
'x-fb-ck-fbc': testData.user_data.fbc,
'currency': testData.custom_data.currency,
'value': testData.custom_data.value,
'search_term': testData.custom_data.search_string,
'transaction_id': testData.custom_data.transaction_id,
'x-fb-cd-status': testData.custom_data.status,
'x-fb-cd-content_category': testData.custom_data.content_category,
'x-fb-cd-content_name': testData.custom_data.content_name,
'x-fb-cd-content_type': testData.custom_data.content_type,
'x-fb-cd-contents': testData.custom_data.contents,
'x-fb-cd-num_items': testData.custom_data.num_items,
'x-fb-cd-predicted_ltv': testData.custom_data.predicted_ltv,
'x-fb-cd-delivery_category': testData.custom_data.delivery_category,
};
const expectedEventData = {
'event_name': testData.event_name,
'event_time': testData.event_time,
'action_source': testConfigurationData.actionSource,
'user_data': {
'client_ip_address': testData.user_data.ip_address,
'client_user_agent': testData.user_data.user_agent,
'em': testData.user_data.email,
'ph': testData.user_data.phone_number,
'fn': testData.user_data.first_name,
'ln': testData.user_data.last_name,
'ct': testData.user_data.city,
'st': testData.user_data.state,
'zp': testData.user_data.zip,
'country': testData.user_data.country,
'ge': testData.user_data.gender,
'db': testData.user_data.date_of_brith,
'external_id': testData.user_data.external_id,
'subscription_id': testData.user_data.subscription_id,
'fbp': testData.user_data.fbp,
'fbc': testData.user_data.fbc,
},
'custom_data': {
'currency': testData.custom_data.currency,
'value': testData.custom_data.value,
'search_string': testData.custom_data.search_string,
'order_id': testData.custom_data.transaction_id,
'content_category': testData.custom_data.content_category,
'content_name': testData.custom_data.content_name,
'content_type': testData.custom_data.content_type,
'contents': testData.custom_data.contents,
'num_items': testData.custom_data.num_items,
'predicted_ltv': testData.custom_data.predicted_ltv,
'status': testData.custom_data.status,
'delivery_category': testData.custom_data.delivery_category,
}
};
mock('getAllEventData', () => {
return inputEventModel;
});
const apiEndpoint = 'https://graph.facebook.com';
const apiVersion = 'v12.0';
const partnerAgent = 'gtmss-1.0.0-0.0.6';
const routeParams = 'events?access_token=' + testConfigurationData.apiAccessToken;
const requestEndpoint = [apiEndpoint,
apiVersion,
testConfigurationData.pixelId,
routeParams].join('/');
let requestData = {
data: [expectedEventData],
partner_agent: partnerAgent,
test_event_code: testData.test_event_code
};
const requestHeaderOptions = {headers: {'content-type': 'application/json'}, method: 'POST'};
let actualSuccessCallback, httpBody;
mock('sendHttpRequest', (postUrl, response, options, body) => {
actualSuccessCallback = response;
httpBody = body;
actualSuccessCallback(200, {}, '');
});
___NOTES___
Created on 8/5/2020, 10:20:28 AM