Meta Pixel Not Firing? 8 Common Causes and How to Fix Each

Quick fix: Open your page with the browser DevTools Network tab filtered to facebook. If fbevents.js never loads, the base code is missing, blocked by a consent tool, or blocked by your Content Security Policy. If it loads but no request goes to facebook.com/tr, check the pixel ID in fbq('init') and the order of your fbq calls.
A Meta Pixel that does not fire is one of the most common tracking problems, and it rarely has a mysterious cause. The pixel is a small JavaScript library plus a few function calls. Either the library never loads, it loads but is never initialized with your ID, or the event calls run at the wrong time.
This guide walks through the causes in the order you are most likely to hit them. For each one you get a quick way to confirm it and a concrete fix. Work from the top, because the early checks rule out whole groups of later problems.
Before you start: get a clean test setup
Use a browser profile with no ad blocker or privacy extensions, or a private window with extensions disabled. Open DevTools, go to the Network tab, enable "Preserve log", and type facebook in the filter box. You are looking for two things:
- A request for
connect.facebook.net/en_US/fbevents.js(the library) and one for/signals/config/<your pixel ID>(its configuration). - One or more requests to
www.facebook.com/trwithev=PageViewor another event name in the query string. These are the actual events.
Also open the Console tab. Errors such as fbq is not defined or a "Refused to load the script" message point straight at the cause. A browser extension that lists detected pixels, such as the Pixel Helper extension, gives you the same picture in a friendlier view, but DevTools is always available and never lies about what was requested.
1. The base code is missing or in the wrong place
Meta recommends placing the base code between the opening and closing <head> tags on every page you want to track. The most common real-world failure is simpler than that: the code is only on some templates. It was added to the home page layout but not to the checkout, landing page builder, or blog.
How to confirm: view the page source (not the rendered DOM) and search for fbevents.js and fbq('init'. If neither appears and you don't load the pixel through a tag manager, the code isn't there.
Fix: add the base code to the shared header template that every page uses. Copy it fresh from Events Manager rather than from an old email or another site. Leave the fbq('track', 'PageView'); line in place; Meta's get started guide recommends keeping it intact.
2. The pixel ID is wrong
The pixel ID appears twice in the base code: inside fbq('init', '...') and inside the <noscript> image URL. Copy-paste errors, a leftover ID from a previous agency, or a staging pixel left in production all produce a pixel that "fires" but sends data somewhere you aren't looking.
How to confirm: in the Network tab, click a facebook.com/tr request and read the id= parameter. Compare it to the ID shown for your pixel (dataset) in Events Manager.
Fix: correct the ID in both places. If you use a platform integration, change the connected pixel in the integration settings rather than editing code it generates.
3. A consent banner is holding the pixel back
If your site uses a consent management platform, the pixel may be intentionally blocked until the visitor accepts marketing cookies. That is correct behavior, but it looks exactly like a broken pixel when you test without clicking "Accept".
Some setups use Meta's consent API instead of blocking the script. Meta documents fbq('consent', 'revoke'), called before init, to pause sending events, and fbq('consent', 'grant') once the visitor agrees. Meta notes you need to call revoke on every page. See the GDPR implementation guide.
<script>
fbq('consent', 'revoke');
fbq('init', 'YOUR_PIXEL_ID');
fbq('track', 'PageView');
</script>
<!-- later, after the visitor accepts -->
<script>
fbq('consent', 'grant');
</script>
How to confirm: reload with no stored consent, accept marketing cookies, and watch whether /tr requests start. If they only start after accepting, consent is working as designed.
Fix: if the pixel never fires even after consent, check that the consent tool actually calls grant or releases the blocked script. A common bug is a consent category mismatch, for example the pixel tagged as "statistics" while the visitor accepted "marketing".
4. An ad blocker or privacy feature is blocking it
Many ad blockers and some browser privacy modes block connect.facebook.net and facebook.com/tr outright. In the Network tab these requests show as blocked or fail with a client error, and the Console may show ERR_BLOCKED_BY_CLIENT.
Fix: for testing, use a clean profile. For production, you cannot make a browser pixel immune to blockers. The usual mitigation is sending the same events server-side through the Conversions API, then deduplicating them. Our guide on ad blockers, ITP and pixel data loss covers what you can and can't recover.
5. Your Content Security Policy blocks Meta's domains
If your site sends a Content-Security-Policy header, the browser refuses any script or request not on the allow list. The Console shows a clear "Refused to load the script" or "Refused to connect" message naming the blocked URL and directive.
Fix: Meta's advanced pixel documentation says to allow JavaScript from https://connect.facebook.net. The pixel sends events to https://www.facebook.com/tr, so if your policy restricts img-src or connect-src, that host needs to be allowed as well. Use the exact directive named in the Console error. The MDN CSP reference explains each directive, and our CSP troubleshooting guide has worked examples.
Content-Security-Policy: script-src 'self' https://connect.facebook.net; img-src 'self' https://www.facebook.com; connect-src 'self' https://www.facebook.com
Merge these sources into your existing policy rather than replacing it.
6. The Google Tag Manager trigger is wrong
When the pixel lives in a GTM Custom HTML tag, the tag itself can be fine while the trigger never matches. Typical mistakes:
- The container version with the tag was never published, so it only works in Preview mode.
- The base code tag uses a trigger limited to certain pages, while event tags fire everywhere.
- An event tag (for example Purchase) fires before the base code tag, because tag sequencing was not set.
- The trigger depends on a dataLayer event name that your site doesn't push, or pushes with different capitalization.
Fix: in GTM Preview, select the page load and confirm the base code tag is listed under "Tags Fired". Fire the base code on all pages, as early as your consent setup allows, and use tag sequencing so event tags run only after it. If Preview itself won't connect, see GTM Preview mode not working.
7. fbq is called before the pixel is initialized
The base code defines a small fbq stub that queues calls until the library loads. That means order matters in two ways:
- If your event code runs before the base code snippet exists on the page, the browser throws
ReferenceError: fbq is not definedand the event is lost. - If
fbq('track', ...)runs beforefbq('init', 'YOUR_PIXEL_ID'), there is no pixel to attach the event to.
How to confirm: look for fbq is not defined in the Console, and check script order in the page source. Theme snippets that sit above the header include, and inline scripts in page builders, are frequent offenders.
Fix: make sure the base code (with init) is the first pixel code on the page. If an event must run from a script that might load earlier, guard it:
if (typeof window.fbq === 'function') {
fbq('track', 'Lead');
}
A guard prevents the error, but it also silently skips the event, so fix the ordering too.
8. A single-page app doesn't fire on route changes
In React, Vue, Next.js and similar apps, the page loads once and later "pages" are rendered by the router without a full reload. The base code fires one PageView on that first load. Whether additional navigations are tracked depends on your setup, so the result can be missing PageViews, or doubled ones once someone adds a manual call.
How to confirm: click through several routes with the Network tab open and count ev=PageView requests. You want exactly one per navigation.
Fix: load the base code once in the app shell, then call fbq('track', 'PageView') from your router's navigation hook only if PageViews are missing. Our SPA route change tracking guide shows patterns for common frameworks.
How to verify the fix
- Reload the page in a clean browser profile and confirm
fbevents.js, the/signals/config/request and at least one/trrequest with your pixel ID. - Trigger the conversion you care about (add to cart, form submit, purchase on a test order) and confirm its
/trrequest. - Open the Test Events tab for your pixel in Events Manager and repeat the steps. Events should appear within moments.
- Check the pixel's Overview in Events Manager. Meta notes that new events can take a few minutes to show, so refresh if you don't see them right away.
Meta's own browser extension, Meta Ads Data Advisor, is another option for this check. Meta says it replaces the company's earlier pixel debugging extension and that existing installs update to it automatically. See the official documentation.
FAQ
The pixel fires in GTM Preview but not on the live site. Why?
Almost always because the container changes were not published, or because a consent tool behaves differently on the live domain. Publish the container, then retest on the live site in a clean browser after accepting cookies.
Events Manager says "no activity yet" but I see requests in DevTools. What's wrong?
Check the id= value on the /tr requests. If it matches your pixel, give it a few minutes and refresh. If it doesn't match, your site is sending to a different pixel, often an old one from a previous setup.
Do I still need the noscript image tag?
It only matters for visitors with JavaScript disabled, and it can only send a simple PageView. Keeping it does no harm, but make sure its pixel ID matches the one in fbq('init').
Can I fix ad blocker losses on the browser side?
Not reliably. The supported approach is to also send key events through the Conversions API from your server and deduplicate them with matching event IDs.
