From a67e0e5864c3ee48893a77dc0b3b38956310f1c2 Mon Sep 17 00:00:00 2001 From: Jonathan Tsai Date: Thu, 26 Feb 2026 00:02:38 -0800 Subject: [PATCH 1/3] feat(components): add MetaPixel component with event tracking - Add MetaPixel component for easy Meta (Facebook) Pixel integration - Parameterized pixelId prop for different sites - Include trackMetaEvent() and trackMetaCustomEvent() helpers - Support all standard Meta Pixel events (Lead, Purchase, etc.) - Follow same patterns as GoogleAnalytics component - TypeScript support with proper Window interface extension --- packages/core/src/components/MetaPixel.tsx | 91 ++++++++++++++++++++++ packages/core/src/components/index.ts | 1 + 2 files changed, 92 insertions(+) create mode 100644 packages/core/src/components/MetaPixel.tsx diff --git a/packages/core/src/components/MetaPixel.tsx b/packages/core/src/components/MetaPixel.tsx new file mode 100644 index 0000000..f3ea064 --- /dev/null +++ b/packages/core/src/components/MetaPixel.tsx @@ -0,0 +1,91 @@ +'use client' + +import Script from 'next/script' + +export interface MetaPixelProps { + /** Meta (Facebook) Pixel ID (e.g., '1275259234564588') */ + pixelId: string + /** Load strategy (default: 'afterInteractive') */ + strategy?: 'afterInteractive' | 'lazyOnload' | 'beforeInteractive' + /** Disable automatic PageView tracking (default: false) */ + disablePageView?: boolean +} + +const PIXEL_ID_PATTERN = /^\d{15,16}$/ + +export function MetaPixel({ + pixelId, + strategy = 'afterInteractive', + disablePageView = false +}: MetaPixelProps) { + // Don't render if no pixel ID or invalid format + if (!pixelId || !PIXEL_ID_PATTERN.test(pixelId)) { + return null + } + + const pageViewScript = disablePageView ? '' : `fbq('track', 'PageView');` + + return ( + <> + + + + ) +} + +/** + * Track a Meta Pixel event + * Call this function to track custom events after the pixel is loaded + * + * @example + * // Standard event + * trackMetaEvent('Lead') + * trackMetaEvent('Purchase', { value: 99.99, currency: 'USD' }) + * + * // Custom event + * trackMetaEvent('CustomEvent', { custom_param: 'value' }) + */ +export function trackMetaEvent( + eventName: string, + params?: Record +) { + if (typeof window !== 'undefined' && typeof window.fbq === 'function') { + if (params) { + window.fbq('track', eventName, params) + } else { + window.fbq('track', eventName) + } + } +} + +// Extend Window interface for TypeScript +declare global { + interface Window { + fbq: ( + action: string, + eventName: string, + params?: Record + ) => void + } +} diff --git a/packages/core/src/components/index.ts b/packages/core/src/components/index.ts index 8402adc..16a4156 100644 --- a/packages/core/src/components/index.ts +++ b/packages/core/src/components/index.ts @@ -1,3 +1,4 @@ export * from './BasicPageLayout' export * from './GoogleAnalytics' +export * from './MetaPixel' export * from './ScrollToTop' From 79aa3dc742734001094e3b0ffbd0837f452567e6 Mon Sep 17 00:00:00 2001 From: Jonathan Tsai Date: Thu, 26 Feb 2026 00:06:39 -0800 Subject: [PATCH 2/3] docs: anonymize example pixel ID in comments --- package-lock.json | 2 +- packages/core/src/components/MetaPixel.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 97d933f..8959b5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5083,7 +5083,7 @@ }, "packages/core": { "name": "@hacktoolkit/nextjs-htk", - "version": "0.1.0", + "version": "0.2.0", "license": "MIT", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.5.1", diff --git a/packages/core/src/components/MetaPixel.tsx b/packages/core/src/components/MetaPixel.tsx index f3ea064..6612ac1 100644 --- a/packages/core/src/components/MetaPixel.tsx +++ b/packages/core/src/components/MetaPixel.tsx @@ -3,7 +3,7 @@ import Script from 'next/script' export interface MetaPixelProps { - /** Meta (Facebook) Pixel ID (e.g., '1275259234564588') */ + /** Meta (Facebook) Pixel ID (e.g., '1234567890123456') */ pixelId: string /** Load strategy (default: 'afterInteractive') */ strategy?: 'afterInteractive' | 'lazyOnload' | 'beforeInteractive' From 03bc9ebbf35d03c409e6d7b7af51ea69a4c1bd1f Mon Sep 17 00:00:00 2001 From: Jonathan Tsai Date: Thu, 26 Feb 2026 00:11:30 -0800 Subject: [PATCH 3/3] fix: address Copilot review feedback - Add trackMetaCustomEvent() for custom events (uses fbq('trackCustom')) - Fix TypeScript Window.fbq types with proper overloads - Simplify trackMetaEvent() - remove unnecessary conditional - Respect disablePageView in noscript fallback - Update JSDoc to clarify standard vs custom events --- packages/core/src/components/MetaPixel.tsx | 70 ++++++++++++++-------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/packages/core/src/components/MetaPixel.tsx b/packages/core/src/components/MetaPixel.tsx index 6612ac1..16faa81 100644 --- a/packages/core/src/components/MetaPixel.tsx +++ b/packages/core/src/components/MetaPixel.tsx @@ -41,51 +41,71 @@ export function MetaPixel({ ${pageViewScript} `} - + {!disablePageView && ( + + )} ) } /** - * Track a Meta Pixel event - * Call this function to track custom events after the pixel is loaded + * Track a standard Meta Pixel event + * Use this for Facebook's predefined standard events + * + * @see https://developers.facebook.com/docs/meta-pixel/reference#standard-events * * @example - * // Standard event * trackMetaEvent('Lead') * trackMetaEvent('Purchase', { value: 99.99, currency: 'USD' }) - * - * // Custom event - * trackMetaEvent('CustomEvent', { custom_param: 'value' }) + * trackMetaEvent('AddToCart', { content_ids: ['SKU123'], value: 29.99 }) */ export function trackMetaEvent( eventName: string, params?: Record ) { if (typeof window !== 'undefined' && typeof window.fbq === 'function') { - if (params) { - window.fbq('track', eventName, params) - } else { - window.fbq('track', eventName) - } + window.fbq('track', eventName, params) + } +} + +/** + * Track a custom Meta Pixel event + * Use this for your own custom events (not Facebook's standard events) + * + * @see https://developers.facebook.com/docs/meta-pixel/reference#custom-events + * + * @example + * trackMetaCustomEvent('StartTrial') + * trackMetaCustomEvent('ShareContent', { content_type: 'article' }) + */ +export function trackMetaCustomEvent( + eventName: string, + params?: Record +) { + if (typeof window !== 'undefined' && typeof window.fbq === 'function') { + window.fbq('trackCustom', eventName, params) } } // Extend Window interface for TypeScript declare global { interface Window { - fbq: ( - action: string, - eventName: string, - params?: Record - ) => void + fbq: { + (action: 'init', pixelId: string, options?: Record): void + ( + action: 'track' | 'trackCustom', + eventName: string, + params?: Record + ): void + (action: string, ...args: unknown[]): void + } } }