From ee3c55a5ecc23255a0af7343b0fd96c964850519 Mon Sep 17 00:00:00 2001 From: sandeepdigumarty Date: Thu, 21 Sep 2023 17:12:24 +0530 Subject: [PATCH 1/3] feat(facebook_datasets): updated fb_pixel to support facebook_datasets --- src/constants/destinationCanonicalNames.js | 1 + src/v0/destinations/facebook_pixel/config.js | 1 + .../data/FBDATASETSAppEventsConfig.json | 100 ++++++++++++++++++ .../data/FBPIXELUserDataConfig.json | 10 ++ .../destinations/facebook_pixel/transform.js | 16 ++- src/v0/destinations/facebook_pixel/utils.js | 36 ++++++- .../__tests__/data/facebook_pixel_output.json | 2 +- 7 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 src/v0/destinations/facebook_pixel/data/FBDATASETSAppEventsConfig.json diff --git a/src/constants/destinationCanonicalNames.js b/src/constants/destinationCanonicalNames.js index 6c7ec83ed9..4d2e15b2f7 100644 --- a/src/constants/destinationCanonicalNames.js +++ b/src/constants/destinationCanonicalNames.js @@ -1,5 +1,6 @@ const DestHandlerMap = { ga360: 'ga', + facebook_datasets: 'facebook_pixel', }; const DestCanonicalNames = { diff --git a/src/v0/destinations/facebook_pixel/config.js b/src/v0/destinations/facebook_pixel/config.js index 09be8e043d..62349783d7 100644 --- a/src/v0/destinations/facebook_pixel/config.js +++ b/src/v0/destinations/facebook_pixel/config.js @@ -6,6 +6,7 @@ const CONFIG_CATEGORIES = { type: 'identify', name: 'FBPIXELUserDataConfig', }, + APPDATA: { name: 'FBDATASETSAppEventsConfig' }, COMMON: { name: 'FBPIXELCommonConfig' }, SIMPLE_TRACK: { standard: false, diff --git a/src/v0/destinations/facebook_pixel/data/FBDATASETSAppEventsConfig.json b/src/v0/destinations/facebook_pixel/data/FBDATASETSAppEventsConfig.json new file mode 100644 index 0000000000..5c4b48ddfb --- /dev/null +++ b/src/v0/destinations/facebook_pixel/data/FBDATASETSAppEventsConfig.json @@ -0,0 +1,100 @@ +[ + { + "destKey": "advertiser_tracking_enabled", + "sourceKeys": "context.device.adTrackingEnabled", + "required": true + }, + { + "destKey": "application_tracking_enabled", + "sourceKeys": "properties.application_tracking_enabled", + "required": true + }, + { + "destKey": "extinfo.0", + "sourceKeys": "context.device.type", + "metadata": { + "type": "toLower" + } + }, + { + "destKey": "extinfo.1", + "sourceKeys": "context.app.namespace" + }, + { + "destKey": "extinfo.2", + "sourceKeys": "context.app.build" + }, + { + "destKey": "extinfo.3", + "sourceKeys": "context.app.version" + }, + { + "destKey": "extinfo.4", + "sourceKeys": "context.os.version", + "required": true + }, + { + "destKey": "extinfo.5", + "sourceKeys": "context.device.model" + }, + { + "destKey": "extinfo.6", + "sourceKeys": "context.locale" + }, + { + "destKey": "extinfo.7", + "sourceKeys": "context.abv_timezone" + }, + { + "destKey": "extinfo.8", + "sourceKeys": "context.network.carrier" + }, + { + "destKey": "extinfo.9", + "sourceKeys": "context.screen.width" + }, + { + "destKey": "extinfo.10", + "sourceKeys": "context.screen.height" + }, + { + "destKey": "extinfo.11", + "sourceKeys": "context.screen.density" + }, + { + "destKey": "extinfo.12", + "sourceKeys": "context.cpu_cores" + }, + { + "destKey": "extinfo.13", + "sourceKeys": "context.ext_storage_size" + }, + { + "destKey": "extinfo.14", + "sourceKeys": "context.avl_storage_size" + }, + { + "destKey": "extinfo.15", + "sourceKeys": "context.timezone" + }, + { + "destKey": "campaign_ids", + "sourceKeys": ["properties.campaignId", "context.traits.campaignId", "context.campaign.name"] + }, + { + "destKey": "install_referrer", + "sourceKeys": "properties.install_referrer" + }, + { + "destKey": "installer_package", + "sourceKeys": "properties.installer_package" + }, + { + "destKey": "url_schemes", + "sourceKeys": "properties.url_schemes" + }, + { + "destKey": "windows_attribution_id", + "sourceKeys": "properties.windows_attribution_id" + } +] diff --git a/src/v0/destinations/facebook_pixel/data/FBPIXELUserDataConfig.json b/src/v0/destinations/facebook_pixel/data/FBPIXELUserDataConfig.json index 29e7588b9d..7929f4010d 100644 --- a/src/v0/destinations/facebook_pixel/data/FBPIXELUserDataConfig.json +++ b/src/v0/destinations/facebook_pixel/data/FBPIXELUserDataConfig.json @@ -155,5 +155,15 @@ "destKey": "fb_login_id", "sourceKeys": "context.fb_login_id", "required": false + }, + { + "destKey": "madid", + "sourceKeys": "context.device.advertisingId", + "required": false + }, + { + "destKey": "anon_id", + "sourceKeys": "context.device.advertisingId", + "required": false } ] diff --git a/src/v0/destinations/facebook_pixel/transform.js b/src/v0/destinations/facebook_pixel/transform.js index c81718dea0..c9cd5e00ab 100644 --- a/src/v0/destinations/facebook_pixel/transform.js +++ b/src/v0/destinations/facebook_pixel/transform.js @@ -23,6 +23,7 @@ const { transformedPayloadData, getActionSource, fetchUserData, + fetchAppData, handleProduct, handleSearch, handleProductListViewed, @@ -34,10 +35,11 @@ const { InstrumentationError, ConfigurationError } = require('../../util/errorTy const responseBuilderSimple = (message, category, destination, categoryToContent) => { const { Config } = destination; - const { pixelId, accessToken } = Config; + const { pixelId, datasetId, accessToken } = Config; + const identifier = pixelId || datasetId; - if (!pixelId) { - throw new ConfigurationError('Pixel Id not found. Aborting'); + if (!identifier) { + throw new ConfigurationError('Pixel Id/Dataset Id not found. Aborting'); } if (!accessToken) { @@ -55,7 +57,7 @@ const responseBuilderSimple = (message, category, destination, categoryToContent } = Config; const integrationsObj = getIntegrationsObj(message, 'fb_pixel'); - const endpoint = `https://graph.facebook.com/v17.0/${pixelId}/events?access_token=${accessToken}`; + const endpoint = `https://graph.facebook.com/v17.0/${identifier}/events?access_token=${accessToken}`; const userData = fetchUserData(message, Config); @@ -177,12 +179,18 @@ const responseBuilderSimple = (message, category, destination, categoryToContent } } + let appData = {}; + if (commonData.action_source === 'app' && datasetId) { + appData = fetchAppData(message); + } + // content_category should only be a string ref: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/custom-data return formingFinalResponse( userData, commonData, customData, + appData, endpoint, testDestination, testEventCode, diff --git a/src/v0/destinations/facebook_pixel/utils.js b/src/v0/destinations/facebook_pixel/utils.js index e1347278bf..bd54ddaef1 100644 --- a/src/v0/destinations/facebook_pixel/utils.js +++ b/src/v0/destinations/facebook_pixel/utils.js @@ -7,6 +7,7 @@ const { constructPayload, defaultPostRequestConfig, defaultRequestConfig, + isAppleFamily, } = require('../../util'); const { ACTION_SOURCES_VALUES, CONFIG_CATEGORIES, MAPPING_CONFIG } = require('./config'); @@ -302,6 +303,31 @@ const fetchUserData = (message, Config) => { return userData; }; +const fetchAppData = (message) => { + const appData = constructPayload( + message, + MAPPING_CONFIG[CONFIG_CATEGORIES.APPDATA.name], + 'fb_pixel', + ); + + if (appData) { + let sourceSDK = appData.extinfo[0]; + if (sourceSDK === 'android') { + sourceSDK = 'a2'; + } else if (isAppleFamily(sourceSDK)) { + sourceSDK = 'i2'; + } else { + // if the sourceSDK is not android or ios + throw new InstrumentationError( + 'Extended device information i.e, "context.device.type" is required', + ); + } + appData.extinfo[0] = sourceSDK; + } + + return appData; +}; + /** * * @param {*} message Rudder element @@ -480,6 +506,7 @@ const formingFinalResponse = ( userData, commonData, customData, + appData, endpoint, testDestination, testEventCode, @@ -488,11 +515,15 @@ const formingFinalResponse = ( const response = defaultRequestConfig(); response.endpoint = endpoint; response.method = defaultPostRequestConfig.requestMethod; - const jsonStringify = JSON.stringify({ + const jsonData = { user_data: userData, ...commonData, custom_data: customData, - }); + }; + if (Object.keys(appData).length > 0) { + jsonData.appData = appData; + } + const jsonStringify = JSON.stringify(jsonData); const payload = { data: [jsonStringify], }; @@ -516,6 +547,7 @@ module.exports = { transformedPayloadData, getActionSource, fetchUserData, + fetchAppData, handleProduct, handleSearch, handleProductListViewed, diff --git a/test/__tests__/data/facebook_pixel_output.json b/test/__tests__/data/facebook_pixel_output.json index 3d36fd079e..a5489ab67e 100644 --- a/test/__tests__/data/facebook_pixel_output.json +++ b/test/__tests__/data/facebook_pixel_output.json @@ -743,7 +743,7 @@ } }, { - "error": "Pixel Id not found. Aborting", + "error": "Pixel Id/Dataset Id not found. Aborting", "statusCode": 400, "statTags": { "errorCategory": "dataValidation", From 7e07b5b508deabf51602c73983610ea873fb0e50 Mon Sep 17 00:00:00 2001 From: sandeepdigumarty Date: Mon, 25 Sep 2023 15:51:29 +0530 Subject: [PATCH 2/3] feat(facebook_conversions_api): renamed facebook_datasets to facebook_conversions_api --- src/constants/destinationCanonicalNames.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/destinationCanonicalNames.js b/src/constants/destinationCanonicalNames.js index 4d2e15b2f7..3d8a18e7a5 100644 --- a/src/constants/destinationCanonicalNames.js +++ b/src/constants/destinationCanonicalNames.js @@ -1,6 +1,6 @@ const DestHandlerMap = { ga360: 'ga', - facebook_datasets: 'facebook_pixel', + facebook_conversions_api: 'facebook_pixel', }; const DestCanonicalNames = { From 7164979c8b6bc3cd3026fc3c7b2819d1d7ea075d Mon Sep 17 00:00:00 2001 From: sandeepdigumarty Date: Tue, 26 Sep 2023 14:46:39 +0530 Subject: [PATCH 3/3] feat(facebook_conversions_api): add support for override action_source --- src/v0/destinations/facebook_pixel/config.js | 2 +- ...FBDATASETSAppEventsConfig.json => FBAppEventsConfig.json} | 0 src/v0/destinations/facebook_pixel/transform.js | 5 +++++ 3 files changed, 6 insertions(+), 1 deletion(-) rename src/v0/destinations/facebook_pixel/data/{FBDATASETSAppEventsConfig.json => FBAppEventsConfig.json} (100%) diff --git a/src/v0/destinations/facebook_pixel/config.js b/src/v0/destinations/facebook_pixel/config.js index 62349783d7..018cdf8dba 100644 --- a/src/v0/destinations/facebook_pixel/config.js +++ b/src/v0/destinations/facebook_pixel/config.js @@ -6,7 +6,7 @@ const CONFIG_CATEGORIES = { type: 'identify', name: 'FBPIXELUserDataConfig', }, - APPDATA: { name: 'FBDATASETSAppEventsConfig' }, + APPDATA: { name: 'FBAppEventsConfig' }, COMMON: { name: 'FBPIXELCommonConfig' }, SIMPLE_TRACK: { standard: false, diff --git a/src/v0/destinations/facebook_pixel/data/FBDATASETSAppEventsConfig.json b/src/v0/destinations/facebook_pixel/data/FBAppEventsConfig.json similarity index 100% rename from src/v0/destinations/facebook_pixel/data/FBDATASETSAppEventsConfig.json rename to src/v0/destinations/facebook_pixel/data/FBAppEventsConfig.json diff --git a/src/v0/destinations/facebook_pixel/transform.js b/src/v0/destinations/facebook_pixel/transform.js index c9cd5e00ab..5ab4bff5a3 100644 --- a/src/v0/destinations/facebook_pixel/transform.js +++ b/src/v0/destinations/facebook_pixel/transform.js @@ -54,6 +54,8 @@ const responseBuilderSimple = (message, category, destination, categoryToContent testDestination, testEventCode, standardPageCall, + overrideActionSource, + actionSource, } = Config; const integrationsObj = getIntegrationsObj(message, 'fb_pixel'); @@ -66,6 +68,9 @@ const responseBuilderSimple = (message, category, destination, categoryToContent commonData = constructPayload(message, MAPPING_CONFIG[CONFIG_CATEGORIES.COMMON.name], 'fb_pixel'); commonData.action_source = getActionSource(commonData, message?.channel); + if (overrideActionSource) { + commonData.action_source = actionSource; + } if (category.type !== 'identify') { customData = flattenJson(