Skip to content

Commit 5504604

Browse files
authored
UTM Source handling (#326)
* UTM Source handling * Add UTM campaign sources * Updated observable events page
1 parent 2bb0061 commit 5504604

File tree

4 files changed

+168
-16
lines changed

4 files changed

+168
-16
lines changed

docs/subscriptions/observable-events.mdx

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,40 @@ title: Observable Events
33
nav_label: Observable Events
44
sidebar_position: 100
55
---
6-
You can integrate Subscriptions with external systems like enterprise resource planning, fulfilment and other systems. For example, when a subscriber updates their address, the Customer Relationship Management system is updated with the change.
76

8-
Events are actions that occur in Subscriptions, such as a subscriber changing their address or a subscription changing from active to inactive. You can create custom functions that perform additional processing outside of Subscriptions, and create integrations so that when an event occurs in your store, the custom function is run.
7+
# Observable Events in Subscriptions
98

10-
Events are processed concurrently. This means that events may not be delivered in the order they are created. For example, if a subscription is updated multiple times, the events may not be delivered in the same sequence they were updated. Events operate on an "at least once" delivery policy. We aim to deliver messages within 30 minutes or less. Ensure that you design your receiving code accordingly.
9+
## Overview
10+
Observable events allow you to integrate Subscriptions with external systems like ERP, fulfillment, and CRM platforms. When specific actions occur within Subscriptions (such as address updates or status changes), these events can trigger custom functions to perform additional processing or update external systems.
1111

12-
For more information about integrating Subscriptions, see [**Integration Types**](/docs/api/integrations/integrations-introduction#integration-types).
12+
## Event Processing Behavior
13+
- Events are processed concurrently and may not be delivered in chronological order
14+
- Events follow an "at least once" delivery policy
15+
- Target delivery time is within 30 minutes
16+
- Integration code should be designed to handle out-of-order and duplicate events
1317

14-
| Resource | Action | Observable Key | Availability |
15-
| --- | --- | --- | --- |
16-
| Product | <ul><li>Created</li><li>Updated</li><li>Deleted</li></ul> | <ul><li>`subscription-product.created`</li><li>`subscription-product.updated`</li><li>`subscription-product.deleted`</li></ul> | Store |
17-
| Plan | <ul><li>Created</li><li>Updated</li><li>Deleted</li></ul> | <ul><li>`subscription-plan.created`</li><li>`subscription-plan.updated`</li><li>`subscription-plan.deleted`</li></ul> | Store |
18-
| Offering | <ul><li>Created</li><li>Updated</li><li>Deleted</li></ul> | <ul><li>`subscription-offering.created`</li><li>`subscription-offering.updated`</li><li>`subscription-offering.deleted`</li></ul> | Store |
19-
| Subscription | <ul><li>Created</li><li>Create-failed</li><li>Paused</li><li>Canceled</li><li>Pending-cancel</li><li>Pending-pause</li><li>Resumed</li><li>Closed</li></ul> | <ul><li>`subscription.created`</li><li>`subscription.create-failed`</li><li>`subscription.canceled`</li><li>`subscription.paused`</li><li>`subscription.pending_cancel`</li><li>`subscription.pending_pause`</li><li>`subscription.resumed`</li><li>`subscription.closed`</li></ul> | Store |
20-
| Job | <ul><li>Created</li><li>Updated</li><li>Deleted</li></ul> | <ul><li>`subscription-job.created`</li><li>`subscription-job.updated`</li><li>`subscription-job.deleted`</li></ul> | Store |
21-
| Invoices | <ul><li>Created</li><li>Deleted</li></ul> | <ul><li>`subscription-invoice.created`</li><li>`subscription-offering.deleted`</li></ul> | Store |
22-
| Schedule | <ul><li>Created</li><li>Updated</li><li>Deleted</li></ul> | <ul><li>`subscription-schedule.created`</li><li>`subscription-schedule.updated`</li><li>`subscription-schedule.deleted`</li></ul> | Store |
23-
| Subscriber | <ul><li>Created</li><li>Updated</li><li>Deleted</li></ul> | <ul><li>`subscription-subscriber.created`</li><li>`subscription-subscriber.updated`</li><li>`subscription-subscriber.deleted`</li></ul> | Store |
18+
For detailed information about integration options, see [**Integration Types**](/docs/api/integrations/integrations-introduction#integration-types).
19+
20+
## Available Events
21+
22+
### Subscription Management
23+
| Resource | Actions | Observable Keys |
24+
|----------|---------|-----------------|
25+
| Subscription | • Created<br/>• Create-failed<br/>• Paused<br/>• Canceled<br/>• Pending-cancel<br/>• Pending-pause<br/>• Resumed<br/>• Closed | `subscription.created`<br/>`subscription.create-failed`<br/>`subscription.paused`<br/>`subscription.canceled`<br/>`subscription.pending_cancel`<br/>`subscription.pending_pause`<br/>`subscription.resumed`<br/>`subscription.closed` |
26+
| Subscriber | • Created<br/>• Updated<br/>• Deleted | `subscription-subscriber.created`<br/>`subscription-subscriber.updated`<br/>`subscription-subscriber.deleted` |
27+
28+
### Product Configuration
29+
| Resource | Actions | Observable Keys |
30+
|----------|---------|-----------------|
31+
| Product | • Created<br/>• Updated<br/>• Deleted | `subscription-product.created`<br/>`subscription-product.updated`<br/>`subscription-product.deleted` |
32+
| Plan | • Created<br/>• Updated<br/>• Deleted | `subscription-plan.created`<br/>`subscription-plan.updated`<br/>`subscription-plan.deleted` |
33+
| Offering | • Created<br/>• Updated<br/>• Deleted | `subscription-offering.created`<br/>`subscription-offering.updated`<br/>`subscription-offering.deleted` |
34+
35+
### Operations
36+
| Resource | Actions | Observable Keys |
37+
|----------|---------|-----------------|
38+
| Job | • Created<br/>• Updated<br/>• Deleted | `subscription-job.created`<br/>`subscription-job.updated`<br/>`subscription-job.deleted` |
39+
| Invoices | • Created<br/>• Deleted | `subscription-invoice.created`<br/>`subscription-invoice.deleted` |
40+
| Schedule | • Created<br/>• Updated<br/>• Deleted | `subscription-schedule.created`<br/>`subscription-schedule.updated`<br/>`subscription-schedule.deleted` |
41+
42+
> **Note**: All events are available at the Store level.

docusaurus.config.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,12 @@ const config = {
252252
{
253253
label: "Changelog",
254254
to: "/changelog-landing",
255+
datautmcampaign: "changelog",
255256
},
256257
{
257258
label: "Support",
258259
to: "https://support.elasticpath.com",
260+
dataUtmCampaign: "support",
259261
},
260262
{
261263
type: "search",
@@ -266,12 +268,14 @@ const config = {
266268
href: "https://www.elasticpath.com/get-in-touch",
267269
position: "right",
268270
className: "navbar-book-demo",
271+
dataUtmCampaign: "get-in-touch",
269272
},
270273
{
271274
label: "Free Trial",
272275
href: "https://useast.cm.elasticpath.com/free-trial",
273276
position: "right",
274277
className: "dev-portal-signup dev-portal-link",
278+
dataUtmCampaign: "free-trial",
275279
},
276280
],
277281
},
@@ -313,7 +317,7 @@ const config = {
313317
},
314318
{
315319
label: "GitHub",
316-
href: "https://github.com/facebook/docusaurus",
320+
href: "https://github.com/elasticpath",
317321
},
318322
],
319323
},
@@ -1329,7 +1333,7 @@ const config = {
13291333
{ to: '/docs/studio/Settings/Domain-Management/Connecting-your-Namecheap-Domain', from: '/docs/cx-studio/Settings/Domain-Management/Connecting-your-Namecheap-Domain'},
13301334
{ to: '/docs/api/pxm/catalog/get-catalog-by-id', from: '/docs/pxm/catalogs/catalog-configuration/get-all-catalogs'},
13311335
{ to: '/docs/api/carts/transactions', from: '/docs/commerce-cloud/payments/transactions/get-all-transactions'},
1332-
{ to: '/docs/api/pxm/catalog/get-by-context-all-nodes', from: '/docs/pxm/catalogs/shopper-catalog/get-a-hierarchys-nodes'},
1336+
{ to: '/docs/api/pxm/catalog/get-by-context-all-hierarchies', from: '/docs/pxm/catalogs/shopper-catalog/get-a-hierarchys-nodes'},
13331337
{ to: '/changelog/Studio-Release-Notes/Release-190-February-14-2024', from: '/docs/cx-studio/Release-Notes/Release-190-February-14-2024'},
13341338
{ to: '/changelog/Studio-Release-Notes/Release-190-February-14-2024', from: '/docs/cx-studio/Release-Notes/Release-191-February-27-2024'},
13351339
{ to: '/docs/api/pxm/products/build-child-products', from: '/docs/pxm/products/pxm-product-variations/child-products-api/build-child-products'},
@@ -1653,6 +1657,12 @@ const config = {
16531657
}),
16541658
],
16551659
],
1660+
scripts: [
1661+
{
1662+
src: '/js/utm-handler.js',
1663+
async: true,
1664+
},
1665+
],
16561666
};
16571667

