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:
- Go to Meta Events Manager
- Click Connect Data Sources → Web
- Select Meta Pixel
- Enter your pixel name
- Optional: Enter website URL
- Click Create Pixel
- 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
- Install Meta Pixel Helper Chrome extension
- Navigate to your DatoCMS site
- Click extension icon
- Verify:
Check Events Manager
- Go to Meta Events Manager
- Select your pixel
- Click Test Events
- Enter your website URL
- Click Open Website
- 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
}
Consent Management
'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:
- Events Not Firing - Debug tracking issues
- Performance Issues - Optimize page load
Next Steps
- Track Custom Events - Configure events
- Install GTM - Manage via Tag Manager
- Optimize Performance - Improve Core Web Vitals