Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add campaign object support in web pixel events #3973

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While these are the standard parameters, there can be custom UTM values like utm_xyz. We should support them too.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@saikumarrs can they be transformed in similar way by just removing utm_ prefix ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Let me get this too

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed @saikumarrs

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"sourceKeys": "utm_campaign",
"destKeys": "name"
},
{
"sourceKeys": "utm_medium",
"destKeys": "medium"
},
{
"sourceKeys": "utm_term",
"destKeys": "term"
},
{
"sourceKeys": "utm_content",
"destKeys": "content"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const {
checkoutStepEventBuilder,
searchEventBuilder,
} = require('./pixelUtils');
const campaignObjectMappings = require('../pixelEventsMappings/campaignObjectMappings.json');
const {
INTEGERATION,
PIXEL_EVENT_TOPICS,
Expand Down Expand Up @@ -85,7 +86,7 @@ const handleCartTokenRedisOperations = async (inputEvent, clientId) => {

function processPixelEvent(inputEvent) {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { name, query_parameters, clientId, data, id } = inputEvent;
const { name, query_parameters, context, clientId, data, id } = inputEvent;
const shopifyDetails = { ...inputEvent };
delete shopifyDetails.context;
delete shopifyDetails.query_parameters;
Expand Down Expand Up @@ -147,6 +148,36 @@ function processPixelEvent(inputEvent) {
});
message.setProperty('context.topic', name);
message.setProperty('context.shopifyDetails', shopifyDetails);

// adding campaign object to the message
if (context?.document?.location?.href) {
const url = new URL(context.document.location.href);
const campaignParams = {};

// Loop through mappings and extract UTM parameters
campaignObjectMappings.forEach((mapping) => {
const value = url.searchParams.get(mapping.sourceKeys);
if (value) {
campaignParams[mapping.destKeys] = value;
}
});

// Extract any UTM parameters not in the mappings
const campaignObjectSourceKeys = campaignObjectMappings.flatMap(
(mapping) => mapping.sourceKeys,
);
url.searchParams.forEach((value, key) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not forEach((key, value) ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, campaignParams[key] will get campaign { } keys, and value will be the utm values in the href

if (key.startsWith('utm_') && !campaignObjectSourceKeys.includes(key)) {
campaignParams[key] = value;
}
});

// Only add campaign object if we have any UTM parameters
if (Object.keys(campaignParams).length > 0) {
message.context = message.context || {};
message.context.campaign = campaignParams;
}
}
message.messageId = id;
message = removeUndefinedAndNullValues(message);
return message;
Expand Down
141 changes: 110 additions & 31 deletions test/integrations/sources/shopify/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,58 @@
const dummyResponseCommonPayload = {
navigator: {
language: 'en-US',
cookieEnabled: true,
languages: ['en-US', 'en'],
userAgent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36',
},
window: {
innerHeight: 1028,
innerWidth: 1362,
outerHeight: 1080,
outerWidth: 1728,
pageXOffset: 0,
pageYOffset: 0,
location: {
href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU',
hash: '',
host: 'store.myshopify.com',
hostname: 'store.myshopify.com',
origin: 'https://store.myshopify.com',
pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU',
port: '',
protocol: 'https:',
search: '',
},
origin: 'https://store.myshopify.com',
screen: {
height: 1117,
width: 1728,
},
screenX: 0,
screenY: 37,
scrollX: 0,
scrollY: 0,
},
page: {
title: 'Checkout - pixel-testing-rs',
url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU',
path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU',
search: '',
},
userAgent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36',
screen: {
height: 1117,
width: 1728,
},
library: {
name: 'RudderStack Shopify Cloud',
eventOrigin: 'client',
version: '2.0.0',
},
};

export const dummySourceConfig = {
ID: 'dummy-source-id',
OriginalID: '',
Expand Down Expand Up @@ -83,25 +138,10 @@ export const dummyContext = {
},
};

export const note_attributes = [
{
name: 'cartId',
value: '9c623f099fc8819aa4d6a958b65dfe7d',
},
{
name: 'cartToken',
value: 'Z2NwLXVzLWVhc3QxOjAxSkQzNUFXVEI4VkVUNUpTTk1LSzBCMzlF',
},
{
name: 'rudderAnonymousId',
value: '50ead33e-d763-4854-b0ab-765859ef05cb',
},
];

export const responseDummyContext = {
export const dummyContextwithCampaign = {
document: {
location: {
href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU',
href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU?checkout%5Bpayment_gateway%5D=shopify_payments&utm_campaign=shopifySale&utm_medium=checkout&utm_term=term_checkout&utm_content=web&utm_custom1=customutm&tag=tag',
hash: '',
host: 'store.myshopify.com',
hostname: 'store.myshopify.com',
Expand Down Expand Up @@ -150,21 +190,60 @@ export const responseDummyContext = {
scrollX: 0,
scrollY: 0,
},
page: {
title: 'Checkout - pixel-testing-rs',
url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU',
path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU',
search: '',
};

export const note_attributes = [
{
name: 'cartId',
value: '9c623f099fc8819aa4d6a958b65dfe7d',
},
userAgent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36',
screen: {
height: 1117,
width: 1728,
{
name: 'cartToken',
value: 'Z2NwLXVzLWVhc3QxOjAxSkQzNUFXVEI4VkVUNUpTTk1LSzBCMzlF',
},
library: {
name: 'RudderStack Shopify Cloud',
eventOrigin: 'client',
version: '2.0.0',
{
name: 'rudderAnonymousId',
value: '50ead33e-d763-4854-b0ab-765859ef05cb',
},
];

export const responseDummyContext = {
document: {
location: {
href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU',
hash: '',
host: 'store.myshopify.com',
hostname: 'store.myshopify.com',
origin: 'https://store.myshopify.com',
pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU',
port: '',
protocol: 'https:',
search: '',
},
referrer: 'https://store.myshopify.com/cart',
characterSet: 'UTF-8',
title: 'Checkout - pixel-testing-rs',
},
...dummyResponseCommonPayload,
};

export const responseDummyContextwithCampaign = {
document: {
location: {
href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU?checkout%5Bpayment_gateway%5D=shopify_payments&utm_campaign=shopifySale&utm_medium=checkout&utm_term=term_checkout&utm_content=web&utm_custom1=customutm&tag=tag',
hash: '',
host: 'store.myshopify.com',
hostname: 'store.myshopify.com',
origin: 'https://store.myshopify.com',
pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU',
port: '',
protocol: 'https:',
search: '',
},
referrer: 'https://store.myshopify.com/cart',
title: 'Checkout - pixel-testing-rs',
characterSet: 'UTF-8',
},
// title: 'Checkout - pixel-testing-rs',
...dummyResponseCommonPayload,
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
// This file contains the test scenarios related to Shopify pixel events, emitted from web pixel on the browser.
import { dummyContext, dummySourceConfig, responseDummyContext } from '../constants';
import {
dummyContext,
dummyContextwithCampaign,
dummySourceConfig,
responseDummyContext,
responseDummyContextwithCampaign,
} from '../constants';

export const pixelEventsTestScenarios = [
{
Expand All @@ -18,7 +24,7 @@ export const pixelEventsTestScenarios = [
type: 'standard',
clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750',
timestamp: '2024-09-15T17:24:30.373Z',
context: dummyContext,
context: dummyContextwithCampaign,
pixelEventLabel: true,
query_parameters: {
topic: ['page_viewed'],
Expand All @@ -42,7 +48,14 @@ export const pixelEventsTestScenarios = [
batch: [
{
context: {
...responseDummyContext,
...responseDummyContextwithCampaign,
campaign: {
content: 'web',
medium: 'checkout',
name: 'shopifySale',
term: 'term_checkout',
utm_custom1: 'customutm',
},
shopifyDetails: {
clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750',
data: {},
Expand Down
Loading