@ops-ai/toggly-ga4-hook
v1.0.0
Published
Google Analytics 4 hook for Toggly Feature Flags SDK. Automatically pushes feature flag data to GA4 for analytics and user behavior correlation.
Readme
@ops-ai/toggly-ga4-hook
Google Analytics 4 hook for Toggly Feature Flags SDK. Automatically pushes feature flag data to Google Analytics 4 for analytics and user behavior correlation.
Can be used WITH or WITHOUT Toggly.io.
What is This?
This hook integrates Toggly feature flags with Google Analytics 4, allowing you to:
- Track feature flag usage as GA4 events
- Correlate features with user behavior in GA4 reports
- Set user properties for feature flag states
- Analyze A/B test results with GA4's built-in analysis tools
- Build audiences based on feature flag exposure
- Monitor real-time feature changes via GA4 events
How It Works
The GA4Hook implements the Toggly SDK Hook interface and listens to multiple lifecycle events:
| Hook | GA4 Action |
|------|------------|
| afterEvaluation | Sends feature_flag_evaluated event |
| afterIdentify | Sets user_id via gtag('config') |
| afterRefresh | Sends feature_flag_changed event on state changes |
Example event sent to GA4:
gtag('event', 'feature_flag_evaluated', {
feature_key: 'checkout-v2',
feature_enabled: true,
event_category: 'toggly'
});Installation
npm install @ops-ai/toggly-ga4-hookOr with yarn:
yarn add @ops-ai/toggly-ga4-hookPrerequisites
- Toggly SDK - Any JavaScript-based Toggly SDK with hooks support (v1.0.0+)
- Google Analytics 4 - GA4 tracking code (
gtag.js) must be loaded on your page
Usage
Vanilla JavaScript
import { Toggly } from '@ops-ai/feature-flags-toggly';
import { GA4Hook } from '@ops-ai/toggly-ga4-hook';
Toggly.init({
appKey: 'your-app-key',
environment: 'Production',
hooks: [
new GA4Hook({
measurementId: 'G-XXXXXXXXXX',
trackEvaluations: true,
trackChanges: true,
setUserProperties: true,
checkConsent: () => cookieConsent.analytics
})
]
});React
import { createTogglyProvider } from '@ops-ai/react-feature-flags-toggly';
import { GA4Hook } from '@ops-ai/toggly-ga4-hook';
const TogglyProvider = await createTogglyProvider({
appKey: 'your-app-key',
environment: 'Production',
hooks: [new GA4Hook({ measurementId: 'G-XXXXXXXXXX' })]
});Angular
import { provideToggly } from '@ops-ai/ngx-feature-flags-toggly';
import { GA4Hook } from '@ops-ai/toggly-ga4-hook';
bootstrapApplication(AppComponent, {
providers: [
provideToggly({
appKey: 'your-app-key',
environment: 'Production',
hooks: [new GA4Hook({ measurementId: 'G-XXXXXXXXXX' })]
})
]
});Vue
import { createApp } from 'vue';
import { TogglyPlugin } from 'vue-feature-flags-toggly';
import { GA4Hook } from '@ops-ai/toggly-ga4-hook';
app.use(TogglyPlugin, {
appKey: 'your-app-key',
environment: 'Production',
hooks: [new GA4Hook({ measurementId: 'G-XXXXXXXXXX' })]
});Svelte
import { Toggly } from '@ops-ai/feature-flags-toggly';
import { GA4Hook } from '@ops-ai/toggly-ga4-hook';
Toggly.init({
appKey: 'your-app-key',
environment: 'Production',
hooks: [new GA4Hook({ measurementId: 'G-XXXXXXXXXX' })]
});Astro
import { Toggly } from '@ops-ai/feature-flags-toggly';
import { GA4Hook } from '@ops-ai/toggly-ga4-hook';
Toggly.init({
appKey: 'your-app-key',
environment: 'Production',
hooks: [new GA4Hook({ measurementId: 'G-XXXXXXXXXX' })]
});Configuration
interface GA4HookOptions {
// Enable or disable the hook (default: true)
enabled?: boolean;
// GA4 Measurement ID (e.g., 'G-XXXXXXXXXX')
measurementId?: string;
// Event name for evaluations (default: "feature_flag_evaluated")
evaluationEventName?: string;
// Event name for changes (default: "feature_flag_changed")
changeEventName?: string;
// Track feature evaluations (default: true)
trackEvaluations?: boolean;
// Track both true and false results (default: true)
trackAllResults?: boolean;
// Set user properties for features (default: false)
setUserProperties?: boolean;
// User property prefix (default: "ff_")
userPropertyPrefix?: string;
// Track real-time changes (default: true)
trackChanges?: boolean;
// Track user identity (default: true)
trackIdentity?: boolean;
// Custom parameters for all events
customParameters?: Record<string, string | number | boolean>;
// Consent callback (default: () => true)
checkConsent?: () => boolean;
// Debug mode (default: false)
debug?: boolean;
}| Option | Type | Default | Description |
|--------|------|---------|-------------|
| enabled | boolean | true | Enable or disable the hook entirely |
| measurementId | string | - | GA4 Measurement ID (optional, uses default gtag) |
| evaluationEventName | string | "feature_flag_evaluated" | Custom event name for evaluations |
| changeEventName | string | "feature_flag_changed" | Custom event name for changes |
| trackEvaluations | boolean | true | Track feature flag evaluations |
| trackAllResults | boolean | true | Track both true and false results |
| setUserProperties | boolean | false | Set GA4 user properties for features |
| userPropertyPrefix | string | "ff_" | Prefix for user property names |
| trackChanges | boolean | true | Track real-time feature changes |
| trackIdentity | boolean | true | Set user_id in GA4 |
| customParameters | object | {} | Custom parameters for all events |
| checkConsent | function | () => true | Consent check callback |
| debug | boolean | false | Enable debug logging |
Full Configuration Example
const ga4Hook = new GA4Hook({
enabled: process.env.NODE_ENV === 'production',
measurementId: 'G-XXXXXXXXXX',
evaluationEventName: 'ff_evaluated',
changeEventName: 'ff_changed',
trackEvaluations: true,
trackAllResults: true,
setUserProperties: true,
userPropertyPrefix: 'feature_',
trackChanges: true,
trackIdentity: true,
customParameters: {
app_version: '2.0.0',
environment: 'production'
},
checkConsent: () => {
return window.cookieConsent?.analytics ?? false;
},
debug: false
});What Gets Tracked
Feature Evaluations
When a feature flag is evaluated:
gtag('event', 'feature_flag_evaluated', {
feature_key: 'new-checkout-flow',
feature_enabled: true,
event_category: 'toggly'
});Feature Changes (Real-time)
When a feature flag state changes:
gtag('event', 'feature_flag_changed', {
feature_key: 'dark-mode',
old_value: false,
new_value: true,
event_category: 'toggly'
});User Properties
When setUserProperties: true:
gtag('set', 'user_properties', {
ff_dark_mode: 'on',
ff_new_checkout: 'off'
});User Identity
When identity is set:
gtag('config', 'G-XXXXXXXXXX', {
user_id: '[email protected]'
});Viewing Data in GA4
Custom Events
- Go to GA4 Admin → Events
- Look for
feature_flag_evaluatedandfeature_flag_changed - Events appear automatically after first trigger
Event Parameters
In Explore → Free Form:
- Add
feature_keyas a dimension - Add
feature_enabledas a dimension - Analyze feature flag usage patterns
User Properties
- Go to GA4 Admin → Custom definitions → Custom user scopes
- Create custom dimensions for
ff_*properties - Use in reports to segment by feature flag exposure
Building Audiences
Create audiences based on feature exposure:
- Go to GA4 Admin → Audiences → New audience
- Add condition: Event =
feature_flag_evaluated - Add parameter condition:
feature_keyequalsyour-feature - Add parameter condition:
feature_enabledequalstrue
Privacy & Consent
GDPR/CCPA Compliance
The checkConsent callback allows integration with consent management platforms:
// OneTrust example
new GA4Hook({
checkConsent: () => window.OneTrust?.IsAlertBoxClosed() &&
window.OneTrust?.GetDomainData()?.Groups
?.find(g => g.CustomGroupId === 'C0002')?.Status === 'active'
});
// Simple cookie consent example
new GA4Hook({
checkConsent: () => document.cookie.includes('analytics_consent=true')
});
// Google Consent Mode v2
new GA4Hook({
checkConsent: () => {
// Check if analytics_storage consent is granted
return window.dataLayer?.some(item =>
item[0] === 'consent' &&
item[1] === 'update' &&
item[2]?.analytics_storage === 'granted'
) ?? false;
}
});What data is sent
- Feature flag key name (e.g.,
"dark-mode") - Feature evaluation result (
true/false) - Custom parameters you explicitly configure
- User ID (only if
trackIdentityis enabled and identity is set) - No automatic PII collection
Error Handling
The hook is designed to never break the Toggly SDK:
- All gtag API calls are wrapped in try-catch
- If gtag is not loaded, events are silently skipped
- If gtag throws an error, it is caught and logged to console
- The hook provides a console warning (not error) if gtag is not detected at initialization
Performance
- Overhead: <0.1ms per evaluation
- Bundle Size: ~2KB (minified)
- No batching: Events are sent immediately via gtag's internal queue
- Short-circuit: Disabled hooks and filtered results exit immediately
Dynamic Hook Management
You can add or remove the hook at runtime:
import { Toggly } from '@ops-ai/feature-flags-toggly';
import { GA4Hook } from '@ops-ai/toggly-ga4-hook';
// Add hook after initialization
Toggly.addHook(new GA4Hook({ measurementId: 'G-XXXXXXXXXX' }));
// Remove hook by name
Toggly.removeHook('ga4-hook');Troubleshooting
Events not appearing in GA4
Check gtag is loaded: Ensure the GA4 tracking code is on the page before Toggly initializes
console.log('gtag available:', typeof window.gtag === 'function');Check measurement ID: Verify your measurement ID is correct (format:
G-XXXXXXXXXX)Check consent: Verify your
checkConsentcallback returnstrueCheck feature evaluation: Ensure your feature flags are actually being evaluated
Check the console: Look for
[Toggly GA4 Hook]messagesEnable debug mode:
new GA4Hook({ debug: true })Use GA4 DebugView: Enable GA4 debug mode to see events in real-time
gtag('config', 'G-XXXXXXXXXX', { debug_mode: true });
Console warning at startup
[Toggly GA4 Hook] Google Analytics 4 gtag not detected.This means gtag was not loaded when the hook was created. The hook will automatically start sending events once gtag becomes available (e.g., loaded asynchronously).
User properties not appearing
- User properties have a 24-character limit in GA4
- Special characters in flag keys are replaced with underscores
- Create custom dimensions in GA4 Admin for user properties
Development
Running Tests
npm testRunning Tests with Coverage
npm test -- --coverageBuilding
npm run buildType Checking
npm run typecheckTypeScript Support
Full TypeScript support included:
import { GA4Hook } from '@ops-ai/toggly-ga4-hook';
import type { GA4HookOptions } from '@ops-ai/toggly-ga4-hook';
const options: GA4HookOptions = {
enabled: true,
measurementId: 'G-XXXXXXXXXX',
trackEvaluations: true,
setUserProperties: true,
};
const hook = new GA4Hook(options);Requirements
- Toggly SDK: Any JS SDK v1.0.0+ with hooks support
- Google Analytics 4: gtag.js loaded on the page
- Browser: Modern browsers with ES2020+ support
- Node.js: 18+ (for development)
Related Packages
- @ops-ai/toggly-hooks-types - Hook type definitions
- @ops-ai/toggly-clarity-hook - Microsoft Clarity hook
- @ops-ai/feature-flags-toggly - Core JavaScript SDK
- @ops-ai/react-feature-flags-toggly - React SDK
- @ops-ai/ngx-feature-flags-toggly - Angular SDK
Find Out More
License
MIT
