If you run Facebook or Instagram ads to a landing page, you’ve probably noticed high click numbers, 80%+ bounce rates, and 2-second or even 0 second visits.
Some of this can be explained by fat-finger syndrome. They wanted to skip your ad > hit the CTA and quickly left.
The majority of this traffic can be explained by bots clicking your Meta ads.
Here’s what’s actually happening: When you run ads, Meta’s automated compliance scrapers, ad review bots, and "potentially affiliated Audience Network click-farms", hit your URL first.
They open your page, stay for 1 to 2 seconds, never touch the screen, and vanish.
Because the standard Meta pixel fires fbq('track', 'PageView') the millisecond your HTML loads, Meta records that bot visit as a successful "Landing Page View."
The algorithm can think: "Great! That person loved the ad. Let's go find 50,000 more users just like that bot."
Your ad account starts optimizing for junk traffic instead of real, delicious buyers.
The Fix: Stop firing PageView on page load. Fire it only when a real person shows up
Real humans do things bots usually don't:
- They scroll past the top of the page.
- They tap or click something.
- They move the mouse naturally.
- They stay on an active tab for more than a few seconds while reading or watching.
The script below loads the Meta pixel as normal but holds back the PageView event until one of those things happens.
Before you paste it: replace YOUR_PIXEL_ID with your own Pixel ID, and remove any other Meta pixel already on your site (see the platform notes below). It's copy-paste ready, but feel free to run it through an AI tool to check it first.
<!-- Human-Gated Meta Pixel (MTHD) -->
<script>
(function () {
// 1. Paste your Meta Pixel ID here (numbers only)
var PIXEL_ID = 'YOUR_PIXEL_ID';
// 2. Pages that should fire PageView straight away (thank-you / confirmation pages)
var INSTANT_PATHS = ['/thank-you', '/order-confirmation'];
// Safety check: do nothing if the Pixel ID hasn't been added
if (!/^\d+$/.test(PIXEL_ID)) {
if (window.console) console.warn('Human-Gated Meta Pixel: add your Pixel ID.');
return;
}
// Standard Meta pixel loader
!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');
// Stop Meta's automatic events firing before the human check (must come before init)
fbq('set', 'autoConfig', false, PIXEL_ID);
fbq('init', PIXEL_ID);
var fired = false;
var moves = 0;
var timer = null;
var EVENTS = ['scroll', 'wheel', 'keydown', 'click', 'touchstart', 'mousemove'];
var OPTS = { passive: true, capture: true };
function firePixel() {
if (fired) return;
fired = true;
fbq('track', 'PageView');
cleanup();
}
function cleanup() {
EVENTS.forEach(function (evt) {
window.removeEventListener(evt, checkHuman, OPTS);
});
window.removeEventListener('focus', onFocus);
if (timer) clearTimeout(timer);
}
// Thank-you and confirmation pages: fire immediately, no gate
var path = window.location.pathname;
for (var i = 0; i < INSTANT_PATHS.length; i++) {
if (path.indexOf(INSTANT_PATHS[i]) === 0) {
firePixel();
return;
}
}
function scrolledPast80(e) {
var y = window.pageYOffset || document.documentElement.scrollTop || 0;
if (y > 80) return true;
// Sites that scroll inside a container rather than the page itself
var t = e.target;
return !!(t && t.scrollTop > 80);
}
function checkHuman(e) {
if (fired) return;
if (e.type === 'scroll') {
if (scrolledPast80(e)) firePixel();
} else if (e.type === 'mousemove') {
moves++;
if (moves > 3) firePixel();
} else {
// wheel, keydown, click, touchstart
firePixel();
}
}
// Fallback: someone reading quietly on an active tab for 6 seconds
function startTimer() {
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
if (!fired && document.hasFocus && document.hasFocus()) firePixel();
}, 6000);
}
function onFocus() {
if (!fired) startTimer();
}
EVENTS.forEach(function (evt) {
window.addEventListener(evt, checkHuman, OPTS);
});
window.addEventListener('focus', onFocus);
startTimer();
})();
</script>
Edit the instantPaths list to match your own thank-you page URLs.
How to check it's working
Open Events Manager → Test Events, enter your URL, and load the page. You should see no PageView until you scroll, click or wait six seconds. You can also use the free Meta Ads Data Advisor Chrome extension.
Common questions
Does this break purchase or lead tracking?
No. The gate only applies to PageView. Your Lead, Purchase and other conversion events fire exactly as they do now.
What happens to my numbers in Ads Manager?
Clicks and CTR stay the same, because the gate doesn't change who clicks your ad. Your Cost per Landing Page View will go up, because you've stopped counting visits that were never real. That's the point: Meta gets cleaner data to optimize on, which is where the budget saving comes from over time. It's worth noting the date you install it so you can compare before and after.
Does this block bot clicks?
No, you may still pay for some junk clicks. What changes is that Meta stops learning from them, so it stops chasing more of the same. Or at least that's our theory - and it seems to be working for us right now.
What about thank-you and order confirmation pages?
Those pages should never be gated. The script above fires immediately on any URL in the instantPaths list.
Do I still need cookie consent?
Yes. If you have visitors in the UK or EU, this doesn't replace your consent banner. The pixel should still only load after consent is given.
I use the Conversions API. Does this still help?
Partly. It gates the browser PageView only. Server-side PageView events sent through the Conversions API aren't affected, so the bigger win is on sites relying on the browser pixel.
Platform setup
Webflow
Works cleanly. Paste it into Site Settings → Custom Code → Head Code, or into a single page's settings if you only want it on your landing pages.
- Custom code only runs on the published site, not in the Designer, so test on your live or staging domain.
- If the Meta pixel is already installed through an integration or another embed, remove it, or you'll get a second, ungated PageView.
WordPress
Works, with two common traps.
- Duplicate pixels. If PixelYourSite, Meta's official plugin, or a theme setting is already adding the pixel, it will fire PageView immediately and your gate does nothing. Disable it first.
- Caching and optimization plugins (WP Rocket, Autoptimize, LiteSpeed) can delay or combine scripts. That won't break it, but it can make the 6-second fallback unpredictable. Exclude this script from delay and minify settings.
The easiest place to add it is a header plugin like WPCode, so theme updates don't wipe it.
Shopify
This is where it's weakest.
- Added to
theme.liquid, it works on storefront pages but not on checkout or thank-you pages, which don't load theme code. - Added as a Customer Events custom pixel, it runs in a sandboxed frame and can't see real scrolling or clicks, so the gate won't work.
- If the Facebook & Instagram sales channel is connected, Shopify already sends PageView from the browser and the server. Adding this script creates a duplicate. For most Shopify stores, focus on optimizing for purchases rather than gating PageView.
Disclaimer: This is part of our efforts to fix our own Meta ads bot problems for ourselves and our clients. Please take this information at your own risk and monitor your performance closely. We cannot make any performance guarantees. Only speak anecdotally about what has worked for us and our clients. Also, we are not prescribing any intent behind Meta Ads Bots or saying anyone is responsible for the wasted spend. It's just part of how the platform currently works.
Remember, this is a filter - not a wall. A sophisticated bot that simulates clicks or scrolling will get through. It filters out the lazy majority, which is the point.






