Installing Meta Pixel on Prismic with Next.js and Gatsby | OpsBlu Docs

Installing Meta Pixel on Prismic with Next.js and Gatsby

Complete guide to setting up Meta (Facebook) Pixel tracking on Prismic-powered sites for conversion tracking and remarketing

Meta Pixel (formerly Facebook Pixel) enables conversion tracking, audience building, and remarketing for Prismic-powered websites. This guide covers implementation for Next.js, Gatsby, and custom React applications.


Prerequisites

Before you begin:

  • Have a Meta Pixel ID from Facebook Business Manager
  • Have a Prismic repository set up
  • Be using Next.js, Gatsby, or another JavaScript framework
  • Have Facebook Business Manager access

Get Your Meta Pixel ID

  1. Log in to Facebook Business Manager
  2. Navigate to Events Manager
  3. Click Connect Data Sources > Web
  4. Select Meta Pixel
  5. Copy your Pixel ID (format: 16-digit number)

Method 1: Next.js with Prismic

Step 1: Create Meta Pixel Component

Create components/MetaPixel.js:

'use client';

import Script from 'next/script';
import { useEffect } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';

export default function MetaPixel({ pixelId }) {
  const pathname = usePathname();
  const searchParams = useSearchParams();

  useEffect(() => {
    // Track page views on route change
    if (typeof window.fbq !== 'undefined') {
      window.fbq('track', 'PageView');
    }
  }, [pathname, searchParams]);

  return (
    <>
      <Script id="meta-pixel" strategy="afterInteractive">
        {`
          !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}');
          fbq('track', 'PageView');
        `}
      </Script>
      <noscript>
        <img
          height="1"
          width="1"
          style={{ display: 'none' }}
          src={`https://www.facebook.com/tr?id=${pixelId}&ev=PageView&noscript=1`}
          alt=""
        />
      </noscript>
    </>
  );
}

Step 2: Add to Root Layout

In app/layout.js:

import MetaPixel from '@/components/MetaPixel';
import { PrismicPreview } from '@prismicio/next';

const META_PIXEL_ID = process.env.NEXT_PUBLIC_META_PIXEL_ID;

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        {META_PIXEL_ID && <MetaPixel pixelId={META_PIXEL_ID} />}
      </head>
      <body>
        {children}
        <PrismicPreview repositoryName="your-repo-name" />
      </body>
    </html>
  );
}

Step 3: Environment Variables

Create .env.local:

NEXT_PUBLIC_META_PIXEL_ID=1234567890123456

For Next.js Pages Router

In pages/_app.js:

import Script from 'next/script';
import { useRouter } from 'next/router';
import { useEffect } from 'react';

const META_PIXEL_ID = process.env.NEXT_PUBLIC_META_PIXEL_ID;

function MyApp({ Component, pageProps }) {
  const router = useRouter();

  useEffect(() => {
    // Track page views on route change
    const handleRouteChange = () => {
      if (typeof window.fbq !== 'undefined') {
        window.fbq('track', 'PageView');
      }
    };

    router.events.on('routeChangeComplete', handleRouteChange);
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange);
    };
  }, [router.events]);

  return (
    <>
      <Script id="meta-pixel" strategy="afterInteractive">
        {`
          !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', '${META_PIXEL_ID}');
          fbq('track', 'PageView');
        `}
      </Script>
      <Component {...pageProps} />
    </>
  );
}

export default MyApp;

Method 2: Gatsby with Prismic

Step 1: Install Gatsby Meta Pixel Plugin

npm install gatsby-plugin-facebook-pixel

Step 2: Configure gatsby-config.js

module.exports = {
  plugins: [
    {
      resolve: 'gatsby-source-prismic',
      options: {
        repositoryName: 'your-repo-name',
        accessToken: process.env.PRISMIC_ACCESS_TOKEN,
      },
    },
    {
      resolve: 'gatsby-plugin-facebook-pixel',
      options: {
        pixelId: process.env.META_PIXEL_ID,
      },
    },
  ],
};