16581668
module.exports = config;

src/snippets/resourceDOCS.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
onmouseover="document.body.setAttribute('docs-menu', 'cm')"
4141
class="flex cursor-pointer !mt-2 items-start justify-start gap-2 border-none bg-transparent text-black dark:text-white"
4242
href="/ui"
43+
datautmcampaign="commerce-manager"
4344
>
4445
<div class="flex-shrink-0">
4546
<img
@@ -62,6 +63,7 @@
6263
onmouseover="document.body.setAttribute('docs-menu', 'pxm')"
6364
class="flex cursor-pointer !mt-2 items-start justify-start gap-2 border-none bg-transparent text-black dark:text-white"
6465
href="/pxm"
66+
datautmcampaign="pxm"
6567
>
6668
<div class="flex-shrink-0">
6769
<img
@@ -84,6 +86,7 @@
8486
onmouseover="document.body.setAttribute('docs-menu', 'subs')"
8587
class="flex cursor-pointer !mt-2 items-start justify-start gap-2 border-none bg-transparent text-black dark:text-white"
8688
href="/subscriptions"
89+
datautmcampaign="subscriptions"
8790
>
8891
<div class="flex-shrink-0">
8992
<img
@@ -106,6 +109,7 @@
106109
onmouseover="document.body.setAttribute('docs-menu', 'carts')"
107110
class="flex cursor-pointer !mt-2 items-start justify-start gap-2 border-none bg-transparent text-black dark:text-white"
108111
href="/orders"
112+
datautmcampaign="carts"
109113
>
110114
<div class="flex-shrink-0">
111115
<img
@@ -146,6 +150,7 @@
146150
onmouseover="document.body.setAttribute('docs-menu', 'studio')"
147151
class="flex cursor-pointer !mt-2 items-start justify-start gap-2 border-none bg-transparent text-black dark:text-white"
148152
href="/docs/studio"
153+
datautmcampaign="studio"
149154
>
150155
<div class="flex-shrink-0">
151156
<img
@@ -168,6 +173,7 @@
168173
onmouseover="document.body.setAttribute('docs-menu', 'composer')"
169174
class="flex cursor-pointer !mt-2 items-start justify-start gap-2 border-none bg-transparent text-black dark:text-white"
170175
href="/docs/composer"
176+
datautmcampaign="composer"
171177
>
172178
<div class="flex-shrink-0">
173179
<img
@@ -190,6 +196,7 @@
190196
onmouseover="document.body.setAttribute('docs-menu', 'payments')"
191197
class="flex cursor-pointer !mt-2 items-start justify-start gap-2 border-none bg-transparent text-black dark:text-white"
192198
href="/docs/payments"
199+
datautmcampaign="payments"
193200
>
194201
<div class="flex-shrink-0">
195202
<img
@@ -212,6 +219,7 @@
212219
onmouseover="document.body.setAttribute('docs-menu', 'developer')"
213220
class="flex cursor-pointer !mt-2 items-start justify-start gap-2 border-none bg-transparent text-black dark:text-white"
214221
href="/docs/developer-tools"
222+
datautmcampaign="developer-tools"
215223
>
216224
<div class="flex-shrink-0">
217225
<img
@@ -235,6 +243,7 @@
235243
class="flex cursor-pointer !mt-4 items-start justify-start gap-2 border-none bg-transparent text-black dark:text-white"
236244
href="https://documentation.elasticpath.com"
237245
target="_blank"
246+
datautmcampaign="self-managed"
238247
>
239248
<div class="flex-shrink-0">
240249
<img

