问题
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?
回答1:
I took a stab at this. Given a callback function named myCallback
and your private id named myId
, use this code:
(function wait() {
// check for the generic script
// easiest check to prevent race condition
if (fbq.version > '2.0') {
// now check for the custom script
// `fbq.on` is now ready (`fbq.once` would be better but has a bug)
fbq.on('configLoaded', function (name) {
if (name === myId) {
myCallback();
}
});
} else {
setTimeout(wait, 10);
}
})();
myCallback
will be called once everything is ready. This is accurate as of fbq.version="2.7.17";
Reference https://github.com/poteto/ember-metrics/pull/151
回答2:
You can use below code if you want to trigger specific FB event after successful completion of FB pixel loading, here is the code:
<script>
function drop_fb_pixel() {
try {
//Drop FB Pixel
fbq('track', 'ViewContent', {
content_ids: ['12'],
content_type: 'product'
});
}
catch (err) {
setTimeout(function () { drop_fb_pixel(); }, 3000);
}
}
$(document).ready(function () {
drop_fb_pixel();
});
</script>
The logic is pretty simple, after document load this script will try to trigger FB event, if got error then it will try to trigger event again after 3 sec, you can customize the time of event trigger as per your own application logic
回答3:
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.
回答4:
The answer of @love-chopra is sort of alright, however I think to use the setTimeout()
with 3s delay is not the best solution when we are talking about a webpage. From my POV the solution could be the setInterval()
to check it constantly until the fbevents.js
not loaded.
var fbLoaded = false;
var tryFB = null;
function drop_fb_pixel() {
fbLoaded = true;
try {
fbq('track', 'ViewContent', {
content_ids: ['12'],
content_type: 'product'
});
} catch (err) {
fbLoaded = false;
}
if (fbLoaded) {
clearInterval(tryFB);
}
}
tryFB = setInterval(function () {
drop_fb_pixel();
}, 100);
回答5:
<script>
$(document).ready(function () {
function fbqcheck() {
if(typeof fbq === 'undefined') {
setTimeout(fbqcheck, 5);
} else {
alert('Facebook pixel loaded');
}
}
fbqcheck();
});
</script>
回答6:
I know this is an old post, but how about loading in Facebook Pixel Helper as a Chrome Extension? This tells you immediately if there is a Pixel loading on your website.
来源:https://stackoverflow.com/questions/41755216/wait-for-facebook-pixel-load