Skip to content

TypeScript reactive library for Google Tag Manager with configurable priority system, RxJS, and automatic duplicate prevention in Frontend and SSR environments.

License

Notifications You must be signed in to change notification settings

marcboreu/gtm-core

Repository files navigation

🎯 GTM Core - v1.0.0 – Priority System Edition

TypeScript reactive library for Google Tag Manager with configurable priority system, RxJS, and automatic duplicate prevention in Frontend and SSR environments.


🚀 What’s New

  • Configurable priorities: 1 = critical, 2 = high, 3+ = low
  • Multiple events per priority: FIFO within each level
  • Immediate processing for priority 1
  • Debounce & batching customizable per event

⚡ Installation

npm install gtm-core

Optional for schema validation with Zod:

npm install zod

📦 File Structure

tu-project/
├── lib/
│   └── gtm.ts            ← Central GTM configuration
├── hooks/
│   └── useGTM.ts         ← Optional custom hook
├── context/
│   └── GTMContext.tsx    ← Optional React context
├── pages/ or src/
│   ├── App.tsx           ← Global initialization
│   ├── HomePage.tsx      ← Example view
│   └── ProductPage.tsx   ← Another example view
└── package.json

1. Basic Configuration

import { PriorityGTMManager, EventPriorityConfig } from 'gtm-core';

interface AppEvents {
  criticalError: { error: string };             // P1 – Critical
  userClick:     { element: string; page: string }; // P2 – Important
  pageView:      { page: string; title: string };   // P3 – General
  scrollDepth:   { page: string; depth: number };   // P3 – General
}

const events: EventPriorityConfig<AppEvents> = {
  criticalError: { priority: 1, debounceMs: 0 },
  userClick:     { priority: 2, debounceMs: 100, maxPerBatch: 5 },
  pageView:      { priority: 3, debounceMs: 300, maxPerBatch: 3 },
  scrollDepth:   { priority: 3, debounceMs: 1000, maxPerBatch: 2 }
};

export const gtm = new PriorityGTMManager<AppEvents>({
  gtm:       { gtmId: 'GTM-XXXXXXX' },           // ← Your GTM ID
  events,
  batcher:   { batchSize: 8, batchIntervalMs: 1500, priorityAware: true },
  reactMode: { enabled: true, globalDebounceMs: 50 }
});

2. Global Initialization

import React, { useEffect } from 'react';
import { gtm } from './lib/gtm';

function App({ Component, pageProps }) {
  useEffect(() => {
    gtm.init().subscribe({
      next: () => console.log('✅ GTM initialized'),
      error: (e) => console.error('❌ GTM init error:', e)
    });
  }, []);

  return <Component {...pageProps} />;
}

export default App;

3. Sending Events with pushSync

3.1 Page View

useEffect(() => {
  gtm.pushSync({ page: '/home', title: 'Home' }, 'pageView');
}, []);

3.2 User Click

<button onClick={() =>
  gtm.pushSync({ element: 'cta', page: '/home' }, 'userClick')
}>
  Click me
</button>

3.3 Critical Error

try {
  await processPayment();
} catch (error) {
  gtm.pushSync({ error: error.message }, 'criticalError');
}

4. Debounce & Batching

  • P1 (priority: 1): debounceMs: 0 → immediate
  • P2 (priority: 2): debounceMs: 100 ms → short burst grouping
  • P3 (priority: 3): debounceMs: 300 ms → longer grouping

Batcher groups up to batchSize events or every batchIntervalMs, respecting priorities if priorityAware: true.


5. SSR Support (Next.js)

import Document, { Html, Head, Main, NextScript } from 'next/document';
import { gtm } from '../lib/gtm';

class MyDocument extends Document {
  render() {
    const script = gtm.renderSSRScriptSync();
    return (
      <Html>
        <Head>{script && <div dangerouslySetInnerHTML={{ __html: script }} />}</Head>
        <body><Main /><NextScript/></body>
      </Html>
    );
  }
}

export default MyDocument;

6. Hooks & Context (Optional)

Custom Hook

import { useCallback } from 'react';
import { gtm } from '../lib/gtm';

export function useGTM() {
  const push = useCallback((data, type) => gtm.pushSync(data, type), []);
  const trackPage = useCallback((page, title) => push({ page, title }, 'pageView'), [push]);
  const trackClick = useCallback((el, pg) => push({ element: el, page: pg }, 'userClick'), [push]);
  return { push, trackPage, trackClick };
}

React Context

import React, { createContext, useContext } from 'react';
import { gtm } from '../lib/gtm';

const GTMContext = createContext(gtm);
export const GTMProvider = ({ children }) => (
  <GTMContext.Provider value={gtm}>{children}</GTMContext.Provider>
);
export const useGTM = () => useContext(GTMContext);

Wrap your app in GTMProvider if using.


7. Debug & Metrics

// Discarded events
gtm.buffer.getDiscardedEvents().subscribe(({ reason, event }) => {
  console.warn('Discarded:', reason, event);
});

// Processed batches
gtm.batcher.getBatchEvents().subscribe(be => {
  console.log(`Batch ${be.reason} (P=${be.avgPriority?.toFixed(1)}):`, be.batch);
});

8. Summary of Steps

  1. Install: npm install gtm-core
  2. Configure: Define your AppEvents and EventPriorityConfig
  3. Initialize: Call gtm.init() in your root component
  4. Send: Use gtm.pushSync(data, 'eventType') in each view
  5. Adjust: Tune debounceMs, maxPerBatch, batcher, reactMode

GTM Core - v1.0.0 handles your critical, important, and general events automatically, both on client and SSR. 🎉

About

TypeScript reactive library for Google Tag Manager with configurable priority system, RxJS, and automatic duplicate prevention in Frontend and SSR environments.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •