I want to detect in my JavaScript code that the load of a Facebook pixel has been completed. Is this possible?
For reference here is the Facebook Pixel Tracking 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','//connect.facebook.net/en_US/fbevents.js');
// Insert Your Facebook Pixel ID below.
fbq('init', 'FB_PIXEL_ID');
fbq('track', 'PageView');
</script>
<!-- Insert Your Facebook Pixel ID below. -->
<noscript><img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=FB_PIXEL_ID&ev=PageView&noscript=1"
/></noscript>
Breaking it down, it seems that fbq('init', ...)
causes a script
tag to be added with the async
attribute set and src
set to //connect.facebook.net/en_US/fbevents.js
.
Subsequently the call to fbq('track', ...)
somehow causes an HTTP GET
to an image via one redirect.
How to detect that all the steps are complete, especially that the final image load is complete?
So Kelly Seldens solution looks great but didnt work for me due to facebook changing their library. My solution is derived from Kelly Seldens and is as follows (applicable to facebook 2.9.15). I offer it up for other people looking for solutions to firing off actions based on facebook pixel being loaded.
In my case, I have Mautic loading the fb pixel on its own. I needed a way to detect when this occured so that I could fire off a conversion event (fb - track lead).
The changes I made to Kelly's code reflects 2 things:
First I added in the condition checking if fbq is defined. Before doing this I was getting console errors that fbq was undefined each time the timeout executed.
Second, I removed the fbq.on statement simple because it doesnt exist anymore in the 2.9.15 version of the pixel being loaded by Mautic.
The final code I ended up with is:
(function wait() {
//first check if the fbq object is defined, then check the version (probably not needed but for good measure
if ((typeof fbq !== 'undefined') && (fbq.version > '2.9')) {
//fire off the call back / tracking event
myCallBack(); //fbq('track', 'Lead');
}
else
setTimeout(wait, 10);
})();
Since OP @user2297550 said his ultimate goal is to redirect a user after an event fires, I'll explain how that can be done (without timeouts or intervals). Some previous answers try to detect when the Facebook pixel <script>
is done loading, but that's not the same as determining when an actual event is done firing. Presumably, OP want's to know when the PageView
event is complete. This solution is not amazing for every use case, but it's pretty simple if we don't have much else happening on the page.
In order to ping their servers and track events, Facebook's code creates a new Image()
and sets its src
attribute to something like https://www.facebook.com/tr/?id=XXXXXX&ev=PageView&{more parameters}
. I discovered this by examining the tracking library and finding this sendGET
function:
this.sendGET = function(b, c, d) {
b.replaceEntry("rqm", "GET");
var f = b.toQueryString();
f = i(c, d) + "?" + f;
if (f.length < 2048) {
var g = new Image();
if (d != null) {
var h = a.getShouldProxy();
g.onerror = function() {
a.setShouldProxy(!0), h || e.sendGET(b, c, d)
}
}
g.src = f;
return !0
}
return !1
};
We can hook into that image load by polyfilling a default Image.onload
callback with our redirect code. The result is something like this, which could be placed immediately above the normal Facebook pixel code in your header:
OriginalImage = Image;
Image = function(){
let oi = new OriginalImage();
oi.onload = function() {
// if the image that loaded was indeed a Facebook pixel
// for a "PageView" event, redirect
if( this.src.indexOf( 'facebook.com/tr/?id=XXXXXX&ev=PageView' ) != -1 )
window.location = 'https://example.com/redirect-here';
};
return oi;
};
So a full "paint the user and redirect" page could look about like this:
<html>
<head>
<!-- Facebook Pixel Code -->
<script>
OriginalImage = Image;
Image = function(){
let oi = new OriginalImage();
oi.onload = function() {
// if the image that loaded was indeed a Facebook pixel
// for a "PageView" event, redirect
if( this.src.indexOf( 'facebook.com/tr/?id=XXXXXX&ev=PageView' ) != -1 )
window.location = 'https://example.com/redirect-here';
};
return oi;
};
!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', 'XXXXXX');
fbq('track', 'PageView');
</script>
<noscript>
<img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=XXXXXX&ev=PageView&noscript=1"/>
</noscript>
<!-- End Facebook Pixel Code -->
</head>
<body></body>
</html>
Of course, you could skip the Javascript and literally just load the image from that <noscript>
block and add an 'onload' attribute, like so:
<html>
<head>
<!-- Facebook Pixel Code -->
<img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=XXXXXX&ev=PageView&noscript=1"
onload="window.location = 'https://example.com/redirect-here';"/>
<!-- End Facebook Pixel Code -->
</head>
<body></body>
</html>
But I would guess that plain image tracking degrades Facebook's ability to identify the user.
This strategy may work for more generic use cases where you want to detect when an arbitrary event is done being sent to Facebook. But it may be unwise to polyfill the onload
callback for every single image on a normal page. Also know that Facebook could change their code at any time, breaking this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With