-
Notifications
You must be signed in to change notification settings - Fork 1.1k
fix: conversion not being tracked properly with builder action #4153
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
base: main
Are you sure you want to change the base?
Changes from 5 commits
86eee54
3c76be2
ffc9157
d3787e7
6267e52
835c560
9245f6d
2bacf49
c018f6f
ecdad57
a4ae75a
a07ac26
9475c04
2ff9c7f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| --- | ||
| "@builder.io/react": patch | ||
| "@builder.io/sdk": patch | ||
| "@builder.io/sdk-angular": patch | ||
| "@builder.io/sdk-react-nextjs": patch | ||
| "@builder.io/sdk-qwik": patch | ||
| "@builder.io/sdk-react": patch | ||
| "@builder.io/sdk-react-native": patch | ||
| "@builder.io/sdk-solid": patch | ||
| "@builder.io/sdk-svelte": patch | ||
| "@builder.io/sdk-vue": patch | ||
| --- | ||
|
|
||
| fix: handle conversion tracking for gen1 and gen2 sdks |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| import { getCookie, setCookie } from './cookie.js'; | ||
|
|
||
| export const testCookiePrefix = 'builder.tests'; | ||
|
|
||
| export function getTestCookie(name: string) { | ||
| return getCookie(`${testCookiePrefix}.${name}`); | ||
| } | ||
|
|
||
| function parseUrlParams(url: string): Map<string, string> { | ||
| const result = new Map<string, string>(); | ||
|
|
||
| try { | ||
| const urlObj = new URL(url); | ||
| const params = urlObj.searchParams; | ||
|
|
||
| for (const [key, value] of params) { | ||
| result.set(key, value); | ||
| } | ||
| } catch (error) { | ||
| console.debug('Error parsing URL parameters:', error); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| export function setTestCookie(contentId: string, variationId: string) { | ||
| // 30 days from now | ||
| const future = new Date(); | ||
| future.setDate(future.getDate() + 30); | ||
|
|
||
| // Use the native setCookie function directly | ||
| if (typeof window !== 'undefined') { | ||
| setCookie(`${testCookiePrefix}.${contentId}`, variationId, future); | ||
| } | ||
| } | ||
|
|
||
| export function setTestsFromUrl() { | ||
| if (typeof window === 'undefined') return; | ||
|
|
||
| try { | ||
| // Use native URL object to parse current page URL | ||
| const params = parseUrlParams(window.location.href); | ||
|
|
||
| // Look for parameters that start with 'builder.tests.' | ||
| for (const [key, value] of params) { | ||
| if (key.startsWith(`${testCookiePrefix}.`)) { | ||
| const testKey = key.replace(`${testCookiePrefix}.`, ''); | ||
| setTestCookie(testKey, value); | ||
| } | ||
| } | ||
| } catch (e) { | ||
| console.debug('Error parsing tests from URL', e); | ||
| } | ||
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| import { isBrowser } from './is-browser.js'; | ||
midhunadarvin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| export function setCookie(name: string, value: string, expires?: Date) { | ||
| try { | ||
| let expiresString = ''; | ||
|
|
||
| // TODO: need to know if secure server side | ||
| if (expires) { | ||
| expiresString = '; expires=' + expires.toUTCString(); | ||
| } | ||
|
|
||
| const secure = isBrowser() ? location.protocol === 'https:' : true; | ||
| document.cookie = | ||
| name + | ||
| '=' + | ||
| (value || '') + | ||
| expiresString + | ||
| '; path=/' + | ||
| (secure ? '; secure; SameSite=None' : ''); | ||
| } catch (err) { | ||
| console.warn('Could not set cookie', err); | ||
| } | ||
| } | ||
|
|
||
| export function getCookie(name: string) { | ||
| try { | ||
| return ( | ||
| decodeURIComponent( | ||
| document.cookie.replace( | ||
| new RegExp( | ||
| '(?:(?:^|.*;)\\s*' + | ||
| encodeURIComponent(name).replace(/[-.+*]/g, '\\$&') + | ||
| '\\s*\\=\\s*([^;]*).*$)|^.*$' | ||
| ), | ||
| '$1' | ||
| ) | ||
| ) || null | ||
| ); | ||
| } catch (err) { | ||
| console.warn('Could not get cookie', err); | ||
| return null; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,9 +2,14 @@ import type { | |
| BuilderContextInterface, | ||
| BuilderRenderState, | ||
| } from '../../context/types.js'; | ||
| import { getDefaultCanTrack } from '../../helpers/canTrack.js'; | ||
| import { getTestCookie } from '../content-variants.js'; | ||
| import { getGlobalBuilderContext } from '../global-context.js'; | ||
| import { isBrowser } from '../is-browser.js'; | ||
| import { isEditing } from '../is-editing.js'; | ||
| import { getUserAttributes } from '../track/helpers.js'; | ||
| import type { EventProps } from '../track/index.js'; | ||
| import { _track } from '../track/index.js'; | ||
|
|
||
| export type EvaluatorArgs = Omit<ExecutorArgs, 'builder' | 'event'> & { | ||
| event?: Event; | ||
|
|
@@ -15,6 +20,18 @@ export type BuilderGlobals = { | |
| isBrowser: boolean | undefined; | ||
| isServer: boolean | undefined; | ||
| getUserAttributes: typeof getUserAttributes; | ||
| track: ( | ||
| eventName: string, | ||
| properties: Partial<EventProps & { apiHost?: string }>, | ||
| context?: any | ||
| ) => void; | ||
| trackConversion: ( | ||
| amount?: number, | ||
| contentId?: string | any, | ||
| variationId?: string, | ||
| customProperties?: any, | ||
| context?: any | ||
| ) => void; | ||
| }; | ||
|
|
||
| export type ExecutorArgs = Pick< | ||
|
|
@@ -52,6 +69,56 @@ export const getBuilderGlobals = (): BuilderGlobals => ({ | |
| isBrowser: isBrowser(), | ||
| isServer: !isBrowser(), | ||
| getUserAttributes: () => getUserAttributes(), | ||
| track: ( | ||
| eventName: string, | ||
| properties: Partial<EventProps & { apiHost?: string }> = {}, | ||
| context?: any | ||
| ) => { | ||
| const builderContext = getGlobalBuilderContext(); | ||
| _track({ | ||
| type: eventName, | ||
| ...properties, | ||
| apiHost: builderContext?.apiHost, | ||
| apiKey: builderContext?.apiKey || '', | ||
| context, | ||
| canTrack: getDefaultCanTrack(properties.canTrack), | ||
| }); | ||
| }, | ||
| trackConversion: ( | ||
| amount?: number, | ||
| contentId?: string, | ||
| variationId?: string, | ||
| customProperties?: any, | ||
| context?: any | ||
| ) => { | ||
| const meta = typeof contentId === 'object' ? contentId : customProperties; | ||
| let useContentId = typeof contentId === 'string' ? contentId : undefined; | ||
| const builderContext = getGlobalBuilderContext(); | ||
|
|
||
| if (!useContentId && builderContext?.contentId) { | ||
| useContentId = builderContext.contentId; | ||
| } | ||
|
|
||
| let useVariationId = variationId; | ||
| if (!useVariationId && useContentId) { | ||
| useVariationId = getTestCookie(useContentId) || undefined; | ||
| } | ||
midhunadarvin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| _track({ | ||
| type: 'conversion', | ||
| apiHost: builderContext?.apiHost, | ||
| apiKey: builderContext?.apiKey || '', | ||
| amount: amount || undefined, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| contentId: useContentId, | ||
| variationId: | ||
| useVariationId && useContentId && useVariationId !== useContentId | ||
| ? useVariationId | ||
| : undefined, | ||
| meta, | ||
| context: context || undefined, | ||
| canTrack: getDefaultCanTrack(), | ||
| }); | ||
| }, | ||
| }); | ||
|
|
||
| export const parseCode = ( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.