Install Meta Pixel with DatoCMS | OpsBlu Docs

Install Meta Pixel with DatoCMS

Step-by-step guide to installing Meta Pixel (Facebook Pixel) on DatoCMS-powered websites.

Install Meta Pixel on your DatoCMS-powered website to track conversions and optimize Facebook/Instagram advertising. Since DatoCMS is headless, Meta Pixel is implemented in your frontend framework.

Prerequisites

  • Meta Pixel ID (from Meta Business Manager)
  • DatoCMS project with GraphQL API access
  • Developer access to frontend codebase
  • Meta Business Manager account

Step 1: Create Meta Pixel

If you don't have a Meta Pixel:

  1. Go to Meta Events Manager
  2. Click Connect Data SourcesWeb
  3. Select Meta Pixel
  4. Enter your pixel name
  5. Optional: Enter website URL
  6. Click Create Pixel
  7. Copy your Pixel ID (format: 16-digit number)

Step 2: Install Meta Pixel in Frontend

Next.js (App Router)

1. Create Meta Pixel Component

Create app/components/MetaPixel.tsx:

'use client'

import Script from 'next/script'
import { useEffect } from 'react'

export function MetaPixel() {
  const PIXEL_ID = process.env.NEXT_PUBLIC_META_PIXEL_ID

  if (!PIXEL_ID) {
    console.warn('Meta Pixel ID not found')
    return null
  }

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

2. Add to Root Layout

Update app/layout.tsx:

import { MetaPixel } from './components/MetaPixel'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <MetaPixel />
        {children}
      </body>
    </html>
  )
}

3. Set Environment Variable

Create .env.local:

NEXT_PUBLIC_META_PIXEL_ID=1234567890123456
NEXT_PUBLIC_DATOCMS_API_TOKEN=your-token

4. Track DatoCMS Content Views

Create app/components/DatoCMSMetaTracker.tsx:

'use client'

import { useEffect } from 'react'

export function DatoCMSMetaTracker({ record }: { record: any }) {
  useEffect(() => {
    if (typeof window !== 'undefined' && window.fbq) {
      window.fbq('track', 'ViewContent', {
        content_name: record.title,
        content_category: record._modelApiKey,
        content_ids: [record.id],
        content_type: 'datocms_content',
      })
    }
  }, [record])

  return null
}

Use in your page:

// app/blog/[slug]/page.tsx
import { DatoCMSMetaTracker } from '@/app/components/DatoCMSMetaTracker'

export default async function BlogPost({ params }) {
  const post = await fetchDatoCMSPost(params.slug)

  return (
    <div>
      <DatoCMSMetaTracker record={post} />
      <article>{/* Content */}</article>
    </div>
  )
}

Next.js (Pages Router)

1. Update _document.tsx

// pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  const PIXEL_ID = process.env.NEXT_PUBLIC_META_PIXEL_ID

  return (
    <Html>
      <Head>
        <script
          dangerouslySetInnerHTML={{
            __html: `
              !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', '${PIXEL_ID}');
              fbq('track', 'PageView');
            `,
          }}
        />
      </Head>
      <body>
        <noscript>
          <img
            height="1"
            width="1"
            style={{ display: 'none' }}
            src={`https://www.facebook.com/tr?id=${PIXEL_ID}&ev=PageView&noscript=1`}
          />
        </noscript>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

2. Track Route Changes

Update pages/_app.tsx:

import { useEffect } from 'react'
import { useRouter } from 'next/router'

export default function App({ Component, pageProps }) {
  const router = useRouter()

  useEffect(() => {
    const handleRouteChange = () => {
      if (window.fbq) {
        window.fbq('track', 'PageView')
      }
    }

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

  return <Component {...pageProps} />
}

Gatsby

1. Install Plugin

npm install gatsby-plugin-facebook-pixel

2. Configure Plugin

Update gatsby-config.js:

module.exports = {
  plugins: [
    {
      resolve: 'gatsby-source-datocms',
      options: {
        apiToken: process.env.DATOCMS_API_TOKEN,
      },
    },
    {
      resolve: 'gatsby-plugin-facebook-pixel',
      options: {
        pixelId: process.env.META_PIXEL_ID,
      },
    },
  ],
}

3. Track DatoCMS Content

// src/templates/blog-post.js
import React, { useEffect } from 'react'

const BlogPostTemplate = ({ data }) => {
  const post = data.datoCmsBlogPost

  useEffect(() => {
    if (typeof window !== 'undefined' && window.fbq) {
      window.fbq('track', 'ViewContent', {
        content_name: post.title,
        content_category: 'blog_post',
        content_ids: [post.originalId],
      })
    }
  }, [post])

  return <article>{/* Content */}</article>
}

export default BlogPostTemplate

React SPA (Vite, CRA)

1. Add Meta Pixel to index.html

Update public/index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Meta Pixel Code -->
    <script>
      !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', '1234567890123456');
      fbq('track', 'PageView');
    </script>
    <noscript>
      <img height="1" width="1" style="display:none"
      src="https://www.facebook.com/tr?id=1234567890123456&ev=PageView&noscript=1"/>
    </noscript>
    <!-- End Meta Pixel Code -->
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

2. Track Route Changes

// App.tsx
import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'

function App() {
  const location = useLocation()

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

  return <Router>{/* Routes */}</Router>
}

Step 3: Add TypeScript Definitions

Create types/facebook-pixel.d.ts:

declare global {
  interface Window {
    fbq: (
      command: 'track' | 'trackCustom' | 'init',
      eventName: string,
      params?: Record<string, any>
    ) => void
  }
}

export {}

Step 4: Track DatoCMS Events

Product Views (E-commerce)

function trackProductView(product: any) {
  if (window.fbq) {
    window.fbq('track', 'ViewContent', {
      content_name: product.title,
      content_category: product.category?.title,
      content_ids: [product.id],
      content_type: 'product',
      value: product.price,
      currency: 'USD',
    })
  }
}

Add to Cart

function trackAddToCart(product: any, quantity: number) {
  if (window.fbq) {
    window.fbq('track', 'AddToCart', {
      content_name: product.title,
      content_ids: [product.id],
      content_type: 'product',
      value: product.price * quantity,
      currency: 'USD',
    })
  }
}

Purchase

function trackPurchase(order: any) {
  if (window.fbq) {
    window.fbq('track', 'Purchase', {
      value: order.total,
      currency: 'USD',
      content_ids: order.items.map(item => item.product.id),
      content_type: 'product',
      contents: order.items.map(item => ({
        id: item.product.id,
        quantity: item.quantity,
        item_price: item.price,
      })),
    })
  }
}

Lead Form Submission

function trackLead(formData: any, contentId: string) {
  if (window.fbq) {
    window.fbq('track', 'Lead', {
      content_name: 'Contact Form',
      content_category: 'form_submission',
      content_ids: [contentId],
    })
  }
}

Step 5: Verify Installation

Use Meta Pixel Helper

  1. Install Meta Pixel Helper Chrome extension
  2. Navigate to your DatoCMS site
  3. Click extension icon
  4. Verify:

Check Events Manager

  1. Go to Meta Events Manager
  2. Select your pixel
  3. Click Test Events
  4. Enter your website URL
  5. Click Open Website
  6. Verify events appear in real-time

Browser Console

// Check if fbq is loaded
console.log(typeof window.fbq) // should be 'function'

// Test event
window.fbq('trackCustom', 'Test Event', { test: 'value' })

Advanced Configuration

Exclude Preview Mode

const isPreview = searchParams.get('preview') === 'true'

if (!isPreview) {
  // Track with Meta Pixel
}
'use client'

import { useEffect, useState } from 'react'

export function MetaPixelWithConsent() {
  const [hasConsent, setHasConsent] = useState(false)

  useEffect(() => {
    const consent = localStorage.getItem('marketing_consent')
    setHasConsent(consent === 'granted')
  }, [])

  if (!hasConsent) return null

  return <MetaPixel />
}

Server-Side Events (Conversions API)

For improved tracking, implement Conversions API:

// pages/api/facebook-conversion.ts
export default async function handler(req, res) {
  const response = await fetch(
    `https://graph.facebook.com/v18.0/${process.env.META_PIXEL_ID}/events`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        data: [{
          event_name: req.body.event,
          event_time: Math.floor(Date.now() / 1000),
          user_data: {
            client_ip_address: req.headers['x-forwarded-for'],
            client_user_agent: req.headers['user-agent'],
          },
          custom_data: req.body.data,
        }],
        access_token: process.env.META_CONVERSION_API_TOKEN,
      }),
    }
  )

  res.status(200).json(await response.json())
}

Troubleshooting

For common issues, see:

Next Steps