top of page

The 2 Second JavaScript Fix That Saved My Facebook Ads

  • admin67410
  • May 22
  • 8 min read

Updated: Aug 5

Let's be honest here. Facebook Ads are not what they used to be. If you look at the dedicated subreddits on advertising and Facebook Groups for authors, they are filled with the same complaints. Previously high-performing ads suddenly die. They get flooded with bot traffic and go from being highly profitable to burning money. Authors end up constantly duplicating their ads, hoping for another 7 to 14-day burst of high-intent traffic before the bots find them all over again.


I know the pain well. I've been having similar issues with my own ads. In early 2025, my return on ad spend (ROAS) went off a cliff and never really recovered. I did course after course after course. I read all of the forums and threads. And yet, my ad account continued to hemorrhage money. By December 2025, I stopped running them altogether and watched my sales slow to a trickle.


In March of this year, tired of watching the dwindling figures in my bank account, I decided to build a technical solution to the problem.


The Facebook Ad Death Spiral


The problem we face is that the Facebook Ads AI inherently wants to serve your ads to get the highest number of clicks possible. A couple of years ago, standard pay-per-click traffic ads worked well, but those died in a big way last year. The conventional wisdom now is to use Sales campaigns pointing to a dedicated landing page on your website that has the Facebook Pixel set up on it. In theory, this sends better conversion data back to Facebook's system, allowing it to deliver better targeting. And it works. For a short time.


Eventually, the bots track you down. What happens next is a silent budget killer: a ton of automated bots click your ad, land on your page, and immediately click your outbound links. You spend the money, but you get zero actual sales.


Worse yet, because Facebook's algorithm thinks it did a great job finding people who click your links, it optimizes your campaign to find more of those exact profiles. It actively trains itself to hunt down bot traffic instead of real readers.


The 2-Second Javascript Solution


My solution to breaking this cycle was pretty simple. Bots are configured for high-volume, rapid clicks. They want to hit a page, click the main calls to action instantly, and move on to the next site to scrape data or simulate activity. They rarely linger.


So, I wrote a small bit of Javascript for my landing page that does one simple thing: it prevents link clicks from registering with the Facebook Pixel until the page has been loaded for a full two seconds.


If a bot lands on the page and clicks the Amazon button within 1.5 seconds, the link still opens normally so the site doesn't feel broken, but the conversion pixel never fires. To Facebook's AI, that junk click never happened.


After setting this up, I launched a clean Sales campaign:

  • Structure: 1 campaign, 1 ad set, 1 ad creative

  • Testing: 3 variations of the primary text, headline, and description

  • Budget: £15 a day

  • Rule: Leave it completely alone for ten weeks.


The Hard Data


At first, the campaign just ticked over nicely, performing more or less how you would expect a fresh ad to run. But because the pixel was only allowed to record data from visitors who lingered for more than two seconds, the long-term trends completely changed.


Look at the massive discrepancy between the raw clicks and the qualified human clicks over that ten-week period:

  • Total Raw Link Clicks: 4,973

  • Actual Landing Page Views: 3,428

  • Qualified Human Results (Clicks after the 2-second delay): 1,357


Over 1,500 clicks were stripped away by the gatekeeper. Because the pixel was completely shielded from those artificially inflated bot strikes, the algorithm spent the last two months learning exclusively from real human behavior. It got better at finding actual readers who buy books, rather than bots that burn budgets.



As a result, the ad isn't decaying. In fact, it's performing better the longer it runs. My sustained ROAS for the current week is up around 3.92.



I made some mistakes early on, like routing the buttons to a universal link aggregator (which just added another layer of click friction). Moving forward, I am linking straight to direct Amazon URLs and building a dedicated landing page for each target country.


And it's important to remember that your advert creatives have to work, your landing page needs to make the reader want the book even more, and your Amazon product page needs to seal the deal. This workaround won't solve those problems, but at least it should put you back on a level playing field.


The Code (Do It Yourself)