Step 3: Environment Variables

Create .env.production:

META_PIXEL_ID=1234567890123456
PRISMIC_ACCESS_TOKEN=your-access-token

Step 4: Track Custom Events

In gatsby-browser.js:

export const location }) => {
  if (typeof window.fbq === 'function') {
    window.fbq('track', 'PageView');

    // Track preview mode
    if (location.search.includes('preview=true')) {
      window.fbq('trackCustom', 'PreviewAccess', {
        path: location.pathname,
      });
    }
  }
};

Method 3: Custom React Implementation

For vanilla React or other frameworks:

// hooks/useMetaPixel.js
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

export function useMetaPixel(pixelId) {
  const location = useLocation();

  useEffect(() => {
    // Load Meta Pixel
    !(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'
    );

    window.fbq('init', pixelId);
    window.fbq('track', 'PageView');
  }, [pixelId]);

  useEffect(() => {
    if (typeof window.fbq === 'function') {
      window.fbq('track', 'PageView');
    }
  }, [location]);
}

Usage in App:

import { useMetaPixel } from './hooks/useMetaPixel';

function App() {
  useMetaPixel('1234567890123456');

  return <div>{/* Your app */}</div>;
}

Prismic-Specific Tracking

Track Slice Interactions

// slices/CallToActionSlice.js
'use client';

export default function CallToActionSlice({ slice }) {
  const handleCTAClick = () => {
    if (typeof window.fbq === 'function') {
      window.fbq('track', 'Lead', {
        content_name: slice.primary.title,
        content_category: 'CTA',
        slice_type: slice.slice_type,
      });
    }
  };

  return (
    <section>
      <h2>{slice.primary.title}</h2>
      <button
        {slice.primary.button_text}
      </button>
    </section>
  );
}

Track Form Submissions

// slices/ContactFormSlice.js
'use client';

export default function ContactFormSlice({ slice }) {
  const handleSubmit = async (e) => {
    e.preventDefault();

    // Track conversion
    if (typeof window.fbq === 'function') {
      window.fbq('track', 'Contact', {
        content_name: slice.primary.form_title,
        slice_type: slice.slice_type,
      });
    }

    // Submit form
    // ... form submission logic
  };

  return (
    <form
      {/* Form fields */}
      <button type="submit">Submit</button>
    </form>
  );
}

Track Document Views by Type

// In your Prismic page component
import { useEffect } from 'react';

export default function PrismicPage({ document }) {
  useEffect(() => {
    if (document && typeof window.fbq === 'function') {
      window.fbq('track', 'ViewContent', {
        content_ids: [document.id],
        content_type: document.type,
        content_name: document.data.title || document.uid,
      });
    }
  }, [document]);

  return (
    <div>
      {/* Render document */}
    </div>
  );
}

Standard Meta Pixel Events

Purchase Event

For e-commerce Prismic sites:

function handlePurchase(order) {
  if (typeof window.fbq === 'function') {
    window.fbq('track', 'Purchase', {
      value: order.total,
      currency: 'USD',
      content_ids: order.items.map(item => item.id),
      content_type: 'product',
    });
  }
}

Add to Cart Event

function handleAddToCart(product) {
  if (typeof window.fbq === 'function') {
    window.fbq('track', 'AddToCart', {
      value: product.price,
      currency: 'USD',
      content_ids: [product.id],
      content_name: product.name,
      content_type: 'product',
    });
  }
}

Lead Event

function handleLeadGeneration(formData) {
  if (typeof window.fbq === 'function') {
    window.fbq('track', 'Lead', {
      content_name: formData.formName,
      content_category: 'Lead Form',
    });
  }
}

Custom Events for Prismic

Track Prismic Preview Usage

// components/PrismicPreviewPixelTracking.js
'use client';

import { useEffect } from 'react';
import { useSearchParams } from 'next/navigation';

