├── .gitignore
├── .eslintignore
├── src
├── types.d.ts
└── index.ts
├── .idea
├── vcs.xml
├── jsLinters
│ └── eslint.xml
├── .gitignore
├── inspectionProfiles
│ └── Project_Default.xml
├── facebook-conversion-api.iml
└── modules.xml
├── .eslintrc.js
├── tsconfig.json
├── package.json
├── dist
├── index.d.ts
└── index.js
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 |
--------------------------------------------------------------------------------
/src/types.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'facebook-nodejs-business-sdk';
2 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/jsLinters/eslint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/facebook-conversion-api.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | commonjs: true,
5 | es2021: true,
6 | },
7 | extends: [
8 | 'airbnb-base',
9 | ],
10 | parser: '@typescript-eslint/parser',
11 | parserOptions: {
12 | ecmaVersion: 12,
13 | },
14 | plugins: [
15 | '@typescript-eslint',
16 | ],
17 | };
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "target": "es6",
5 | "module": "commonjs",
6 | "outDir": "./dist",
7 | "rootDir": "./src",
8 | "strict": true,
9 | "moduleResolution": "node",
10 | "esModuleInterop": true,
11 | "declaration": true,
12 | },
13 | "exclude": [
14 | "./dist",
15 | "./node_modules",
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@rivercode/facebook-conversion-api",
3 | "version": "1.1.8",
4 | "description": "Facebook Conversion API Wrapper for Node.js",
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "scripts": {
8 | "lint": "eslint . --ext .ts",
9 | "lint:tsc": "tsc",
10 | "watch": "tsc --watch",
11 | "build": "tsc --build",
12 | "test": "echo \"Error: no test specified\" && exit 1"
13 | },
14 | "repository": {
15 | "type": "git",
16 | "url": "git+https://github.com/RivercodeAB/facebook-conversion-api.git"
17 | },
18 | "author": "Rivercode",
19 | "license": "ISC",
20 | "bugs": {
21 | "url": "https://github.com/RivercodeAB/facebook-conversion-api/issues"
22 | },
23 | "homepage": "https://github.com/RivercodeAB/facebook-conversion-api#readme",
24 | "dependencies": {
25 | "facebook-nodejs-business-sdk": "^13.0.0"
26 | },
27 | "devDependencies": {
28 | "@types/node": "^16.7.1",
29 | "@typescript-eslint/eslint-plugin": "^4.29.3",
30 | "@typescript-eslint/parser": "^4.29.3",
31 | "eslint": "^7.32.0",
32 | "eslint-config-airbnb-base": "^14.2.1",
33 | "eslint-plugin-import": "^2.24.1",
34 | "typescript": "^4.3.5"
35 | },
36 | "keywords": [
37 | "facebook-conversion-api",
38 | "fb-conversion-api",
39 | "node",
40 | "typescript"
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/dist/index.d.ts:
--------------------------------------------------------------------------------
1 | declare class FacebookConversionAPI {
2 | #private;
3 | accessToken: string;
4 | pixelId: string;
5 | fbp: string | null;
6 | fbc: string | null;
7 | userData: any;
8 | contents: any;
9 | debug: boolean;
10 | /**
11 | * Constructor.
12 | *
13 | * @param accessToken
14 | * @param pixelId
15 | * @param emails
16 | * @param phones
17 | * @param clientIpAddress
18 | * @param clientUserAgent
19 | * @param fbp
20 | * @param fbc
21 | * @param debug
22 | */
23 | constructor(accessToken: string, pixelId: string, emails: Array | null, phones: Array | null, clientIpAddress: string, clientUserAgent: string, fbp: string | null, fbc: string | null, debug?: boolean);
24 | /**
25 | * Add product to contents array.
26 | *
27 | * @param sku
28 | * @param quantity
29 | */
30 | addProduct(sku: string, quantity: number): void;
31 | /**
32 | * Send event to Facebook Conversion API and clear contents array after event is fired.
33 | *
34 | * @param eventName
35 | * @param sourceUrl
36 | * @param purchaseData
37 | * @param eventData
38 | */
39 | sendEvent(eventName: string, sourceUrl: string, purchaseData?: {
40 | value?: number;
41 | currency?: string;
42 | }, eventData?: {
43 | eventId?: string;
44 | }): void;
45 | }
46 | export default FacebookConversionAPI;
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Facebook Conversion API
2 |
3 | > Node.js wrapper for [Facebook's Conversion API](https://developers.facebook.com/docs/marketing-api/conversions-api/)
4 |
5 | ## Install
6 |
7 | ```bash
8 | npm install @rivercode/facebook-conversion-api
9 | ```
10 |
11 | ## Initiate Facebook Conversion API
12 | ```node
13 | // ES6 import or TypeScript
14 | import FacebookConversionAPI from '@rivercode/facebook-conversion-api';
15 | // CommonJS
16 | const FacebookConversionAPI = require('@rivercode/facebook-conversion-api').default;
17 |
18 | const FBConversionAPI = new FacebookConversionAPI(
19 | 'accessToken',
20 | 'pixelId',
21 | ['email1', 'email2'], // or null
22 | ['phone1', 'phone2'], // or null
23 | 'clientIpAddress',
24 | 'clientUserAgent',
25 | 'fbp', // or null
26 | 'fpc', // or null
27 | 'debug', // default to false
28 | );
29 | ```
30 |
31 | Read more here on how you can get your [access token](https://developers.facebook.com/docs/marketing-api/conversions-api/get-started/#access-token) and [fbp/fpc identifiers](https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc/).
32 |
33 | ### ViewContent Event
34 | ```node
35 | FBConversionAPI.addProduct('productSku', quantity);
36 | FBConversionAPI.sendEvent('ViewContent', sourceUrl, { value: 1000, currency: 'USD' }, { eventId: 'eventId' });
37 | ```
38 |
39 | ### Add To Cart Event
40 | ```node
41 | FBConversionAPI.addProduct('productSku', quantity);
42 | FBConversionAPI.sendEvent('AddToCart', sourceUrl, { value: 1000, currency: 'USD' }, { eventId: 'eventId' });
43 | ```
44 |
45 | ### Initiate Checkout Event
46 | ```node
47 | FBConversionAPI.addProduct('productSku', quantity);
48 | FBConversionAPI.sendEvent('InitiateCheckout', sourceUrl, { value: 1000, currency: 'USD' }, { eventId: 'eventId' });
49 | ```
50 |
51 | ### Purchase Event
52 | ```node
53 | FBConversionAPI.addProduct('productSku', quantity);
54 | FBConversionAPI.sendEvent('Purchase', sourceUrl, { value: 1000, currency: 'USD' }, { eventId: 'eventId' });
55 | ```
56 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-explicit-any */
2 | const bizSdk = require('facebook-nodejs-business-sdk');
3 |
4 | class FacebookConversionAPI {
5 | accessToken: string;
6 |
7 | pixelId: string;
8 |
9 | fbp: string | null;
10 |
11 | fbc: string | null;
12 |
13 | userData: any;
14 |
15 | contents: any;
16 |
17 | debug: boolean;
18 |
19 | /**
20 | * Constructor.
21 | *
22 | * @param accessToken
23 | * @param pixelId
24 | * @param emails
25 | * @param phones
26 | * @param clientIpAddress
27 | * @param clientUserAgent
28 | * @param fbp
29 | * @param fbc
30 | * @param debug
31 | */
32 | constructor(
33 | accessToken: string, pixelId: string, emails: Array|null,
34 | phones: Array|null, clientIpAddress: string, clientUserAgent: string,
35 | fbp: string | null, fbc: string | null, debug: boolean = false,
36 | ) {
37 | this.accessToken = accessToken;
38 | this.pixelId = pixelId;
39 | this.fbp = fbp;
40 | this.fbc = fbc;
41 | this.debug = debug;
42 | this.userData = (new bizSdk.UserData())
43 | .setEmails(emails)
44 | .setPhones(phones)
45 | .setClientIpAddress(clientIpAddress)
46 | .setClientUserAgent(clientUserAgent)
47 | .setFbp(fbp)
48 | .setFbc(fbc);
49 | this.contents = [];
50 |
51 | if (this.debug) {
52 | console.log(`User Data: ${JSON.stringify(this.userData)}\n`);
53 | }
54 | }
55 |
56 | /**
57 | * Add product to contents array.
58 | *
59 | * @param sku
60 | * @param quantity
61 | */
62 | addProduct(sku: string, quantity: number): void {
63 | this.contents.push((new bizSdk.Content()).setId(sku).setQuantity(quantity));
64 |
65 | if (this.debug) {
66 | console.log(`Add To Cart: ${JSON.stringify(this.contents)}\n`);
67 | }
68 | }
69 |
70 | /**
71 | * Send event to Facebook Conversion API and clear contents array after event is fired.
72 | *
73 | * @param eventName
74 | * @param sourceUrl
75 | * @param purchaseData
76 | * @param eventData
77 | */
78 | sendEvent(
79 | eventName: string, sourceUrl: string,
80 | purchaseData?: { value?: number, currency?: string }, eventData?: { eventId?: string },
81 | ): void {
82 | const eventRequest = (new bizSdk.EventRequest(this.accessToken, this.pixelId))
83 | .setEvents([this.#getEventData(eventName, sourceUrl, purchaseData, eventData)]);
84 |
85 | this.contents = [];
86 |
87 | eventRequest.execute().then(
88 | (response: any) => response,
89 | (error: any) => error,
90 | );
91 |
92 | if (this.debug) {
93 | console.log(`Event Request: ${JSON.stringify(eventRequest)}\n`);
94 | }
95 | }
96 |
97 | /**
98 | * Get event data.
99 | *
100 | * @param eventName
101 | * @param sourceUrl
102 | * @param purchaseData
103 | * @param eventData
104 | */
105 | #getEventData(
106 | eventName: string,
107 | sourceUrl: string,
108 | purchaseData?: { value?: number, currency?: string },
109 | eventData?: { eventId?: string },
110 | ): any {
111 | const currentTimestamp = Math.floor(new Date() as any / 1000);
112 |
113 | return (new bizSdk.ServerEvent())
114 | .setEventName(eventName)
115 | .setEventTime(currentTimestamp)
116 | .setEventId(eventData?.eventId)
117 | .setUserData(this.userData)
118 | .setCustomData((new bizSdk.CustomData())
119 | .setContents(this.contents)
120 | .setCurrency(purchaseData?.currency)
121 | .setValue(purchaseData?.value))
122 | .setEventSourceUrl(sourceUrl)
123 | .setActionSource('website');
124 | }
125 | }
126 |
127 | export default FacebookConversionAPI;
128 |
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3 | if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4 | if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5 | return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6 | };
7 | var _FacebookConversionAPI_instances, _FacebookConversionAPI_getEventData;
8 | Object.defineProperty(exports, "__esModule", { value: true });
9 | /* eslint-disable @typescript-eslint/no-explicit-any */
10 | const bizSdk = require('facebook-nodejs-business-sdk');
11 | class FacebookConversionAPI {
12 | /**
13 | * Constructor.
14 | *
15 | * @param accessToken
16 | * @param pixelId
17 | * @param emails
18 | * @param phones
19 | * @param clientIpAddress
20 | * @param clientUserAgent
21 | * @param fbp
22 | * @param fbc
23 | * @param debug
24 | */
25 | constructor(accessToken, pixelId, emails, phones, clientIpAddress, clientUserAgent, fbp, fbc, debug = false) {
26 | _FacebookConversionAPI_instances.add(this);
27 | this.accessToken = accessToken;
28 | this.pixelId = pixelId;
29 | this.fbp = fbp;
30 | this.fbc = fbc;
31 | this.debug = debug;
32 | this.userData = (new bizSdk.UserData())
33 | .setEmails(emails)
34 | .setPhones(phones)
35 | .setClientIpAddress(clientIpAddress)
36 | .setClientUserAgent(clientUserAgent)
37 | .setFbp(fbp)
38 | .setFbc(fbc);
39 | this.contents = [];
40 | if (this.debug) {
41 | console.log(`User Data: ${JSON.stringify(this.userData)}\n`);
42 | }
43 | }
44 | /**
45 | * Add product to contents array.
46 | *
47 | * @param sku
48 | * @param quantity
49 | */
50 | addProduct(sku, quantity) {
51 | this.contents.push((new bizSdk.Content()).setId(sku).setQuantity(quantity));
52 | if (this.debug) {
53 | console.log(`Add To Cart: ${JSON.stringify(this.contents)}\n`);
54 | }
55 | }
56 | /**
57 | * Send event to Facebook Conversion API and clear contents array after event is fired.
58 | *
59 | * @param eventName
60 | * @param sourceUrl
61 | * @param purchaseData
62 | * @param eventData
63 | */
64 | sendEvent(eventName, sourceUrl, purchaseData, eventData) {
65 | const eventRequest = (new bizSdk.EventRequest(this.accessToken, this.pixelId))
66 | .setEvents([__classPrivateFieldGet(this, _FacebookConversionAPI_instances, "m", _FacebookConversionAPI_getEventData).call(this, eventName, sourceUrl, purchaseData, eventData)]);
67 | this.contents = [];
68 | eventRequest.execute().then((response) => response, (error) => error);
69 | if (this.debug) {
70 | console.log(`Event Request: ${JSON.stringify(eventRequest)}\n`);
71 | }
72 | }
73 | }
74 | _FacebookConversionAPI_instances = new WeakSet(), _FacebookConversionAPI_getEventData = function _FacebookConversionAPI_getEventData(eventName, sourceUrl, purchaseData, eventData) {
75 | const currentTimestamp = Math.floor(new Date() / 1000);
76 | return (new bizSdk.ServerEvent())
77 | .setEventName(eventName)
78 | .setEventTime(currentTimestamp)
79 | .setEventId(eventData === null || eventData === void 0 ? void 0 : eventData.eventId)
80 | .setUserData(this.userData)
81 | .setCustomData((new bizSdk.CustomData())
82 | .setContents(this.contents)
83 | .setCurrency(purchaseData === null || purchaseData === void 0 ? void 0 : purchaseData.currency)
84 | .setValue(purchaseData === null || purchaseData === void 0 ? void 0 : purchaseData.value))
85 | .setEventSourceUrl(sourceUrl)
86 | .setActionSource('website');
87 | };
88 | exports.default = FacebookConversionAPI;
89 |
--------------------------------------------------------------------------------