medusa-google-analytics-logic 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +45 -0
- package/dist/ui-library.js +102 -0
- package/dist/ui-library.umd.cjs +1 -0
- package/package.json +48 -0
- package/readme.md +92 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meta Conversions API (CAPI) Service
|
|
3
|
+
*/
|
|
4
|
+
export declare interface CAPIEvent {
|
|
5
|
+
event_name: string;
|
|
6
|
+
action_source: 'website' | 'app' | 'physical_store' | 'system_generated' | 'other';
|
|
7
|
+
event_source_url?: string;
|
|
8
|
+
custom_data?: Record<string, any>;
|
|
9
|
+
user_data?: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export declare type CookieConsent = 'granted' | 'denied' | null;
|
|
13
|
+
|
|
14
|
+
export declare const initGTM: (id: string) => void;
|
|
15
|
+
|
|
16
|
+
export declare const pushToDataLayer: (data: Record<string, any>) => void;
|
|
17
|
+
|
|
18
|
+
export declare const sendCAPIEvent: (event: string | CAPIEvent, extraData?: Record<string, any>) => Promise<any>;
|
|
19
|
+
|
|
20
|
+
export declare const trackEvent: (eventName: string, params?: Record<string, any>) => void;
|
|
21
|
+
|
|
22
|
+
export declare const useCookieConsent: () => {
|
|
23
|
+
consent: CookieConsent;
|
|
24
|
+
acceptConsent: () => void;
|
|
25
|
+
rejectConsent: () => void;
|
|
26
|
+
isFirstVisit: boolean;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export declare const useTracking: () => {
|
|
30
|
+
trackLead: (label?: string) => Promise<void>;
|
|
31
|
+
trackCustomEvent: (event: string | CAPIEvent, extraData?: Record<string, any>) => Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { }
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Analytics Service for Google Tag Manager (GTM)
|
|
38
|
+
*/
|
|
39
|
+
declare global {
|
|
40
|
+
interface Window {
|
|
41
|
+
dataLayer: any[];
|
|
42
|
+
gtag?: (...args: any[]) => void;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { useState as g, useEffect as p, useCallback as c } from "react";
|
|
2
|
+
const m = (e) => {
|
|
3
|
+
if (typeof window > "u") return;
|
|
4
|
+
window.dataLayer = window.dataLayer || [], window.dataLayer.push({
|
|
5
|
+
"gtm.start": (/* @__PURE__ */ new Date()).getTime(),
|
|
6
|
+
event: "gtm.js"
|
|
7
|
+
});
|
|
8
|
+
const n = document.getElementsByTagName("script")[0], t = document.createElement("script"), a = "";
|
|
9
|
+
t.async = !0, t.src = "https://www.googletagmanager.com/gtm.js?id=" + e + a, n.parentNode && n.parentNode.insertBefore(t, n);
|
|
10
|
+
}, y = (e) => {
|
|
11
|
+
typeof window > "u" || (window.dataLayer = window.dataLayer || [], window.dataLayer.push(e));
|
|
12
|
+
}, d = (e, n) => {
|
|
13
|
+
y({
|
|
14
|
+
event: e,
|
|
15
|
+
...n
|
|
16
|
+
});
|
|
17
|
+
}, i = async (e, n) => {
|
|
18
|
+
var s;
|
|
19
|
+
if (typeof window > "u") return;
|
|
20
|
+
const t = (s = document.querySelector('meta[name="csrf-token"]')) == null ? void 0 : s.content, a = typeof e == "string" ? { event: e, ...n } : {
|
|
21
|
+
event_name: e.event_name,
|
|
22
|
+
action_source: e.action_source || "website",
|
|
23
|
+
event_source_url: e.event_source_url || window.location.href,
|
|
24
|
+
custom_data: e.custom_data,
|
|
25
|
+
user_data: e.user_data || {},
|
|
26
|
+
...n
|
|
27
|
+
};
|
|
28
|
+
try {
|
|
29
|
+
const o = await fetch("/meta/event", {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: {
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
"X-CSRF-TOKEN": t || ""
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify(a)
|
|
36
|
+
}), w = o.headers.get("content-type") || "";
|
|
37
|
+
let r;
|
|
38
|
+
if (w.includes("application/json"))
|
|
39
|
+
r = await o.json();
|
|
40
|
+
else {
|
|
41
|
+
const u = await o.text();
|
|
42
|
+
try {
|
|
43
|
+
r = JSON.parse(u);
|
|
44
|
+
} catch {
|
|
45
|
+
r = { success: o.ok };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return console.log("CAPI Event Sent:", r), r;
|
|
49
|
+
} catch (o) {
|
|
50
|
+
throw console.error("CAPI Error:", o), o;
|
|
51
|
+
}
|
|
52
|
+
}, _ = () => {
|
|
53
|
+
const [e, n] = g(null);
|
|
54
|
+
p(() => {
|
|
55
|
+
if (typeof window > "u") return;
|
|
56
|
+
const o = localStorage.getItem("cookie_consent");
|
|
57
|
+
n(o);
|
|
58
|
+
}, []);
|
|
59
|
+
const t = (o) => {
|
|
60
|
+
typeof window > "u" || (localStorage.setItem("cookie_consent", o), n(o), o === "granted" ? (typeof window.gtag == "function" && (window.gtag("consent", "update", {
|
|
61
|
+
ad_storage: "granted",
|
|
62
|
+
analytics_storage: "granted",
|
|
63
|
+
ad_user_data: "granted",
|
|
64
|
+
ad_personalization: "granted"
|
|
65
|
+
}), window.gtag("event", "page_view")), window.dataLayer = window.dataLayer || [], window.dataLayer.push({
|
|
66
|
+
event: "cookie_accept"
|
|
67
|
+
})) : (window.dataLayer = window.dataLayer || [], window.dataLayer.push({
|
|
68
|
+
event: "cookie_consent_update",
|
|
69
|
+
ad_storage: "denied",
|
|
70
|
+
analytics_storage: "denied"
|
|
71
|
+
})));
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
consent: e,
|
|
75
|
+
acceptConsent: () => t("granted"),
|
|
76
|
+
rejectConsent: () => t("denied"),
|
|
77
|
+
isFirstVisit: e === null
|
|
78
|
+
};
|
|
79
|
+
}, L = () => {
|
|
80
|
+
const e = c(async (t) => {
|
|
81
|
+
d("Lead", { label: t }), await i("Lead", {
|
|
82
|
+
custom_data: {
|
|
83
|
+
button_name: t
|
|
84
|
+
}
|
|
85
|
+
}), console.log(`Lead tracked with label: ${t}`);
|
|
86
|
+
}, []), n = c(async (t, a) => {
|
|
87
|
+
const s = typeof t == "string" ? t : t.event_name;
|
|
88
|
+
d(s, a), await i(t, a);
|
|
89
|
+
}, []);
|
|
90
|
+
return {
|
|
91
|
+
trackLead: e,
|
|
92
|
+
trackCustomEvent: n
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
export {
|
|
96
|
+
m as initGTM,
|
|
97
|
+
y as pushToDataLayer,
|
|
98
|
+
i as sendCAPIEvent,
|
|
99
|
+
d as trackEvent,
|
|
100
|
+
_ as useCookieConsent,
|
|
101
|
+
L as useTracking
|
|
102
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(a,s){typeof exports=="object"&&typeof module<"u"?s(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],s):(a=typeof globalThis<"u"?globalThis:a||self,s(a.MedusaAnalyticsLogic={},a.React))})(this,function(a,s){"use strict";const f=e=>{if(typeof window>"u")return;window.dataLayer=window.dataLayer||[],window.dataLayer.push({"gtm.start":new Date().getTime(),event:"gtm.js"});const n=document.getElementsByTagName("script")[0],t=document.createElement("script"),d="";t.async=!0,t.src="https://www.googletagmanager.com/gtm.js?id="+e+d,n.parentNode&&n.parentNode.insertBefore(t,n)},w=e=>{typeof window>"u"||(window.dataLayer=window.dataLayer||[],window.dataLayer.push(e))},r=(e,n)=>{w({event:e,...n})},u=async(e,n)=>{var c;if(typeof window>"u")return;const t=(c=document.querySelector('meta[name="csrf-token"]'))==null?void 0:c.content,d=typeof e=="string"?{event:e,...n}:{event_name:e.event_name,action_source:e.action_source||"website",event_source_url:e.event_source_url||window.location.href,custom_data:e.custom_data,user_data:e.user_data||{},...n};try{const o=await fetch("/meta/event",{method:"POST",headers:{"Content-Type":"application/json","X-CSRF-TOKEN":t||""},body:JSON.stringify(d)}),p=o.headers.get("content-type")||"";let i;if(p.includes("application/json"))i=await o.json();else{const l=await o.text();try{i=JSON.parse(l)}catch{i={success:o.ok}}}return console.log("CAPI Event Sent:",i),i}catch(o){throw console.error("CAPI Error:",o),o}},y=()=>{const[e,n]=s.useState(null);s.useEffect(()=>{if(typeof window>"u")return;const o=localStorage.getItem("cookie_consent");n(o)},[]);const t=o=>{typeof window>"u"||(localStorage.setItem("cookie_consent",o),n(o),o==="granted"?(typeof window.gtag=="function"&&(window.gtag("consent","update",{ad_storage:"granted",analytics_storage:"granted",ad_user_data:"granted",ad_personalization:"granted"}),window.gtag("event","page_view")),window.dataLayer=window.dataLayer||[],window.dataLayer.push({event:"cookie_accept"})):(window.dataLayer=window.dataLayer||[],window.dataLayer.push({event:"cookie_consent_update",ad_storage:"denied",analytics_storage:"denied"})))};return{consent:e,acceptConsent:()=>t("granted"),rejectConsent:()=>t("denied"),isFirstVisit:e===null}},g=()=>{const e=s.useCallback(async t=>{r("Lead",{label:t}),await u("Lead",{custom_data:{button_name:t}}),console.log(`Lead tracked with label: ${t}`)},[]),n=s.useCallback(async(t,d)=>{const c=typeof t=="string"?t:t.event_name;r(c,d),await u(t,d)},[]);return{trackLead:e,trackCustomEvent:n}};a.initGTM=f,a.pushToDataLayer=w,a.sendCAPIEvent=u,a.trackEvent=r,a.useCookieConsent=y,a.useTracking=g,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "medusa-google-analytics-logic",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Unified Google Analytics (GTM) and Meta Conversions API (CAPI) tracking for Medusa.js storefronts.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"medusa-plugin",
|
|
7
|
+
"google-analytics",
|
|
8
|
+
"gtm",
|
|
9
|
+
"meta-capi",
|
|
10
|
+
"tracking"
|
|
11
|
+
],
|
|
12
|
+
"author": "SmartByte Labs",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "./dist/ui-library.umd.cjs",
|
|
16
|
+
"module": "./dist/ui-library.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"import": "./dist/ui-library.js",
|
|
21
|
+
"require": "./dist/ui-library.umd.cjs",
|
|
22
|
+
"types": "./dist/index.d.ts"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"dev": "vite",
|
|
30
|
+
"build": "tsc && vite build",
|
|
31
|
+
"preview": "vite preview"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
35
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.0.0",
|
|
39
|
+
"@types/react": "^18.0.0 || ^19.0.0",
|
|
40
|
+
"@types/react-dom": "^18.0.0 || ^19.0.0",
|
|
41
|
+
"@vitejs/plugin-react": "^4.0.0",
|
|
42
|
+
"react": "^19.0.0",
|
|
43
|
+
"react-dom": "^19.0.0",
|
|
44
|
+
"typescript": "^5.0.0",
|
|
45
|
+
"vite": "^5.0.0",
|
|
46
|
+
"vite-plugin-dts": "^3.0.0"
|
|
47
|
+
}
|
|
48
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Medusa Google Analytics Logic
|
|
2
|
+
|
|
3
|
+
This package provides a unified interface for Google Tag Manager (GTM) and Meta Conversions API (CAPI) tracking.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install medusa-google-analytics-logic
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Local Development
|
|
12
|
+
|
|
13
|
+
For local testing, use `npm link` in this directory and then `npm link medusa-google-analytics-logic` in your consumer project.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### 1. Initialization
|
|
18
|
+
|
|
19
|
+
Initialize GTM in your application's entry point (e.g., `main.tsx` or `_app.tsx`):
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { initGTM } from 'medusa-google-analytics-logic';
|
|
23
|
+
|
|
24
|
+
initGTM('GTM-XXXXXXX');
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Tracking Hook
|
|
28
|
+
|
|
29
|
+
Use the `useTracking` hook to track events:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { useTracking } from 'medusa-google-analytics-logic';
|
|
33
|
+
|
|
34
|
+
const MyComponent = () => {
|
|
35
|
+
const { trackLead, trackCustomEvent } = useTracking();
|
|
36
|
+
|
|
37
|
+
const handleSignup = async () => {
|
|
38
|
+
await trackLead('Signup Form');
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const handlePurchase = async () => {
|
|
42
|
+
await trackCustomEvent('Purchase', {
|
|
43
|
+
value: 99.99,
|
|
44
|
+
currency: 'USD'
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div>
|
|
50
|
+
<button onClick={handleSignup}>Track Lead</button>
|
|
51
|
+
<button onClick={handlePurchase}>Track Purchase</button>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 3. Cookie Consent Hook
|
|
58
|
+
|
|
59
|
+
Manage user consent with `useCookieConsent`:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { useCookieConsent } from 'medusa-google-analytics-logic';
|
|
63
|
+
|
|
64
|
+
const CookieBanner = () => {
|
|
65
|
+
const { consent, acceptConsent, rejectConsent, isFirstVisit } = useCookieConsent();
|
|
66
|
+
|
|
67
|
+
if (!isFirstVisit) return null;
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<div className="banner">
|
|
71
|
+
<p>We use cookies for analytics and ads.</p>
|
|
72
|
+
<button onClick={acceptConsent}>Accept</button>
|
|
73
|
+
<button onClick={rejectConsent}>Decline</button>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 4. Meta CAPI
|
|
80
|
+
|
|
81
|
+
The `useTracking` hook automatically sends events to Meta Conversions API via a `/meta/event` endpoint. Ensure your server handles this endpoint and includes the necessary Meta Pixel ID and Access Token.
|
|
82
|
+
|
|
83
|
+
## API Reference
|
|
84
|
+
|
|
85
|
+
### Services
|
|
86
|
+
- `initGTM(id: string)`: Initializes Google Tag Manager.
|
|
87
|
+
- `trackEvent(eventName: string, params?: object)`: Pushes a GTM event to the `dataLayer`.
|
|
88
|
+
- `sendCAPIEvent(event: string | CAPIEvent, extraData?: object)`: Sends a request to the CAPI proxy.
|
|
89
|
+
|
|
90
|
+
### Hooks
|
|
91
|
+
- `useTracking()`: Returns `trackLead` and `trackCustomEvent`.
|
|
92
|
+
- `useCookieConsent()`: Manages local storage consent and GTM consent mode updates.
|