add meta pixel integration
This commit is contained in:
190
src/lib/MetaPixel.svelte
Normal file
190
src/lib/MetaPixel.svelte
Normal file
@@ -0,0 +1,190 @@
|
||||
<script lang="ts" module>
|
||||
export class PixelControl {
|
||||
private _pixelID: string;
|
||||
private _testEventCode?: string = undefined;
|
||||
private _trackingManager: MaybeGetter<TrackingManager | undefined>;
|
||||
|
||||
private static _baseLoaded: boolean = false;
|
||||
|
||||
static get baseLoaded(): boolean {
|
||||
return this._baseLoaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the Meta Pixel base has been loaded before
|
||||
* allowing further operations.
|
||||
* @throws Error if the Meta Pixel API is not loaded.
|
||||
*/
|
||||
static loadGuard(): void {
|
||||
if (!this._baseLoaded || !window._fbq) {
|
||||
throw new Error('Meta Pixel API has not been loaded. Call PixelControl.load() first.');
|
||||
}
|
||||
}
|
||||
|
||||
private constructor(
|
||||
trackingManager: MaybeGetter<TrackingManager | undefined>,
|
||||
pixelID: string,
|
||||
testEventCode?: string
|
||||
) {
|
||||
this._trackingManager = trackingManager;
|
||||
this._pixelID = pixelID;
|
||||
this._testEventCode = testEventCode;
|
||||
}
|
||||
|
||||
/** Loads the Meta Pixel base script. */
|
||||
static load() {
|
||||
if (this._baseLoaded && window._fbq) return;
|
||||
if (!window._fbq) {
|
||||
PixelControl.revokeConsent(); // Initialize without consent
|
||||
loadMetaPixel(); // Load the Meta Pixel script
|
||||
}
|
||||
this._baseLoaded = true;
|
||||
}
|
||||
|
||||
/** Tells the Meta pixel that the user has given consent for tracking. */
|
||||
static grantConsent() {
|
||||
this.loadGuard();
|
||||
window.fbq?.('consent', 'grant');
|
||||
}
|
||||
|
||||
/** Tells the Meta pixel that the user has revoked consent for tracking. */
|
||||
static revokeConsent() {
|
||||
this.loadGuard();
|
||||
window.fbq?.('consent', 'revoke');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 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.
|
||||
* @param pixelID Meta Pixel ID
|
||||
* @param testEventCode Optional test event code
|
||||
* @returns PixelControl instance
|
||||
*/
|
||||
static for(
|
||||
trackingManager: MaybeGetter<TrackingManager | undefined>,
|
||||
pixelID: string,
|
||||
options?: {
|
||||
testEventCode?: string;
|
||||
advancedMatching?: AdvancedMatching;
|
||||
initOptions?: InitOptions;
|
||||
}
|
||||
): PixelControl {
|
||||
PixelControl.load();
|
||||
window.fbq('init', pixelID);
|
||||
return new PixelControl(trackingManager, pixelID, options?.testEventCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the Meta Pixel has consent to track user data
|
||||
* and if the Pixel has been loaded.
|
||||
* @returns true if tracking is allowed, false otherwise.
|
||||
* @throws Error if the Meta Pixel is not loaded.
|
||||
*/
|
||||
consentGuard(): boolean {
|
||||
PixelControl.loadGuard();
|
||||
const trackingManager = resolveGetter(this._trackingManager);
|
||||
return trackingManager?.haveUserConsent() ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a PageView event
|
||||
* @throws Error if the Meta Pixel is not initialized.
|
||||
*/
|
||||
pageView() {
|
||||
if (!this.consentGuard()) return;
|
||||
window.fbq('track', 'PageView', undefined, { test_event_code: this._testEventCode });
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks a standard event for this pixel (uses `trackSingle` under the hood)
|
||||
* @throws Error if the Meta Pixel is not initialized.
|
||||
*/
|
||||
track<K extends StandardEventName>(event: K, params?: EventParamsByName[K], eventID?: string) {
|
||||
if (!this.consentGuard()) return;
|
||||
window.fbq('trackSingle', this._pixelID, event, params, {
|
||||
eventID,
|
||||
test_event_code: this._testEventCode
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks a custom event for this pixel (uses `trackSingleCustom` under the hood)
|
||||
* @throws Error if the Meta Pixel is not initialized.
|
||||
*/
|
||||
trackCustom(event: string, params?: CommonParams & CustomParams, eventID?: string) {
|
||||
if (!this.consentGuard()) return;
|
||||
window.fbq('trackSingleCustom', this._pixelID, event, params, {
|
||||
eventID,
|
||||
test_event_code: this._testEventCode
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
import type { TrackingManager } from './tracking.svelte.ts';
|
||||
import type {
|
||||
EventParamsByName,
|
||||
StandardEventName,
|
||||
CommonParams,
|
||||
CustomParams,
|
||||
AdvancedMatching,
|
||||
InitOptions
|
||||
} from './types/fbq.js';
|
||||
import { loadMetaPixel } from './util/meta-pixel-loader.ts';
|
||||
import { onNavigate } from '$app/navigation';
|
||||
import { resolveGetter, type MaybeGetter } from './util/getter.ts';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
let { pixelID, testEventCode, autoPageView = true, trackingManager }: Props = $props();
|
||||
|
||||
let pixel = $state<PixelControl | null>(null);
|
||||
|
||||
onMount(() => {
|
||||
if (!trackingManager) {
|
||||
throw new Error('MetaPixel component requires a TrackingManager to manage consent.');
|
||||
}
|
||||
PixelControl.load();
|
||||
pixel = PixelControl.for(trackingManager, pixelID, { testEventCode });
|
||||
|
||||
trackingManager.runWithConsent(() => {
|
||||
if (autoPageView && pixel) {
|
||||
pixel.pageView();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onNavigate(() => {
|
||||
trackingManager?.runWithConsent(() => {
|
||||
if (autoPageView && pixel) {
|
||||
pixel.pageView();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user