⚠️ Important Note for Authors: If you copy and paste the HTML block below, make sure to replace the placeholder Amazon URL (https://www.amazon.com/dp/B0068NOYM8) and the image source URL with your own book link and button graphics. Otherwise, you will be paying to advertise my books!

Step 1: Add the Global Script


Paste this global script block into the header or top section of your custom landing page code:


<script>

// 1. Initialize the Humanity Check immediately

window.isHumanVisitor = false;


// 2. Start the 2-second countdown

setTimeout(function() {

window.isHumanVisitor = true;

}, 2000);


// 3. The Shared Function (Used by ALL buttons)

function safePixelFire(contentName) {

if (window.isHumanVisitor) {

fbq('track', 'Purchase', {

value: 3.00,

currency: 'GBP',

content_name: contentName

});

}

return true; // Always allow the link to open normally

}

</script>


Step 2: Set Up Your Buttons


Then, use this structure for your actual on-page buttons and text links further down the body:


<!-- Image Button Example -->

<div style="text-align: center; margin: 20px 0;">

<a href="https://www.amazon.com/dp/B0068NOYM8" target="_blank" onclick="return safePixelFire('Book Launch - Top Image');">

<img src="YOUR_BUTTON_IMAGE_URL_HERE.png" alt="Get it on Amazon" style="max-width: 100%; height: auto; display: inline-block;">

</a>

</div>


<!-- Text Link Example -->

<h2 style="text-align: center; font-weight: bold; margin-top: 15px;">

<a href="https://www.amazon.com/dp/B0068NOYM8" target="_blank" style="color: rgb(0,0,0); text-decoration: underline; cursor: pointer;" onclick="return safePixelFire('Book Launch - Top Text');">

Available to read for FREE on Kindle Unlimited

</a>

</h2> If you are using Wix...

Wix won't let you add an onclick to one of its own button elements, so the code as written in the post assumes you've built the button in an HTML embed. If your button is a normal Wix one, use this version instead. It goes in Settings > Custom Code in the dashboard, not on the page, and it watches for clicks on any link going to Amazon rather than needing anything attached to the button itself.


<script>

window.isHumanVisitor = false;

setTimeout(function() { window.isHumanVisitor = true; }, 2000);


document.addEventListener('click', function(e) {

var link = e.target.closest('a');

if (!link || !link.href) return;

if (link.href.indexOf('amazon.') === -1) return;

if (!window.isHumanVisitor) return;

if (typeof fbq === 'undefined') return;

fbq('track', 'Purchase', {

value: 3.00,

currency: 'GBP',

content_name: 'Landing page button'

});

}, true);

</script>


Change the value to whatever a sale is actually worth to you in royalties, and the currency to match. If you're sending people somewhere other than Amazon, swap that bit for whatever's in your link.


Checking it actually works

Three ways, easiest first.

Meta's own test tool. In Events Manager, open your pixel and click Test Events. Paste in your landing page URL and open it. Events appear in the list as they fire. Wait five seconds, click your button, and you should see a Purchase event arrive. Click the button the instant the page loads instead and nothing should appear, which is the whole point.


Meta Pixel Helper. A free Chrome extension. Load your page, count to five, then click the extension icon. It should show your pixel and a PageView. Click your button (it opens Amazon in a new tab, so come back to the original) and check again for the Purchase event. One warning: if you click the icon straight away it will tell you there's no pixel on the page. That's correct rather than broken. There isn't one yet.


The browser's own network log. Fiddlier, but definitive.

On Chrome or Edge, right-click anywhere on your page and choose Inspect. A panel opens, usually at the side or bottom. Along the top of that panel there's a row of tabs, one of which says Network. Click it, then reload your page, because it only records from the moment it's open.

There's a filter box near the top of that panel. Type tr?id= into it. Wait five seconds and you should see a line appear. That's the pixel reporting in. Click your button and another should appear.

On Safari you have to switch the tools on first. Safari menu, Settings, Advanced, then tick the box about showing features for web developers. After that, right-click and Inspect Element works the same way.

If nothing shows after ten seconds, the pixel isn't loading at all, and the usual culprit is the code sitting in a page element rather than in Settings, Custom Code. Alternatively, if the pixel is firing before the two seconds are up, then the chances are that it's native integration is still enabled. You need to make sure that is turned off and the pixel is only initialised through the custom code.


The traffic campaign problem

Everything above works because a Sales campaign optimises against something you control, which is the click on your outbound link. Traffic campaigns don't work like that. The event Meta learns from is the landing page view, and that fires the moment your pixel initialises. There's no click to intercept.

So you move the delay one step earlier and hold back the pixel itself.


<script>

setTimeout(function() {

!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', 'YOUR_PIXEL_ID_HERE');

fbq('track', 'PageView');

}, 2000);


setTimeout(function() {

if (typeof fbq !== 'undefined') {

fbq('trackCustom', 'EngagedVisitor');

}

}, 15000);

</script>


Two timers, both counting from page load. The pixel initialises at two seconds. A second event, EngagedVisitor, fires at fifteen. Anyone who leaves before then simply never fires it, which is exactly the signal you want.

That second event matters more than it looks. Landing page views tell you somebody's browser loaded a page. EngagedVisitor tells you somebody was still there fifteen seconds later, which on a page with a few hundred words means they were reading it. Once you have a few weeks of that data you can optimise towards it rather than towards clicks.


What the numbers looked like

Running this on a new landing page, 95 clicks produced 53 landing page views. Forty-four per cent of the traffic Meta charged me for didn't survive two seconds on the page.

For comparison, one of my established book campaigns ran 1,417 clicks to 966 landing page views over the same period, so about a third fell away. The colder and cheaper the traffic, the more of it evaporates when you ask it to wait two seconds.


Three things that will trip you up

Pixel Helper will tell you your pixel is missing. It checks the page as it loads, and for the first two seconds there genuinely isn't one. Load the page, count to five, then click the icon.


If you're on Wix, disconnect the native Facebook integration first. It loads its own copy of the pixel with no delay, which quietly undoes everything above. On Wix this sits in the Custom Code, which you set from the Dashboard - not from an inline HTML element on the page.


And give it a fortnight before you judge anything. Your click numbers will look worse immediately, because you're throwing away clicks you were previously counting. The point is that the ones left should be real.


What this really comes down to

You're paying for a measurement system that you don't own and can't audit, and that system is being gamed by people who aren't your customers. You can't stop the bots arriving. What you can do is decide what counts as a real visit, and refuse to report anything else.


Two seconds is arbitrary. Pick your own number. The principle is what matters: the algorithm learns from whatever you feed it, so be careful about what you give it for lunch. One More Thing... Fixing your pixel only matters if the rest of it holds up. Your creative has to work, your landing page has to do its job, and you need to know what a sale is actually worth to you before you spend a penny finding one.


That's the marketing chapter of The Small Press Operating Manual, and it comes with the ad tracker I use to work out whether a campaign is paying for itself. Both free.


Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
bottom of page