static/js/utm-handler.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Default UTM parameters
2+
const DEFAULT_UTM = {
3+
utm_source: 'elastic-path-dev',
4+
utm_medium: 'dev-site',
5+
utm_campaign: 'fy25q1-dev'
6+
};
7+
8+
// Campaign mapping for different buttons
9+
const CAMPAIGN_MAPPING = {
10+
'support': 'fy25q1-dev-support',
11+
'freetrial': 'fy25q1-dev-free-trial',
12+
'docs': 'fy25q1-dev-documentation',
13+
'get-in-touch': 'fy25q1-dev-get-in-touch',
14+
'guides': 'fy25q1-dev-guides',
15+
'videos': 'fy25q1-dev-videos',
16+
'api': 'fy25q1-dev-api',
17+
'sample-apps': 'fy25q1-dev-sample-apps',
18+
'changelog': 'fy25q1-dev-changelog',
19+
'commerce-manager': 'fy25q1-dev-commerce-manager',
20+
'pxm': 'fy25q1-dev-pxm',
21+
'subscriptions': 'fy25q1-dev-subscriptions',
22+
'carts': 'fy25q1-dev-carts',
23+
'studio': 'fy25q1-dev-studio',
24+
'composer': 'fy25q1-dev-composer',
25+
'payments': 'fy25q1-dev-payments',
26+
'developer-tools': 'fy25q1-dev-developer-tools',
27+
'self-managed': 'fy25q1-dev-self-managed',
28+
// Add more campaign mappings as needed
29+
};
30+
31+
// Get UTM params from URL if they exist
32+
function getUrlUtmParams() {
33+
const urlParams = new URLSearchParams(window.location.search);
34+
const utmParams = {};
35+
36+
['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'].forEach(param => {
37+
if (urlParams.has(param)) {
38+
utmParams[param] = urlParams.get(param);
39+
}
40+
});
41+
42+
return utmParams;
43+
}
44+
45+
// Store UTM params in sessionStorage
46+
function storeUtmParams(params) {
47+
sessionStorage.setItem('utmParams', JSON.stringify(params));
48+
}
49+
50+
// Get stored UTM params
51+
function getStoredUtmParams() {
52+
const stored = sessionStorage.getItem('utmParams');
53+
return stored ? JSON.parse(stored) : null;
54+
}
55+
56+
// Add UTM params to a URL
57+
function addUtmToUrl(url, campaignType) {
58+
try {
59+
const urlObj = new URL(url);
60+
61+
// Don't modify external URLs
62+
if (!urlObj.hostname.includes('elasticpath.dev')) {
63+
return url;
64+
}
65+
66+
// Get stored or default UTM params
67+
const utmParams = getStoredUtmParams() || {...DEFAULT_UTM};
68+
69+
// Override campaign if specified
70+
if (campaignType && CAMPAIGN_MAPPING[campaignType]) {
71+
utmParams.utm_campaign = CAMPAIGN_MAPPING[campaignType];
72+
}
73+
74+
// Add UTM params to URL
75+
Object.entries(utmParams).forEach(([key, value]) => {
76+
urlObj.searchParams.set(key, value);
77+
});
78+
79+
return urlObj.toString();
80+
} catch (e) {
81+
// Return original URL if invalid
82+
return url;
83+
}
84+
}
85+
86+
// Initialize UTM handling
87+
function initUtmHandler() {
88+
// Store UTM params from URL if present
89+
const urlUtmParams = getUrlUtmParams();
90+
if (Object.keys(urlUtmParams).length > 0) {
91+
storeUtmParams(urlUtmParams);
92+
}
93+
94+
// Add click event listener to handle links
95+
document.addEventListener('click', (e) => {
96+
const link = e.target.closest('a');
97+
if (link && link.href) {
98+
// Get the campaign type from the data attribute
99+
const campaignType = link.getAttribute('datautmcampaign');
100+
const modifiedUrl = addUtmToUrl(link.href, campaignType);
101+
if (modifiedUrl !== link.href) {
102+
e.preventDefault();
103+
window.location.href = modifiedUrl;
104+
}
105+
}
106+
});
107+
}
108+
109+
// Run when DOM is loaded
110+
if (document.readyState === 'loading') {
111+
document.addEventListener('DOMContentLoaded', initUtmHandler);
112+
} else {
113+
initUtmHandler();
114+
}

0 commit comments

Comments
 (0)