2 Commits

Author SHA1 Message Date
Elijah Duffy
674663b027 0.0.4 2025-12-18 10:23:17 -08:00
Elijah Duffy
e7b12f50b1 pixel: improve fetching existing PixelControls 2025-12-18 10:23:12 -08:00
2 changed files with 84 additions and 43 deletions

View File

@@ -4,7 +4,7 @@
"type": "git",
"url": "https://gitea.auvem.com/svelte-toolkit/spectator.git"
},
"version": "0.0.3",
"version": "0.0.4",
"license": "MIT",
"scripts": {
"dev": "vite dev",

View File

@@ -1,11 +1,36 @@
<!-- @component
MetaPixel integrates the Meta (Facebook) Pixel into your Svelte application,
allowing you to track page views and custom events while respecting user consent
for tracking. The component manages the lifecycle of the Meta Pixel script and
PixelControl interface.
The PixelControl class also allows you to directly manage multiple Pixel
instances and handle event tracking with optional test event codes without
using the MetaPixel component.
-->
<script lang="ts" module>
export type PixelControlOptions = {
/**
* if provided, events fired will always have this code attached
* to prevent them from polluting real analytics data.
*/
testEventCode?: string;
/** Advanced matching data */
advancedMatching?: AdvancedMatching;
/** Initialization options */
initOptions?: InitOptions;
};
export class PixelControl {
private _pixelID: string;
private _testEventCode?: string = undefined;
private _trackingManager: MaybeGetter<TrackingManager | undefined>;
private static _baseLoaded: boolean = false;
private static _registeredPixels: Record<string, PixelControl> = {};
/** Indicates whether the Meta Pixel base script has been loaded. */
static get baseLoaded(): boolean {
return this._baseLoaded;
}
@@ -24,11 +49,11 @@
private constructor(
trackingManager: MaybeGetter<TrackingManager | undefined>,
pixelID: string,
testEventCode?: string
options?: PixelControlOptions
) {
this._trackingManager = trackingManager;
this._pixelID = pixelID;
this._testEventCode = testEventCode;
this._testEventCode = options?.testEventCode;
}
/** Loads the Meta Pixel base script. */
@@ -60,43 +85,55 @@
}
/**
* Returns a PixelControl instance for the given Meta Pixel ID. If
* Registers a PixelControl instance for the given Meta Pixel ID. If
* the base Meta Pixel script has not been loaded yet, it will be
* loaded automatically. Optionally sets a test event code for the Pixel.
* Does NOT initialize the Pixel; call `fireInit()` on the returned instance
* before tracking events.
* Should only be called once for each Pixel ID, use PixelControl.get()
* to retrieve existing instances.
* @param trackingManager Tracking manager to handle user consent for tracking
* @param pixelID Meta Pixel ID
* @param options Optional settings
* @returns PixelControl instance
*/
static for(
static initialize(
trackingManager: MaybeGetter<TrackingManager | undefined>,
pixelID: string,
options?: {
/**
* if provided, events fired will always have this code attached
* to prevent them from polluting real analytics data.
*/
testEventCode?: string;
}
options?: PixelControlOptions
): PixelControl {
// Load the base script if not already loaded
PixelControl.load();
return new PixelControl(trackingManager, pixelID, options?.testEventCode);
// Check for existing PixelControl instance
if (this._registeredPixels[pixelID]) {
log.warn(
`PixelControl instance for Meta Pixel ID: ${pixelID} already exists. Returning existing instance.`
);
return this._registeredPixels[pixelID];
}
// Create and register the PixelControl instance
const pixel = new PixelControl(trackingManager, pixelID, options);
this._registeredPixels[pixelID] = pixel;
// Fire initialization
window.fbq('init', pixel._pixelID, options?.advancedMatching, options?.initOptions);
log.debug(`Meta Pixel [${pixel._pixelID}] initialized.`);
return pixel;
}
/**
* Initializes this pixel with the Meta Pixel API including any advanced
* matching data and options.
* @param advancedMatching Advanced matching data
* @param initOptions Initialization options
* @returns this PixelControl instance
* Returns an existing PixelControl instance for the given Meta Pixel ID.
* @param pixelID Meta Pixel ID
* @returns PixelControl instance
* @throws Error if no PixelControl instance is found for the given ID.
*/
fireInit(advancedMatching?: AdvancedMatching, initOptions?: InitOptions): PixelControl {
PixelControl.loadGuard();
window.fbq('init', this._pixelID, advancedMatching, initOptions);
log.debug(`Meta Pixel [${this._pixelID}] initialized.`);
return this;
static get(pixelID: string): PixelControl {
const pixel = this._registeredPixels[pixelID];
if (!pixel) {
throw new Error(`No PixelControl instance found for Meta Pixel ID: ${pixelID}`);
}
return pixel;
}
/**
@@ -156,7 +193,7 @@
</script>
<script lang="ts">
import { onMount } from 'svelte';
import { createContext, onMount } from 'svelte';
import type { TrackingManager } from './tracking.svelte.ts';
import type {
@@ -173,30 +210,27 @@
import log from 'loglevel';
interface Props {
/** Meta Pixel ID */
pixelID: string;
/**
* If a test event code is available, events fired will always have this
* code attached to prevent them from polluting real analytics data.
*/
testEventCode?: string;
/**
* Controls whether page views are automatically tracked by this
* component (default: true).
*/
autoPageView?: boolean;
/**
* Tracking manager to handle user consent for tracking. If omitted
* tracking is disabled by default until consent is granted via
* PixelControl.grantConsent().
*/
trackingManager?: TrackingManager;
/** Meta Pixel ID */
pixelID: string;
/** Meta Pixel Options */
pixelOptions?: PixelControlOptions;
/**
* Controls whether page views are automatically tracked by this
* component (default: true).
*/
autoPageView?: boolean;
}
let { pixelID, testEventCode, autoPageView = true, trackingManager }: Props = $props();
let { pixelID, pixelOptions, autoPageView = true, trackingManager }: Props = $props();
let pixel = $state<PixelControl | null>(null);
@@ -205,7 +239,7 @@
throw new Error('MetaPixel component requires a TrackingManager to manage consent.');
}
PixelControl.load();
pixel = PixelControl.for(trackingManager, pixelID, { testEventCode }).fireInit();
pixel = PixelControl.initialize(trackingManager, pixelID, pixelOptions);
trackingManager.runWithConsent(() => {
if (autoPageView && pixel) {
@@ -221,4 +255,11 @@
}
});
});
export const getPixelControl = (): PixelControl => {
if (!pixel) {
throw new Error('MetaPixel component has not been initialized yet, wait for onMount.');
}
return pixel;
};
</script>