-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #318 from rudderlabs/production-snap-pixel
Snap Pixel Integration
- Loading branch information
Showing
6 changed files
with
400 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
/* eslint-disable class-methods-use-this */ | ||
import get from "get-value"; | ||
import sha256 from "crypto-js/sha256"; | ||
import Storage from "../../utils/storage"; | ||
import logger from "../../utils/logUtil"; | ||
|
||
import { | ||
isDefinedAndNotNull, | ||
removeUndefinedAndNullValues, | ||
} from "../utils/commonUtils"; | ||
import { ecommEventPayload, eventPayload, sendEvent } from "./util"; | ||
|
||
class SnapPixel { | ||
constructor(config) { | ||
this.pixelId = config.pixelId; | ||
this.hashMethod = config.hashMethod; | ||
this.name = "SNAP_PIXEL"; | ||
|
||
this.trackEvents = [ | ||
"SIGN_UP", | ||
"OPEN_APP", | ||
"SAVE", | ||
"VIEW_CONTENT", | ||
"SEARCH", | ||
"SUBSCRIBE", | ||
"COMPLETE_TUTORIAL", | ||
"INVITE", | ||
"LOGIN", | ||
"SHARE", | ||
"RESERVE", | ||
"ACHIEVEMENT_UNLOCKED", | ||
"SPENT_CREDITS", | ||
"RATE", | ||
"START_TRIAL", | ||
"LIST_VIEW", | ||
]; | ||
|
||
this.ecomEvents = { | ||
PURCHASE: "PURCHASE", | ||
START_CHECKOUT: "START_CHECKOUT", | ||
ADD_CART: "ADD_CART", | ||
ADD_BILLING: "ADD_BILLING", | ||
AD_CLICK: "AD_CLICK", | ||
AD_VIEW: "AD_VIEW", | ||
ADD_TO_WISHLIST: "ADD_TO_WISHLIST", | ||
}; | ||
|
||
this.customEvents = [ | ||
"custom_event_1", | ||
"custom_event_2", | ||
"custom_event_3", | ||
"custom_event_4", | ||
"custom_event_5", | ||
]; | ||
} | ||
|
||
init() { | ||
logger.debug("===In init SnapPixel==="); | ||
|
||
(function (e, t, n) { | ||
if (e.snaptr) return; | ||
var a = (e.snaptr = function () { | ||
a.handleRequest | ||
? a.handleRequest.apply(a, arguments) | ||
: a.queue.push(arguments); | ||
}); | ||
a.queue = []; | ||
var s = "script"; | ||
var r = t.createElement(s); | ||
r.async = !0; | ||
r.src = n; | ||
var u = t.getElementsByTagName(s)[0]; | ||
u.parentNode.insertBefore(r, u); | ||
})(window, document, "https://sc-static.net/scevent.min.js"); | ||
|
||
const cookieData = Storage.getUserTraits(); | ||
|
||
let payload = { | ||
user_email: cookieData.email, | ||
user_phone_number: cookieData.phone, | ||
}; | ||
|
||
if (!payload.user_email && !payload.user_phone_number) { | ||
logger.debug( | ||
"User parameter (email or phone number) not found in cookie. identify is required" | ||
); | ||
return; | ||
} | ||
|
||
if (this.hashMethod === "sha256") { | ||
if (isDefinedAndNotNull(payload.user_email)) { | ||
payload.user_email = sha256(payload.user_email).toString(); | ||
} | ||
if (isDefinedAndNotNull(payload.user_phone_number)) { | ||
payload.user_phone_number = sha256( | ||
payload.user_phone_number | ||
).toString(); | ||
} | ||
} | ||
|
||
payload = removeUndefinedAndNullValues(payload); | ||
window.snaptr("init", this.pixelId, payload); | ||
} | ||
|
||
isLoaded() { | ||
logger.debug("===In isLoaded SnapPixel==="); | ||
return !!window.snaptr; | ||
} | ||
|
||
isReady() { | ||
logger.debug("===In isReady SnapPixel==="); | ||
return !!window.snaptr; | ||
} | ||
|
||
identify(rudderElement) { | ||
logger.debug("===In SnapPixel identify"); | ||
|
||
const { message } = rudderElement; | ||
|
||
let payload = { | ||
user_email: get(message, "context.traits.email"), | ||
user_phone_number: get(message, "context.traits.phone"), | ||
}; | ||
|
||
if (!payload.user_email && !payload.user_phone_number) { | ||
logger.error("User parameter (email or phone number) is required"); | ||
return; | ||
} | ||
|
||
if (this.hashMethod === "sha256") { | ||
if (isDefinedAndNotNull(payload.user_email)) { | ||
payload.user_email = sha256(payload.user_email).toString(); | ||
} | ||
if (isDefinedAndNotNull(payload.user_phone_number)) { | ||
payload.user_phone_number = sha256( | ||
payload.user_phone_number | ||
).toString(); | ||
} | ||
} | ||
|
||
payload = removeUndefinedAndNullValues(payload); | ||
window.snaptr("init", this.pixelId, payload); | ||
} | ||
|
||
track(rudderElement) { | ||
logger.debug("===In SnapPixel track==="); | ||
|
||
const { message } = rudderElement; | ||
const { event } = message; | ||
|
||
if (!event) { | ||
logger.error("Event name not present"); | ||
return; | ||
} | ||
|
||
switch (event.toLowerCase().trim()) { | ||
case "order completed": | ||
sendEvent(this.ecomEvents.PURCHASE, ecommEventPayload(event, message)); | ||
break; | ||
case "checkout started": | ||
sendEvent( | ||
this.ecomEvents.START_CHECKOUT, | ||
ecommEventPayload(event, message) | ||
); | ||
break; | ||
case "product added": | ||
sendEvent(this.ecomEvents.ADD_CART, ecommEventPayload(event, message)); | ||
break; | ||
case "payment info entered": | ||
sendEvent( | ||
this.ecomEvents.ADD_BILLING, | ||
ecommEventPayload(event, message) | ||
); | ||
break; | ||
case "promotion clicked": | ||
sendEvent(this.ecomEvents.AD_CLICK, ecommEventPayload(event, message)); | ||
break; | ||
case "promotion viewed": | ||
sendEvent(this.ecomEvents.AD_VIEW, ecommEventPayload(event, message)); | ||
break; | ||
case "product added to wishlist": | ||
sendEvent( | ||
this.ecomEvents.ADD_TO_WISHLIST, | ||
ecommEventPayload(event, message) | ||
); | ||
break; | ||
default: | ||
if ( | ||
!this.trackEvents.includes(event) && | ||
!this.customEvents.includes(event.trim().toLowerCase()) | ||
) { | ||
logger.error("Event doesn't match with Snap Pixel Events!"); | ||
return; | ||
} | ||
sendEvent(event, eventPayload(message)); | ||
break; | ||
} | ||
} | ||
|
||
page(rudderElement) { | ||
logger.debug("===In SnapPixel page==="); | ||
|
||
const { message } = rudderElement; | ||
sendEvent("PAGE_VIEW", eventPayload(message)); | ||
} | ||
} | ||
|
||
export default SnapPixel; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import SnapPixel from "./browser"; | ||
|
||
export default SnapPixel; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import get from "get-value"; | ||
import logger from "../../utils/logUtil"; | ||
import { | ||
isDefinedAndNotNull, | ||
isNotEmpty, | ||
removeUndefinedAndNullValues, | ||
} from "../utils/commonUtils"; | ||
|
||
const sendEvent = (event, payload) => { | ||
if (isNotEmpty(payload)) { | ||
window.snaptr("track", event, payload); | ||
} else { | ||
window.snaptr("track", event); | ||
} | ||
}; | ||
|
||
const eventPayload = (message) => { | ||
let payload = { | ||
price: get(message, "properties.price"), | ||
currency: get(message, "properties.currency"), | ||
transaction_id: get(message, "properties.transaction_id"), | ||
item_ids: get(message, "properties.item_ids"), | ||
item_category: get(message, "properties.category"), | ||
description: get(message, "properties.description"), | ||
search_string: get(message, "properties.search_string"), | ||
number_items: get(message, "properties.number_items"), | ||
payment_info_available: get(message, "properties.payment_info_available"), | ||
sign_up_method: get(message, "properties.sign_up_method"), | ||
success: get(message, "properties.success"), | ||
}; | ||
|
||
if ( | ||
payload.payment_info_available !== 0 && | ||
payload.payment_info_available !== 1 | ||
) { | ||
payload.payment_info_available = null; | ||
} | ||
if (payload.success !== 0 && payload.success !== 1) { | ||
payload.success = null; | ||
} | ||
|
||
payload = removeUndefinedAndNullValues(payload); | ||
return payload; | ||
}; | ||
|
||
const ecommEventPayload = (event, message) => { | ||
let payload = { | ||
price: get(message, "properties.price"), | ||
currency: get(message, "properties.currency"), | ||
item_category: get(message, "properties.category"), | ||
description: get(message, "properties.description"), | ||
search_string: get(message, "properties.search_string"), | ||
number_items: get(message, "properties.number_items"), | ||
payment_info_available: get(message, "properties.payment_info_available"), | ||
sign_up_method: get(message, "properties.sign_up_method"), | ||
success: get(message, "properties.success"), | ||
}; | ||
|
||
switch (event.toLowerCase().trim()) { | ||
case "order completed": { | ||
let itemIds = []; | ||
const products = get(message, "properties.products"); | ||
if (isDefinedAndNotNull(products)) { | ||
products.forEach((element, index) => { | ||
const pId = element.product_id; | ||
if (pId) { | ||
itemIds.push(pId); | ||
} else { | ||
logger.debug( | ||
`product_id not present for product at index ${index}` | ||
); | ||
} | ||
}); | ||
} else { | ||
itemIds = null; | ||
} | ||
payload = { | ||
...payload, | ||
transaction_id: get(message, "properties.order_id"), | ||
item_ids: itemIds, | ||
}; | ||
break; | ||
} | ||
case "checkout started": { | ||
let itemIds = []; | ||
const products = get(message, "properties.products"); | ||
if (isDefinedAndNotNull(products)) { | ||
products.forEach((element, index) => { | ||
const pId = element.product_id; | ||
if (pId) { | ||
itemIds.push(pId); | ||
} else { | ||
logger.debug( | ||
`product_id not present for product at index ${index}` | ||
); | ||
} | ||
}); | ||
} else { | ||
itemIds = null; | ||
} | ||
payload = { | ||
...payload, | ||
transaction_id: get(message, "properties.order_id"), | ||
item_ids: itemIds, | ||
}; | ||
break; | ||
} | ||
case "product added": { | ||
let itemIds = []; | ||
const pId = get(message, "properties.product_id"); | ||
if (isDefinedAndNotNull(pId)) { | ||
itemIds.push(pId); | ||
} else { | ||
logger.debug("product_id is not present"); | ||
itemIds = null; | ||
} | ||
payload = { | ||
...payload, | ||
transaction_id: get(message, "properties.transaction_id"), | ||
item_ids: itemIds, | ||
}; | ||
break; | ||
} | ||
case "payment info entered": | ||
payload = { | ||
...payload, | ||
transaction_id: get(message, "properties.checkout_id"), | ||
item_ids: get(message, "properties.item_ids"), | ||
}; | ||
break; | ||
case "promotion clicked": | ||
payload = { | ||
...payload, | ||
transaction_id: get(message, "properties.transaction_id"), | ||
item_ids: get(message, "properties.item_ids"), | ||
}; | ||
break; | ||
case "promotion viewed": | ||
payload = { | ||
...payload, | ||
transaction_id: get(message, "properties.transaction_id"), | ||
item_ids: get(message, "properties.item_ids"), | ||
}; | ||
break; | ||
case "product added to wishlist": { | ||
let itemIds = []; | ||
const pId = get(message, "properties.product_id"); | ||
if (isDefinedAndNotNull(pId)) { | ||
itemIds.push(pId); | ||
} else { | ||
logger.debug("product_id is not present"); | ||
itemIds = null; | ||
} | ||
payload = { | ||
...payload, | ||
transaction_id: get(message, "properties.transaction_id"), | ||
item_ids: itemIds, | ||
}; | ||
break; | ||
} | ||
default: | ||
break; | ||
} | ||
|
||
if ( | ||
payload.payment_info_available !== 0 && | ||
payload.payment_info_available !== 1 | ||
) { | ||
payload.payment_info_available = null; | ||
} | ||
if (payload.success !== 0 && payload.success !== 1) { | ||
payload.success = null; | ||
} | ||
|
||
payload = removeUndefinedAndNullValues(payload); | ||
return payload; | ||
}; | ||
|
||
export { sendEvent, ecommEventPayload, eventPayload }; |
Oops, something went wrong.