@codeswayam/analytics 0.1.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/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # @codeswayam/analytics
2
+
3
+ **Version:** 0.1.0
4
+
5
+ Centralized analytics and tracking package for all CodeSwayam applications. A single `<Analytics />` component that loads GTM, GA4, Meta Pixel, Hotjar, and Microsoft Clarity — plus Google Search Console verification — all configurable from the Admin Panel or environment variables.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @codeswayam/analytics
13
+ ```
14
+
15
+ **Peer dependencies:** `react ^19`, `next ^16`
16
+
17
+ ---
18
+
19
+ ## Setup
20
+
21
+ Add `<Analytics />` to your app's root layout. All props are optional — only the tools you pass IDs for will be loaded.
22
+
23
+ ```tsx
24
+ // app/layout.tsx
25
+ import { Analytics } from '@codeswayam/analytics';
26
+
27
+ export default function RootLayout({ children }) {
28
+ return (
29
+ <html>
30
+ <body>
31
+ <Analytics
32
+ gtmId={process.env.NEXT_PUBLIC_GTM_ID}
33
+ ga4Id={process.env.NEXT_PUBLIC_GA4_ID}
34
+ metaPixelId={process.env.NEXT_PUBLIC_META_PIXEL_ID}
35
+ gscVerification={process.env.NEXT_PUBLIC_GSC_VERIFICATION}
36
+ hotjarId={process.env.NEXT_PUBLIC_HOTJAR_ID}
37
+ clarityId={process.env.NEXT_PUBLIC_CLARITY_ID}
38
+ appName="web"
39
+ />
40
+ {children}
41
+ </body>
42
+ </html>
43
+ );
44
+ }
45
+ ```
46
+
47
+ > If no IDs are provided, the component renders nothing.
48
+
49
+ ---
50
+
51
+ ## Props
52
+
53
+ | Prop | Type | Description |
54
+ |------|------|-------------|
55
+ | `gtmId` | `string` | Google Tag Manager container ID (e.g. `GTM-XXXXXX`) |
56
+ | `ga4Id` | `string` | GA4 Measurement ID (e.g. `G-XXXXXXXXXX`). Skipped if `gtmId` is set — GTM handles GA4 |
57
+ | `metaPixelId` | `string` | Meta (Facebook) Pixel ID |
58
+ | `gscVerification` | `string` | Google Search Console meta verification code |
59
+ | `hotjarId` | `string` | Hotjar Site ID |
60
+ | `clarityId` | `string` | Microsoft Clarity Project ID |
61
+ | `appName` | `string` | Pushed to `dataLayer` as `appName` for GTM filtering across apps |
62
+
63
+ ---
64
+
65
+ ## Dynamic Config from Admin Panel
66
+
67
+ Fetch analytics IDs from the core-api at runtime — no redeploy needed when IDs change.
68
+
69
+ ```tsx
70
+ // app/layout.tsx (server component)
71
+ import { Analytics, getAnalyticsConfig } from '@codeswayam/analytics';
72
+
73
+ export default async function RootLayout({ children }) {
74
+ const config = await getAnalyticsConfig('web'); // fetches from /admin/analytics/config/web
75
+
76
+ return (
77
+ <html>
78
+ <body>
79
+ <Analytics {...config} appName="web" />
80
+ {children}
81
+ </body>
82
+ </html>
83
+ );
84
+ }
85
+ ```
86
+
87
+ `getAnalyticsConfig(appId)` fetches from `{API_URL}/admin/analytics/config/{appId}` with a 5-minute Next.js cache (`revalidate: 300`). Falls back to an empty config on error.
88
+
89
+ ### App IDs
90
+
91
+ | App | `appId` |
92
+ |-----|---------|
93
+ | codeswayam-web | `web` |
94
+ | codeswayam-auth | `auth` |
95
+ | Auraflow | `auraflow` |
96
+ | EMS Frontend | `ems` |
97
+ | NeuralHub | `neural` |
98
+
99
+ ---
100
+
101
+ ## Custom Event Tracking
102
+
103
+ ```tsx
104
+ import { trackEvent } from '@codeswayam/analytics';
105
+
106
+ // Fires to GTM dataLayer + Meta Pixel
107
+ trackEvent('button_click', { button_id: 'cta-hero', page: '/home' });
108
+ ```
109
+
110
+ ## Page View Tracking
111
+
112
+ ```tsx
113
+ import { trackPageView } from '@codeswayam/analytics';
114
+
115
+ trackPageView('/dashboard');
116
+ // Pushes page_view to dataLayer + fires Meta Pixel PageView
117
+ ```
118
+
119
+ Both functions are no-ops on the server (SSR-safe).
120
+
121
+ ---
122
+
123
+ ## Environment Variables
124
+
125
+ | Variable | Description |
126
+ |----------|-------------|
127
+ | `NEXT_PUBLIC_GTM_ID` | Google Tag Manager container ID |
128
+ | `NEXT_PUBLIC_GA4_ID` | GA4 Measurement ID |
129
+ | `NEXT_PUBLIC_META_PIXEL_ID` | Meta Pixel ID |
130
+ | `NEXT_PUBLIC_GSC_VERIFICATION` | Google Search Console verification code |
131
+ | `NEXT_PUBLIC_HOTJAR_ID` | Hotjar Site ID |
132
+ | `NEXT_PUBLIC_CLARITY_ID` | Microsoft Clarity Project ID |
133
+ | `NEXT_PUBLIC_API_URL` / `API_URL` | Core API base URL (for `getAnalyticsConfig`) |
134
+
135
+ ---
136
+
137
+ ## Exports
138
+
139
+ ```typescript
140
+ Analytics // React component — loads all tracking scripts
141
+ getAnalyticsConfig // Server utility — fetches config from core-api
142
+ trackEvent // Fire a custom event to GTM dataLayer + Meta Pixel
143
+ trackPageView // Fire a page view event
144
+ AnalyticsConfig // TypeScript interface for the config shape
145
+ ```
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@codeswayam/analytics",
3
+ "version": "0.1.0",
4
+ "description": "Centralized analytics and tracking for CodeSwayam apps",
5
+ "main": "./src/index.tsx",
6
+ "types": "./src/index.tsx",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "dev": "tsc --watch"
10
+ },
11
+ "dependencies": {
12
+ "react": "^19.2.3",
13
+ "next": "^16.2.4"
14
+ },
15
+ "devDependencies": {
16
+ "@types/react": "^19",
17
+ "typescript": "^5"
18
+ },
19
+ "peerDependencies": {
20
+ "react": "^19.2.3",
21
+ "next": "^16.2.4"
22
+ }
23
+ }
@@ -0,0 +1,118 @@
1
+ 'use client';
2
+
3
+ import Script from 'next/script';
4
+
5
+ export interface AnalyticsConfig {
6
+ gtmId?: string;
7
+ ga4Id?: string;
8
+ metaPixelId?: string;
9
+ gscVerification?: string;
10
+ hotjarId?: string;
11
+ clarityId?: string;
12
+ }
13
+
14
+ interface AnalyticsProps extends AnalyticsConfig {
15
+ appName?: string;
16
+ }
17
+
18
+ export function Analytics({
19
+ gtmId,
20
+ ga4Id,
21
+ metaPixelId,
22
+ gscVerification,
23
+ hotjarId,
24
+ clarityId,
25
+ appName,
26
+ }: AnalyticsProps) {
27
+ if (!gtmId && !ga4Id && !metaPixelId && !hotjarId && !clarityId) return null;
28
+
29
+ return (
30
+ <>
31
+ {gscVerification && (
32
+ <meta name="google-site-verification" content={gscVerification} />
33
+ )}
34
+
35
+ {gtmId && (
36
+ <>
37
+ <Script id="gtm-script" strategy="afterInteractive">
38
+ {`(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
39
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
40
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
41
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
42
+ })(window,document,'script','dataLayer','${gtmId}');
43
+ ${appName ? `window.dataLayer=window.dataLayer||[];window.dataLayer.push({'appName':'${appName}'});` : ''}`}
44
+ </Script>
45
+ <noscript>
46
+ <iframe src={`https://www.googletagmanager.com/ns.html?id=${gtmId}`}
47
+ height="0" width="0" style={{ display: 'none', visibility: 'hidden' }} />
48
+ </noscript>
49
+ </>
50
+ )}
51
+
52
+ {ga4Id && !gtmId && (
53
+ <>
54
+ <Script src={`https://www.googletagmanager.com/gtag/js?id=${ga4Id}`} strategy="afterInteractive" />
55
+ <Script id="ga4-script" strategy="afterInteractive">
56
+ {`window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}
57
+ gtag('js',new Date());gtag('config','${ga4Id}',{'send_page_view':true});`}
58
+ </Script>
59
+ </>
60
+ )}
61
+
62
+ {metaPixelId && (
63
+ <>
64
+ <Script id="meta-pixel" strategy="afterInteractive">
65
+ {`!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
66
+ n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
67
+ n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
68
+ t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
69
+ document,'script','https://connect.facebook.net/en_US/fbevents.js');
70
+ fbq('init','${metaPixelId}');fbq('track','PageView');`}
71
+ </Script>
72
+ <noscript>
73
+ <img height="1" width="1" style={{ display: 'none' }}
74
+ src={`https://www.facebook.com/tr?id=${metaPixelId}&ev=PageView&noscript=1`} alt="" />
75
+ </noscript>
76
+ </>
77
+ )}
78
+
79
+ {hotjarId && (
80
+ <Script id="hotjar-script" strategy="afterInteractive">
81
+ {`(function(h,o,t,j,a,r){h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
82
+ h._hjSettings={hjid:${hotjarId},hjsv:6};a=o.getElementsByTagName('head')[0];
83
+ r=o.createElement('script');r.async=1;r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
84
+ a.appendChild(r);})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');`}
85
+ </Script>
86
+ )}
87
+
88
+ {clarityId && (
89
+ <Script id="clarity-script" strategy="afterInteractive">
90
+ {`(function(c,l,a,r,i,t,y){c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
91
+ t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
92
+ y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
93
+ })(window,document,"clarity","script","${clarityId}");`}
94
+ </Script>
95
+ )}
96
+ </>
97
+ );
98
+ }
99
+
100
+ export function trackEvent(eventName: string, eventData?: Record<string, any>) {
101
+ if (typeof window === 'undefined') return;
102
+ if (window.dataLayer) window.dataLayer.push({ event: eventName, ...eventData });
103
+ if (window.fbq) window.fbq('trackCustom', eventName, eventData);
104
+ }
105
+
106
+ export function trackPageView(url: string) {
107
+ if (typeof window === 'undefined') return;
108
+ if (window.dataLayer) window.dataLayer.push({ event: 'page_view', page_path: url });
109
+ if (window.fbq) window.fbq('track', 'PageView');
110
+ }
111
+
112
+ declare global {
113
+ interface Window {
114
+ dataLayer: any[];
115
+ fbq: any;
116
+ gtag: (...args: any[]) => void;
117
+ }
118
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,3 @@
1
+ export { Analytics, trackEvent, trackPageView } from './Analytics';
2
+ export type { AnalyticsConfig } from './Analytics';
3
+ export { getAnalyticsConfig } from './server';
package/src/server.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { AnalyticsConfig } from './Analytics';
2
+
3
+ /**
4
+ * Fetch analytics config for a given appId from the core-api.
5
+ * Call this in your Next.js root layout (server component).
6
+ *
7
+ * Usage:
8
+ * const config = await getAnalyticsConfig('web');
9
+ * <Analytics {...config} appName="web" />
10
+ */
11
+ export async function getAnalyticsConfig(appId: string): Promise<AnalyticsConfig> {
12
+ const apiUrl = process.env.NEXT_PUBLIC_API_URL || process.env.API_URL || 'http://localhost:3000';
13
+ try {
14
+ const res = await fetch(`${apiUrl}/admin/analytics/config/${appId}`, {
15
+ next: { revalidate: 300 },
16
+ } as RequestInit);
17
+ if (!res.ok) return {};
18
+ return res.json();
19
+ } catch {
20
+ return {};
21
+ }
22
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx"
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules"]
18
+ }