Skip to content

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

 
 
 

Contributors