eventfoundry-tracker
v1.1.2
Published
EventFoundry tracking script for custom GA4 event tracking
Maintainers
Readme
EventFoundry Tracker
Embedded JavaScript tracking script for EventFoundry - enables multi-platform event tracking with a visual editor. Send events to Google Analytics 4, Meta Pixel, and other destinations from a single unified tracking implementation.
Table of Contents
- Installation
- Supported Destinations
- How It Works
- Features
- Configuration
- Development Mode
- Debugging Events
- Troubleshooting
- Editor Integration
- Architecture
- Browser Compatibility
- Development
- PostMessage API Reference
- License
Installation
Add the EventFoundry tracker script to your website's HTML. All destination configuration (GA4, Meta Pixel, etc.) is managed through the EventFoundry app - no credentials needed in the script tag.
Via jsDelivr CDN (Recommended)
<!-- Pinned to specific version (recommended for production) -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/tracker.min.js"
data-site-key="YOUR_SITE_KEY_HERE"
async></script>Or use the latest version (auto-updates):
<!-- Latest version (auto-updates - use with caution) -->
<script src="https://cdn.jsdelivr.net/npm/eventfoundry-tracker@latest/dist/tracker.min.js"
data-site-key="YOUR_SITE_KEY_HERE"
async></script>Via npm
npm install eventfoundry-trackerThat's it! Configure your tracking destinations (GA4, Meta Pixel, etc.) in the EventFoundry app, and events will automatically be sent to all enabled destinations.
Supported Destinations
EventFoundry Tracker uses a destination adapter architecture to support multiple analytics platforms from a single implementation. Each event you define can be sent to one or more destinations.
Currently Supported
Google Analytics 4 (GA4)
- Auto-injection: EventFoundry automatically injects the GA4 SDK if not already present
- Existing installations: If you already have GA4 installed, EventFoundry will detect and use it
- Event delivery: Events sent via
gtag('event', ...)with Beacon API transport for reliability - Configuration: Provide your GA4 Measurement ID (e.g.,
G-XXXXXXXXXX) in the EventFoundry app
Meta Pixel (Facebook Pixel)
- Auto-injection: EventFoundry automatically injects the Meta Pixel SDK if not already present
- Existing installations: If you already have Meta Pixel installed, EventFoundry will detect and use it
- Event delivery: Custom events sent via
fbq('trackCustom', ...) - Configuration: Provide your Meta Pixel ID in the EventFoundry app
- Automatic PageView: EventFoundry sends an automatic PageView event on initialization
How Multi-Destination Works
- Configure once: Define your events in the EventFoundry app with descriptive names
- Enable destinations: Choose which destinations (GA4, Meta Pixel, etc.) should receive each event
- Unified tracking: The same event fires to all enabled destinations with the same parameters
- No code changes: Add or remove destinations without touching your website code
Example: Single Event, Multiple Destinations
When a user clicks a "Sign Up" button:
- GA4 receives:
gtag('event', 'sign_up_click', {...params}) - Meta Pixel receives:
fbq('trackCustom', 'sign_up_click', {...params}) - Future destinations: Automatically included when you enable them
Roadmap
Additional destinations coming soon:
- Google Ads conversion tracking
- TikTok Pixel
- LinkedIn Insight Tag
- Custom webhook destinations
How It Works
EventFoundry Tracker operates in two distinct modes:
1. Tracking Mode (Production)
This is the default mode when the script is embedded on your website:
- Initialization: On page load, the tracker reads configuration from script attributes
- Configuration Fetch: Retrieves event definitions and destination configs from EventFoundry API using your site key
- Caching: Stores configuration in localStorage with ETag-based cache validation, stale-cache fallback on API/network failures, and safe-empty fallback when no usable cache is available
- Destination Initialization: Automatically initializes all enabled destination SDKs:
- GA4: Injects gtag.js (or detects existing installation) and configures with your Measurement ID
- Meta Pixel: Injects fbq.js (or detects existing installation) and configures with your Pixel ID
- Each destination validates credentials and reports initialization status
- Click Tracking: Attaches click listeners to elements matching CSS selectors from your event definitions
- Event Resolution and Delivery: When tracked elements are clicked:
- Generates auto-parameters (element text, URL, page title, etc.)
- Resolves overlapping selector matches deterministically (highest specificity wins, then stable tie-breakers)
- Fires to all enabled destinations for that event using destination-specific adapters
- GA4 uses
gtag('event', ...)with Beacon API transport - Meta Pixel uses
fbq('trackCustom', ...) - Errors in one destination don't affect others
2. Editor Mode (EventFoundry App)
When loaded inside the EventFoundry application's iframe:
- Detection: Automatically detects iframe environment and initializes editor mode
- Visual Overlay: Displays an interactive overlay for selecting elements on your page
- Element Selection: Click any element to select it and generate an optimized CSS selector
- Selector Generation: Normalizes clicks to nearest interactive ancestor and uses a priority-based algorithm to create reliable selectors
- Communication: Sends element data back to the parent app via secure PostMessage
- Preview Testing: Allows testing events in preview mode with real-time logging showing all destinations
Features
- Multi-Platform: Send events to multiple analytics platforms (GA4, Meta Pixel) from a single implementation
- Lightweight: ~4.75 KB gzipped, <5 KB budget enforced by CI/CD
- Zero dependencies: Pure vanilla JavaScript
- Destination adapters: Extensible architecture makes adding new platforms simple
- Auto-parameter generation: Automatically captures element context, page info, and event metadata
- Fast: ETag-based caching with localStorage for efficient configuration updates
- Non-blocking: Async loading and initialization won't slow down your site
- Browser support: Chrome, Firefox, Safari, Edge (ES2015+)
- Reliable delivery: Uses Beacon API (GA4) to ensure events complete even during navigation
- Development mode: Auto-detects localhost and logs event routing without sending to destinations
- Visual editor: Interactive element selection overlay for defining events
- Smart selectors: Priority-based CSS selector generation algorithm
- Secure communication: Origin validation for iframe PostMessage API
- Per-event destination control: Enable/disable specific destinations for each event
- Graceful degradation: If one destination fails, others continue to work
Configuration
Script Tag Attributes
The tracker script accepts the following data attributes:
Required
data-site-key: Your EventFoundry site key (obtained from your EventFoundry account)
Optional
data-dev-mode: Control development mode behavior"true": Force development mode on (logs events, doesn't send to any destinations)"false": Force production mode on- Not set: Auto-detects (dev mode on localhost, production mode elsewhere)
id="eventfoundry-tracker": Recommended when multiple tracker script tags may exist on the same page, for deterministic script config selection
Destination Configuration
All destination credentials (GA4 Measurement IDs, Meta Pixel IDs, etc.) are configured in the EventFoundry app, not in the script tag. This provides several benefits:
- Security: No credentials exposed in client-side code
- Flexibility: Update destinations without changing website code
- Per-event control: Enable/disable destinations for individual events
- Centralized management: Manage all tracking from one dashboard
To configure destinations:
- Log in to the EventFoundry app
- Navigate to your site settings
- Add your destination credentials (GA4 Measurement ID, Meta Pixel ID, etc.)
- Enable destinations globally and per-event as needed
Development Mode
Development mode helps you test EventFoundry tracking without sending events to any analytics destinations (GA4, Meta Pixel, etc.).
Auto-Detection
By default, the tracker automatically enables development mode when running on localhost:
// On localhost - dev mode is automatically enabled
// Events are logged to console but NOT sent to any destinationsManual Control
You can override the auto-detection:
<!-- Force dev mode on production domain (for testing) -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/tracker.min.js"
data-site-key="YOUR_SITE_KEY_HERE"
data-dev-mode="true"
async></script>
<!-- Force production mode on localhost (to test real destination events) -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/tracker.min.js"
data-site-key="YOUR_SITE_KEY_HERE"
data-dev-mode="false"
async></script>Behavior in Dev Mode
When development mode is active:
- Events are logged to the browser console with full details for each destination
- No events are sent to any analytics destinations (GA4, Meta Pixel, etc.)
- A console message indicates dev mode is active
- All tracking logic still runs (useful for testing selectors and event configuration)
- Destination initialization still occurs (validates credentials and reports status)
Debugging Events
Development mode provides enhanced logging to help troubleshoot event tracking issues.
Enabling Debug Logging
Debug logging automatically enables on localhost, or you can manually enable it:
<!-- Enable debug logging on any domain -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/tracker.min.js"
data-site-key="YOUR_SITE_KEY_HERE"
data-dev-mode="true"
async></script>Debug Console Messages
When dev mode is enabled, the tracker logs helpful debugging information:
Destination Initialization:
EventFoundry: Initializing 2 destination(s)
✓ GA4 initialized
✓ META_PIXEL initializedConfirms each destination SDK was successfully loaded and configured.
Event Firing:
[DEV] Would fire to GA4: button_click {event_category: "EventFoundry", ...}
[DEV] Would fire to META_PIXEL: button_click {event_category: "EventFoundry", ...}
EventFoundry: Event fired to 2 destination(s): ["GA4", "META_PIXEL"]Shows which destinations will receive the event and what parameters are being sent.
Non-Matching Clicks:
EventFoundry: Click on <button class="test"> matched 0 eventsThe clicked element doesn't match any of your event selectors. Check your event definitions to ensure the selector is correct.
Editor Mode:
EventFoundry: Click ignored (editor mode active, not in preview)Clicks are ignored when the editor is active to prevent false events during element selection.
Critical Errors (Always Logged):
EventFoundry: GA4 not initialized - cannot fire eventGA4 SDK failed to load or was blocked by an ad blocker. Check browser console for script loading errors.
EventFoundry: Meta Pixel not initialized - cannot fire eventMeta Pixel SDK failed to load or was blocked. Check browser console for script loading errors.
EventFoundry: Invalid selector ".some[invalid:selector" - SyntaxError: ...One of your event selectors is malformed. The tracker validates all selectors at initialization and logs warnings for each invalid selector.
🚨 EventFoundry: All event selectors invalid - possible cache corruptionCritical: ALL event selectors are invalid. The tracker will not attach any click listeners. Common causes:
- Unsupported CSS pseudo-classes (e.g.,
:has()in older browsers) - Syntax errors in selectors
- Browser compatibility issues
If this error appears with cached data during normal initialization, the tracker will clear cache and refetch definitions from the API.
EventFoundry: 2 of 10 selectors are invalid and will be skippedSome (but not all) selectors are invalid. Tracking will continue for valid selectors, but invalid ones will be skipped. Check the console warnings above to see which selectors failed validation.
EventFoundry: Multiple events matched, firing highest priority: ["Event 2 [button.cta.primary]", "Event 1 [.cta]"]Multiple events matched the same click. The tracker fires one event deterministically (highest selector priority). Consider making selectors non-overlapping for clarity.
Troubleshooting
Events aren't showing in GA4
- Enable dev mode and check console logs
- Click the tracked element and look for:
[DEV] Would fire to GA4: ...→ Event is matching and routing correctlymatched 0 events→ Your selector doesn't match the elementGA4 not initialized - cannot fire event→ GA4 script is blocked or missing
- Verify GA4 is configured in EventFoundry app settings
- Check that GA4 Measurement ID is correct
- Use browser DevTools to verify your selector matches the element:
document.querySelector('.your-selector') // Should return the element
Events aren't showing in Meta Pixel
- Enable dev mode and check console logs
- Look for
✓ META_PIXEL initializedmessage - if missing, check:- Meta Pixel ID is configured correctly in EventFoundry app
- Ad blockers aren't blocking
connect.facebook.net - Browser console for script loading errors
- Use Meta Pixel Helper browser extension to verify events are firing
- Check Meta Events Manager (events can take 20+ minutes to appear)
Click doesn't trigger any logs
- Check that the tracker loaded: look for
✓ EventFoundry tracker loadedin console - Verify your site key is correct:
data-site-key="..." - Check browser console for errors during tracker initialization
- Ensure the element isn't inside an iframe (events only track in the same page)
Events fire in preview but not on live site
- Check if destination scripts are being blocked by ad blockers
- Enable dev mode on live site to see destination error messages
- Verify destination credentials in EventFoundry app match your analytics accounts
- Check browser console for Content Security Policy (CSP) violations
One destination works but another doesn't
This is expected behavior - destinations are independent:
- If GA4 works but Meta Pixel doesn't, check Meta Pixel configuration
- If Meta Pixel works but GA4 doesn't, check GA4 configuration
- Each destination's errors are logged separately in dev mode
Cache issues
If events aren't updating after changes in the EventFoundry app:
- Clear localStorage cache manually:
localStorage.clear()in browser console - Use the "Reload Config" button in the EventFoundry app editor
- Check for ETag validation in Network tab (should see 304 or 200 responses)
- If the API is down, the tracker will use cached data when available (
Definitions reload used cached payload fallback) - If no usable cache is available, reload falls back to safe-empty (
Definitions reload fell back to safe-empty payload)
Editor Integration
EventFoundry Tracker includes a sophisticated visual editor for defining events directly on your website.
How Editor Mode Works
When your site is loaded inside the EventFoundry application:
- The tracker detects the iframe environment
- Sends an
IFRAME_READYmessage to the parent app - Activates the visual overlay system
- Waits for element selection requests from the parent app
Visual Element Selection
The editor overlay provides:
- Click-to-select: Click any element to select it
- Visual highlighting: Selected elements are highlighted in the overlay
- Parent traversal: Navigate up the DOM tree to select parent elements
- Selector preview: See the generated CSS selector in real-time
CSS Selector Generation
The tracker uses a priority-based algorithm to generate reliable CSS selectors:
- Interactive ancestor normalization: Resolves nested click targets to semantic clickable elements when possible
- ID selectors (highest priority):
#unique-element-id - Unique attributes:
[data-track="value"],[name="value"] - Class-based selectors:
.class-name,.multiple.classes - Tag + nth-child:
div:nth-child(3), with parent context for specificity - Fallback combinations: Combines multiple strategies for robustness
The algorithm ensures selectors are:
- Specific enough to target the correct element
- Resilient to minor page changes
- Human-readable when possible
Preview Mode
Test your events before deploying:
- Preview mode sends
EVENT_FIREDmessages to the parent app instead of firing destination adapters - See real-time feedback when clicking tracked elements
- Verify event parameters and tracking accuracy
- No impact on your destination data while preview is active
Architecture
EventFoundry Tracker is built with a modular, extensible architecture that separates concerns and makes adding new analytics platforms straightforward.
Source Structure
src/
├── index.js - Entry point, initialization, caching
├── tracker.js - Event tracking engine, click listeners
├── editor-mode.js - Editor mode detection and PostMessage
├── editor-overlay.js - Visual overlay, element selection, selectors
├── params-generator.js - Auto-parameter generation for events
└── adapters/
├── registry.js - Adapter registry and lookup
├── base-adapter.js - Abstract base class for all adapters
├── ga4-adapter.js - Google Analytics 4 adapter
└── meta-pixel-adapter.js - Meta Pixel adapterModule Responsibilities
- index.js: Configuration parsing, API communication, ETag-based caching
- tracker.js: Click event handling, selector validation, event orchestration
- editor-mode.js: Iframe detection, parent communication, mode switching
- editor-overlay.js: DOM overlay rendering, element selection UI, CSS selector algorithm
- registry.js: Adapter lifecycle lookup and destination routing
- base-adapter.js: Abstract interface for destination adapters (SDK detection, injection, validation)
- ga4-adapter.js: GA4-specific logic (gtag.js injection, event formatting, Beacon API)
- meta-pixel-adapter.js: Meta Pixel logic (fbq.js injection, event formatting, PageView)
- params-generator.js: Automatic parameter extraction (element text, URL, page title, timestamp)
Destination Adapter Pattern
Each analytics platform is implemented as a destination adapter that extends DestinationAdapter:
class GA4Adapter extends DestinationAdapter {
// SDK detection and injection
async initialize(config) { ... }
// Event formatting and sending
fireEvent(eventName, params) { ... }
// Health checks
isInitialized() { ... }
}This pattern provides:
- Isolation: Each destination operates independently
- Extensibility: Adding new platforms requires only a new adapter class
- Reliability: Failures in one destination don't affect others
- Testability: Each adapter can be tested in isolation
Build Output
- Format: IIFE (Immediately Invoked Function Expression)
- Target: ES2015 for broad browser compatibility
- Global bundle name:
EventFoundry(IIFE name; no public runtime API surface) - Bundler: Rollup with Terser minification
- Optimizations: Template minification, console stripping, tree-shaking
- Size budget: <5 KB gzipped (enforced by CI/CD)
Browser Compatibility
EventFoundry Tracker is built with ES2015+ JavaScript and supports all modern browsers:
- Chrome: 51+
- Firefox: 54+
- Safari: 10+
- Edge: 15+
Required Browser Features
- ES2015 syntax (arrow functions, const/let, template literals)
localStorageAPIfetchAPInavigator.sendBeaconAPI (for reliable event delivery)postMessageAPI (for editor mode communication)
All these features are widely supported in browsers from 2016 onwards.
Development
Setup
# Install dependencies
npm installBuilding
# Production build (outputs to dist/tracker.min.js)
npm run build
# Development watch mode (outputs to ../eventfoundry-app/frontend/public/test/tracker.min.js)
npm run devBuild System
The tracker uses Rollup for optimal tree-shaking and bundle optimization:
- Bundler: Rollup with Terser minification
- Console stripping:
console.logandconsole.warnremoved from production builds (console.errorpreserved) - Tree-shaking: Aggressive dead code elimination
- Sourcemaps: Inline in development mode and external in production
- Watch mode: Automatically rebuilds on file changes and outputs to sibling project
- Size budget: CI/CD enforces <5 KB gzipped limit
Build Configuration
- Production builds: Optimize for size and performance, strip console logs
- Development builds: Include sourcemaps, preserve console logs, faster iteration
- Both modes: IIFE bundles targeting ES2015
- Version injection:
__VERSION__replaced with package.json version at build time
Development Workflow
The dev build automatically outputs to ../eventfoundry-app/frontend/public/test/tracker.min.js for local integration testing. This allows you to:
- Make changes to the tracker
- See them immediately in the parent EventFoundry app (no publish needed)
- Test the full editor integration workflow locally
API Response Format
The tracker fetches configuration from the EventFoundry API. The response includes event definitions, destination configurations, and a version number:
{
"destinationConfigs": [
{
"destination": "GA4",
"enabled": true,
"credentials": {
"measurementId": "G-XXXXXXXXXX"
}
},
{
"destination": "META_PIXEL",
"enabled": true,
"credentials": {
"pixelId": "123456789012345"
}
}
],
"events": [
{
"eventKey": "sign_up_click",
"eventLabel": "Sign Up Click",
"selector": "button.signup",
"destinations": {
"GA4": { "enabled": true },
"META_PIXEL": { "enabled": true }
}
}
],
"version": 1
}Key features:
- Global destination config: Contains credentials and enabled status for each destination
- Per-event destination control: Each event can enable/disable specific destinations
- Canonical event keys:
eventKeyis used as the destination event name across adapters - Automatic params: Tracker-generated params are sent to each enabled destination adapter
- ETag caching: Response includes ETag header for efficient cache validation
- Stale-cache fallback: If the API is temporarily unavailable, cached definitions are used (with warnings)
- Safe-empty fallback: If API and cache are both unavailable/unusable, tracker uses a no-op payload to avoid runtime failures
PostMessage API Reference
When running in editor mode (inside EventFoundry app iframe), the tracker communicates with the parent window using the following PostMessage events:
Messages Sent by Tracker (to Parent)
IFRAME_READY
Sent when the tracker initializes in editor mode.
{
type: 'IFRAME_READY'
}ELEMENT_SELECTED
Sent when a user selects an element in the visual editor.
{
type: 'ELEMENT_SELECTED',
element: {
tagName: 'button', // Lowercase tag name
text: 'Click me', // Truncated element text content
id: 'submit-btn', // Element ID (if present)
className: 'primary btn', // Space-separated class string
selector: 'button.primary', // Generated CSS selector
page_path: '/pricing?plan=pro' // Path + query + hash
}
}EVENT_FIRED
Sent in preview mode when a tracked event is triggered. Includes event metadata, params, and destination list.
{
type: 'EVENT_FIRED',
timestamp: 1739328000000,
eventLabel: 'Button Click',
eventKey: 'button_click',
selector: 'button.primary',
destinations: ['GA4', 'META_PIXEL'], // Enabled + initialized destinations
params: { event_category: 'EventFoundry', ... },
pagePath: '/pricing'
}MATCH_COUNT_RESULT
Sent after the parent requests selector count via COUNT_MATCHES.
{
type: 'MATCH_COUNT_RESULT',
selector: 'button.primary',
count: 3
}Messages Received by Tracker (from Parent)
ENTER_EDIT_MODE
Activates editor overlay mode and enables element selection.
{
type: 'ENTER_EDIT_MODE'
}ENABLE_PREVIEW
Activates preview mode for testing events.
{
type: 'ENABLE_PREVIEW'
}DISABLE_PREVIEW
Deactivates preview mode and returns to normal editor mode.
{
type: 'DISABLE_PREVIEW'
}RELOAD_CONFIG
Triggers a full tracker config reload (definitions + destination re-initialization).
{
type: 'RELOAD_CONFIG'
}HIGHLIGHT_SELECTOR
Highlights all elements matching a selector in the overlay.
{
type: 'HIGHLIGHT_SELECTOR',
selector: 'button.primary'
}COUNT_MATCHES
Requests the number of elements matching a selector.
{
type: 'COUNT_MATCHES',
selector: 'button.primary'
}Security
All PostMessage communication includes origin validation to ensure messages are only accepted from authorized EventFoundry domains. This prevents malicious sites from interfering with the tracker's operation.
License
MIT © Kyle Logue
