Skip to content

Commit b28376b

Browse files
committed
add trackLead and trackSale method
1 parent ff7776e commit b28376b

File tree

7 files changed

+189
-0
lines changed

7 files changed

+189
-0
lines changed

apps/html/conversion-tracking.html

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<meta name="description" content="Your website description" />
7+
<title>Client Conversion Tracking</title>
8+
</head>
9+
<body>
10+
<script>
11+
!(function (w, da) {
12+
w[da] =
13+
w[da] ||
14+
function () {
15+
(w[da].q = w[da].q || []).push(arguments);
16+
};
17+
18+
['trackClick', 'trackLead', 'trackSale'].forEach(function (m) {
19+
w[da][m] = function () {
20+
w[da](m, ...arguments);
21+
};
22+
});
23+
})(window, 'dubAnalytics');
24+
</script>
25+
26+
<script>
27+
// Add a 3-second delay before loading the script to test queue functionality
28+
setTimeout(() => {
29+
const script = document.createElement('script');
30+
script.defer = true;
31+
script.src = './analytics/script.client-conversion-tracking.js';
32+
script.setAttribute('data-api-host', 'http://api.localhost:8888');
33+
script.setAttribute(
34+
'data-publishable-key',
35+
'dub_pk_BgyBCEJCPCGN3RN7oieLVHRs',
36+
);
37+
document.head.appendChild(script);
38+
}, 3000);
39+
</script>
40+
41+
<header>
42+
<h1>Client Conversion Tracking</h1>
43+
<button
44+
onclick="dubAnalytics.trackLead({
45+
clickId: 'W13FJbgeLIGdlx7s',
46+
eventName: 'Account created',
47+
customerExternalId: '1234567890',
48+
customerName: 'John Doe',
49+
customerEmail: '[email protected]',
50+
})"
51+
>
52+
Track Lead
53+
</button>
54+
55+
<button
56+
onclick="dubAnalytics.trackSale({
57+
customerExternalId: 'CXvG5QOLi8QKBA2jYmDh',
58+
paymentProcessor: 'stripe',
59+
invoiceId: Math.random().toString(36).substring(2, 15),
60+
amount: 5000,
61+
currency: 'usd',
62+
})"
63+
>
64+
Track Sale
65+
</button>
66+
</header>
67+
</body>
68+
</html>

packages/script/build.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ Promise.all([
6262
outfile: 'dist/analytics/script.outbound-domains.js',
6363
}),
6464

65+
// Client conversion tracking
66+
esbuild.build({
67+
...baseConfig,
68+
stdin: {
69+
contents: combineFiles([
70+
'src/base.js',
71+
'src/extensions/client-conversion-tracking.js',
72+
]),
73+
resolveDir: __dirname,
74+
sourcefile: 'combined.js',
75+
},
76+
outfile: 'dist/analytics/script.client-conversion-tracking.js',
77+
}),
78+
6579
// Complete script with concatenated feature names
6680
esbuild.build({
6781
...baseConfig,

packages/script/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"dist/analytics/script.js",
77
"dist/analytics/script.site-visit.js",
88
"dist/analytics/script.outbound-domains.js",
9+
"dist/analytics/script.client-conversion-tracking.js",
910
"dist/analytics/script.site-visit.outbound-domains.js"
1011
],
1112
"scripts": {

packages/script/src/base.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
// Common script attributes
1111
const API_HOST = script.getAttribute('data-api-host') || 'https://api.dub.co';
12+
const PUBLISHABLE_KEY = script.getAttribute('data-publishable-key');
1213
const COOKIE_OPTIONS = (() => {
1314
const defaultOptions = {
1415
domain:
@@ -271,6 +272,7 @@
271272
p: QUERY_PARAM, // was QUERY_PARAM
272273
v: QUERY_PARAM_VALUE, // was QUERY_PARAM_VALUE
273274
n: DOMAINS_CONFIG, // was DOMAINS_CONFIG
275+
k: PUBLISHABLE_KEY,
274276
};
275277

276278
// Initialize
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
const initClientConversionTracking = () => {
2+
console.debug('Running initClientConversionTracking');
3+
4+
const { a: API_HOST, k: PUBLISHABLE_KEY } = window._dubAnalytics;
5+
6+
console.log({
7+
API_HOST,
8+
PUBLISHABLE_KEY,
9+
});
10+
11+
// Track lead conversion
12+
const trackLead = async (input) => {
13+
console.debug('Calling trackLead', input);
14+
15+
const response = await fetch(`${API_HOST}/track/lead/client`, {
16+
method: 'POST',
17+
headers: {
18+
'Content-Type': 'application/json',
19+
Authorization: `Bearer ${PUBLISHABLE_KEY}`,
20+
},
21+
body: JSON.stringify(input),
22+
});
23+
24+
const result = await response.json();
25+
26+
if (!response.ok) {
27+
console.error('[dubAnalytics] trackLead failed', result.error);
28+
}
29+
30+
return result;
31+
};
32+
33+
// Track sale conversion
34+
const trackSale = async (input) => {
35+
console.debug('Calling trackSale', input);
36+
37+
const response = await fetch(`${API_HOST}/track/sale/client`, {
38+
method: 'POST',
39+
headers: {
40+
'Content-Type': 'application/json',
41+
Authorization: `Bearer ${PUBLISHABLE_KEY}`,
42+
},
43+
body: JSON.stringify(input),
44+
});
45+
46+
const result = await response.json();
47+
48+
if (!response.ok) {
49+
console.error('[dubAnalytics] trackSale failed', result.error);
50+
}
51+
52+
return result;
53+
};
54+
55+
// Process the queued events
56+
if (window.dubAnalytics) {
57+
const original = window.dubAnalytics;
58+
const queue = original.q || [];
59+
60+
// Create a callable function
61+
// Eg: dubAnalytics('trackLead', {});
62+
function dubAnalytics(method, ...args) {
63+
if (method === 'trackLead') {
64+
trackLead(...args);
65+
} else if (method === 'trackSale') {
66+
trackSale(...args);
67+
} else {
68+
console.warn('[dubAnalytics] Unknown method:', method);
69+
}
70+
}
71+
72+
dubAnalytics.q = queue;
73+
74+
dubAnalytics.trackLead = function (...args) {
75+
trackLead(...args);
76+
};
77+
78+
dubAnalytics.trackSale = function (...args) {
79+
trackSale(...args);
80+
};
81+
82+
window.dubAnalytics = {
83+
...original,
84+
...dubAnalytics,
85+
};
86+
}
87+
};
88+
89+
// Run when base script is ready
90+
if (window._dubAnalytics) {
91+
initClientConversionTracking();
92+
} else {
93+
window.addEventListener('load', initClientConversionTracking);
94+
}

packages/web/src/generic.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ function inject(props: AnalyticsProps): void {
5151
script.setAttribute('data-api-host', props.apiHost);
5252
}
5353

54+
if (props.publishableKey) {
55+
script.setAttribute('data-publishable-key', props.publishableKey);
56+
}
57+
5458
if (props.domainsConfig) {
5559
script.setAttribute('data-domains', JSON.stringify(props.domainsConfig));
5660
}

packages/web/src/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ export interface AnalyticsProps {
77
*/
88
apiHost?: string;
99

10+
/**
11+
* The publishable key for client conversion tracking
12+
* @example 'dub_pk_BgyBCEJCPCGN3RN7oieLVHRs'
13+
*/
14+
publishableKey?: string;
15+
1016
/**
1117
* This is a JSON object that configures the domains that Dub will track.
1218
*

0 commit comments

Comments
 (0)