Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions packages/core/src/components/MetaPixel.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<Script id="meta-pixel-init" strategy={strategy}>
{`
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '${pixelId}');
${pageViewScript}
`}
</Script>
<noscript>
<img
height="1"
width="1"
style={{ display: 'none' }}
src={`https://www.facebook.com/tr?id=${pixelId}&ev=PageView&noscript=1`}
alt=""
/>
</noscript>

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When disablePageView is true, the JavaScript code skips PageView tracking, but the noscript fallback image still includes 'ev=PageView' in the URL. This creates inconsistent behavior between JavaScript and non-JavaScript environments. The noscript fallback should respect the disablePageView prop and conditionally render based on its value, or omit the 'ev' parameter when PageView tracking is disabled.

Suggested change
<noscript>
<img
height="1"
width="1"
style={{ display: 'none' }}
src={`https://www.facebook.com/tr?id=${pixelId}&ev=PageView&noscript=1`}
alt=""
/>
</noscript>
{!disablePageView && (
<noscript>
<img
height="1"
width="1"
style={{ display: 'none' }}
src={`https://www.facebook.com/tr?id=${pixelId}&ev=PageView&noscript=1`}
alt=""
/>
</noscript>
)}

Copilot uses AI. Check for mistakes.
</>
)
}

/**
* 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' })
*/
Comment on lines +59 to +69

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation comment states this function can be used for custom events (line 66-67), but the implementation only uses fbq('track', ...) which is for standard events. Custom events in Facebook Pixel should use fbq('trackCustom', eventName, params). This could lead to confusion or incorrect event tracking. Consider either updating the implementation to handle custom events differently or clarifying in the documentation that this function is for standard events only.

Copilot uses AI. Check for mistakes.
export function trackMetaEvent(
eventName: string,
params?: Record<string, unknown>
) {
if (typeof window !== 'undefined' && typeof window.fbq === 'function') {
if (params) {
window.fbq('track', eventName, params)
} else {
window.fbq('track', eventName)
}

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional logic to check if params exists is unnecessary. Facebook Pixel's fbq function accepts an optional third parameter, so window.fbq('track', eventName, params) can be called even when params is undefined. This simplifies the code and removes the redundant if-else branch.

Suggested change
if (params) {
window.fbq('track', eventName, params)
} else {
window.fbq('track', eventName)
}
window.fbq('track', eventName, params)

Copilot uses AI. Check for mistakes.
}
}
Comment on lines +70 to +96

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions a trackMetaCustomEvent() helper function, but this function does not exist in the code. Only trackMetaEvent() is implemented. Either the PR description should be updated to remove this reference, or the function should be added to match the documentation. Note that Facebook Pixel distinguishes between standard events (using fbq('track', eventName)) and custom events (using fbq('trackCustom', eventName)).

Copilot uses AI. Check for mistakes.

// Extend Window interface for TypeScript
declare global {
interface Window {
fbq: (
action: string,
eventName: string,
params?: Record<string, unknown>
) => void

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TypeScript Window interface extension for fbq is incomplete. The Facebook Pixel fbq function supports multiple actions ('init', 'track', 'trackCustom', etc.), but the current type definition only supports 'track'. This will cause TypeScript errors when using fbq('init', pixelId) as seen on line 40. The function signature should be updated to support multiple overloads or use a more flexible type that accommodates all fbq actions.

Suggested change
fbq: (
action: string,
eventName: string,
params?: Record<string, unknown>
) => void
fbq(
action: 'init',
pixelId: string,
options?: Record<string, unknown>
): void
fbq(
action: 'track' | 'trackCustom',
eventName: string,
params?: Record<string, unknown>
): void
fbq(action: string, ...args: unknown[]): void

Copilot uses AI. Check for mistakes.
}
}
1 change: 1 addition & 0 deletions packages/core/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './BasicPageLayout'
export * from './GoogleAnalytics'
export * from './MetaPixel'
export * from './ScrollToTop'