export function PrismicPreviewPixelTracking() {
  const searchParams = useSearchParams();
  const isPreview = searchParams.get('preview') === 'true';

  useEffect(() => {
    if (isPreview && typeof window.fbq === 'function') {
      window.fbq('trackCustom', 'PrismicPreviewAccess', {
        preview_mode: 'active',
      });
    }
  }, [isPreview]);

  return null;
}

Track Slice Zone Engagement

function trackSliceZone(slices) {
  if (typeof window.fbq === 'function') {
    window.fbq('trackCustom', 'SliceZoneView', {
      slice_count: slices.length,
      slice_types: slices.map(s => s.slice_type).join(','),
    });
  }
}

Advanced Match Parameters

Enhance conversion tracking with user data:

// Set advanced matching (if user data available)
if (typeof window.fbq === 'function') {
  window.fbq('init', 'YOUR_PIXEL_ID', {
    em: 'user@example.com', // Hashed email
    fn: 'john', // Hashed first name
    ln: 'doe', // Hashed last name
    ph: '1234567890', // Hashed phone number
  });
}

Note: Always hash personal information before sending to Meta Pixel.


Conversion API Integration

For server-side tracking with Prismic:

Next.js API Route

Create app/api/meta-conversion/route.js:

import { NextResponse } from 'next/server';

export async function POST(request) {
  const { event, eventData } = await request.json();

  const accessToken = process.env.META_CONVERSION_API_TOKEN;
  const pixelId = process.env.NEXT_PUBLIC_META_PIXEL_ID;

  const response = await fetch(
    `https://graph.facebook.com/v18.0/${pixelId}/events`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        data: [{
          event_name: event,
          event_time: Math.floor(Date.now() / 1000),
          user_data: {
            client_ip_address: request.headers.get('x-forwarded-for'),
            client_user_agent: request.headers.get('user-agent'),
          },
          custom_data: eventData,
        }],
        access_token: accessToken,
      }),
    }
  );

  const result = await response.json();
  return NextResponse.json(result);
}

Client-side usage:

async function trackServerSide(event, data) {
  await fetch('/api/meta-conversion', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ event, eventData: data }),
  });
}

Testing & Validation

1. Meta Pixel Helper Chrome Extension

  1. Install Meta Pixel Helper
  2. Visit your Prismic site
  3. Click the extension icon
  4. Verify Pixel is detected and events fire

2. Events Manager Test Events

  1. Go to Events Manager > Test Events
  2. Enter your browser identifier or IP
  3. Interact with your site
  4. See events appear in real-time

3. Browser Console Testing

// In browser console
console.log(window.fbq);
console.log(window._fbq); // Should show Meta Pixel object

// Test event manually
fbq('track', 'Lead', { test: true });

Common Issues & Solutions

Issue: Pixel Not Loading

Cause: Ad blocker or script not loaded

Solution: Test in incognito mode without extensions

Issue: Events Not Firing on Route Change

Cause: SPA navigation not tracked

Solution: Use route change listener (see Next.js example above)

Issue: Duplicate Events

Cause: Multiple Pixel initializations

Solution: Ensure Pixel component only rendered once in root layout

Issue: Preview Mode Events Not Tracked

Cause: Pixel excluded from preview

Solution: Don't exclude preview routes from Pixel loading


Privacy & Compliance

Implement consent before loading Pixel:

'use client';

import { useState, useEffect } from 'react';
import MetaPixel from './MetaPixel';

export function ConsentAwareMetaPixel({ pixelId }) {
  const [consent, setConsent] = useState(false);

  useEffect(() => {
    // Check consent (use your consent management platform)
    const hasConsent = localStorage.getItem('cookie-consent') === 'true';
    setConsent(hasConsent);
  }, []);

  if (!consent) return null;

  return <MetaPixel pixelId={pixelId} />;
}

Disable Automatic Advanced Matching

fbq('init', 'YOUR_PIXEL_ID', {
  autoConfig: false,
  enableAutomaticMatching: false,
});

Next Steps


Additional Resources