How IsPixelWorking checks your tracking
IsPixelWorking loads your page in a real browser, watches what your ad tracking sends, and turns that into a report. This page explains exactly what we do, what we do not do, and where the limits are. If something in a report surprises you, this is the place to understand why.
The short version
- We open the URL you give us in a headless Chrome browser running in the EU, twice, in two different ways. Monitoring plans add a third visit on a phone.
- We record every request your page tries to send to ad platforms, but we stop those requests before they leave the browser, so your ad accounts do not receive test data.
- We never fill in or submit forms, and we never click buy, cart or checkout buttons.
- We report what we observed, and what we could not see.
The browser runs
The free check is two separate visits, A and B, each in a fresh browser with no cookies from the other. Both start at the same time, so a whole check usually takes under a minute. Monitoring plans add run C, on a phone.
Run A: first visit, no interaction (desktop). We load the page on a desktop-sized screen and wait until it settles (up to about 8 seconds). We do not touch anything. This shows what your tracking does before a visitor has answered the cookie banner. It is the basis for "fires before consent" findings. We also take a screenshot.
Run B: arriving from an ad, consent accepted, then button clicks (desktop). We load the page again with test click IDs added to the URL, exactly as an ad click would add them:
fbclid=TRACKCHECK_TEST_FBCLID(Meta)ttclid=TRACKCHECK_TEST_TTCLID(TikTok)gclid=TRACKCHECK_TEST_GCLID(Google)
We find the cookie banner and click its "accept all" button, then wait a few seconds. This shows what your tracking does once a visitor has agreed. We then check whether your site stored the click IDs in its cookies (for Meta: whether the _fbc cookie contains our test value). Finally we look for call-to-action buttons (such as "Contact us", "Book a call", "Get started") and click up to six of them, recording which tracking events each click sends. If a button opens another page of your site, we also check that the click ID survived the navigation.
Run C: on a phone (monitoring plans). Monitoring plans add a third visit on a phone-sized screen with a mobile browser identity and touch input, also arriving with test click IDs. We accept the cookie banner, check the click IDs, follow one internal link and click up to four buttons on the mobile layout. Because most ad traffic is mobile, we compare which buttons send events on mobile and on desktop, and whether the mobile cookie banner works. In the free check, these mobile checkpoints are shown as "included in monitoring plans".
The test values are obviously fake. Since we stop all requests to ad platforms (see below), they never reach your ad accounts.
We stop tracking data from reaching ad platforms
Checking your tracking should not pollute your ad data. So in every run:
- Every request that carries tracking data to a known ad or analytics endpoint (for example Meta's
facebook.com/tr, TikTok's and Google's event endpoints) is recorded and then answered by us with an empty "OK" response. Your page thinks the request succeeded, so it does not retry another way, but nothing is delivered to the platform. - Tracking libraries still load. We let the official tracking scripts load (such as Meta's
fbevents.js, Google Tag Manager and gtag, and the TikTok pixel script), because otherwise there would be nothing to check. Everything else on ad-platform domains, including ad tags, is stopped. - Tracking through your own domain. Some sites send events to their own domain first and forward them from their server (server-side tagging, Conversions API tools). We recognize known forwarding endpoints, and we look inside requests to your own domain for the typical contents of a tracking event. Matching requests are stopped too, and reported as "tracking through the site's own domain". This recognition is a heuristic: it can miss unusual setups, and we label it as such.
- A second safety net in the browser. Some tracking requests go through redirects (one address bouncing to another). We watch for these at the browser level as well, so the later hops are stopped too.
Known limitations of this protection:
- Browsers sometimes open a secure (TLS) connection to a server in advance, before any request is made. We cannot always prevent that early handshake. No event data is sent over it.
- If your site forwards events from its own server to an ad platform in a way we do not recognize, we cannot see or stop that server-to-server traffic. We do our best to recognize forwarding endpoints, and we stop clicking buttons when we see something that looks like an unrecognized event (see below).
What we never do
- We never type into fields, fill in forms or submit forms. We only note that forms exist.
- We never click buttons that look like buy, add to cart, checkout, payment or subscribe, in any of the languages we support. We note that they exist and report "Purchase events were not tested".
- We never click buttons that look destructive (log out, delete, confirm order).
- While we click buttons, every request your site sends to its own domain that is not a simple page or file load (for example a form-style POST) is answered by us and not delivered to your server.
- If, after a click, we see a request that looks like a tracking event and that we could not stop, we stop clicking for the rest of that run and report "Button testing stopped early".
- Clicks that would take us to another website are blocked. Phone, email and WhatsApp links are clicked with navigation blocked, only to see whether a tracking event fires.
Button clicks are observations, not verdicts
The report shows which events fired when we clicked each button, for example "Contact us → Lead" or "+48 600… → nothing". We do not grade this. We do not know which actions you count as a conversion, and real conversions usually happen after a form is submitted, which we never do.
Verifying that your leads and sales actually reach Meta needs data from your ad account. That is coming next.
How we handle cookie banners
We recognize the cookie consent tools below and click their "accept all" button directly:
| Consent tool | ||
|---|---|---|
| Cookiebot | OneTrust | Usercentrics |
| CookieYes | Complianz | Iubenda |
| Didomi | Termly | Osano |
| TrustArc | Axeptio | consentmanager.net |
| Sourcepoint | Quantcast Choice / InMobi Choice | CookieFirst |
| Borlabs Cookie | Klaro | Cookie Script |
| Shopify customer privacy banner | Consentmo (Shopify app) | Framer cookie banner |
| Finsweet Cookie Consent / Consent Pro (Webflow) | Squarespace cookie banner | Wix cookie banner |
| Google Funding Choices (Privacy & messaging) | Cookie Information | FastCMP |
| Ketch |
If your banner is not on this list, we look for a cookie notice on the page and for a button whose text clearly means "accept" (in several languages), and click it.
If we find a banner but cannot operate it, we say so ("Cookie banner could not be operated automatically") and skip the checks that depend on consent instead of guessing. This can happen separately on desktop and mobile. We also never report "does not fire after consent" as critical unless we actually managed to accept your banner.
Where the browser runs
The browser runs on Cloudflare's network in the EU. The exact country can vary from check to check, and every report shows the country the check ran from. If the browser does not end up in the EU, we retry or fail the check rather than run it from elsewhere.
We run from the EU on purpose: many sites only show a cookie banner, or only hold back tracking, for EU visitors. A visitor in another country may see different behaviour.
The browser identifies itself honestly as an automated checker (its User-Agent includes IsPixelWorking/0.1). See our bot page for details and how to opt out.
How findings are scored
Each finding has a severity. The score starts at 100 and each finding subtracts points according to its severity. Any critical finding caps the grade, and the score with it.
When there is no grade. A grade says "we watched this tracking work, and this is how well it works". We only give one when we actually saw enough:
- No Meta Pixel on the page. There is nothing to grade. Whether that is a problem depends on whether you run Meta ads to this page.
- The visit after consent did not finish (the page was too slow or crashed), so we never saw what the pixel does after a visitor agrees.
- The cookie banner could not be answered, so after-consent behaviour is unknown.
- The site blocked our browser.
In these cases the report still lists everything we did observe, marked as a partial check. If the visit was only cut short during button clicks, we grade it and say that button coverage was partial.
The score is not a share of conversions kept or lost. It ranks how serious the problems we saw are.
| Severity | Points off |
|---|---|
| critical | 35 |
| high | 15 |
| medium | 7 |
| low | 2 |
| info | 0 |
Every check starts at 100. Grades: A ≥ 90, B ≥ 75, C ≥ 60, D ≥ 40, F ≥ 0. Any critical finding caps the grade at D, and the score at the top of that range. Checks without enough coverage get no grade (see below).
What we check
| Finding | Severity | What it means |
|---|---|---|
No Meta Pixel found (meta.pixel_missing) |
info | We did not see a Meta Pixel on this page. If you run Meta ads to it, Meta cannot attribute conversions or optimize delivery for this page. |
Meta Pixel fires before cookie consent (meta.fires_before_consent) |
critical | The pixel sent data while the cookie banner was still waiting for an answer. For EU visitors this is a likely privacy problem (we report behaviour, not legal compliance), and it often means the consent setup is not wired to your tags at all. |
Meta Pixel does not fire after consent (meta.not_firing_after_consent) |
critical | The pixel script is on the page, but no events were sent after cookies were accepted. Meta receives nothing from this page, so ads optimize blind and conversions go unreported. |
Duplicate Meta events (meta.duplicate_pixel) |
high | The same event was sent twice for the same pixel within a second, usually because the pixel is installed twice (for example in site code and in Google Tag Manager). Duplicates inflate reported results and confuse Meta's optimization. |
Meta events have no event ID (meta.missing_event_id) |
high | Without an event ID, Meta cannot match browser events with server (Conversions API) events, so the same conversion may be counted twice or dropped. |
TikTok events have no event ID (tiktok.missing_event_id) |
high | Without an event ID, TikTok cannot match browser pixel events with server (Events API) events, so the same conversion may be counted twice and campaigns optimize on inflated numbers. |
Click ID from Meta ads is not stored (meta.fbc_not_set) |
high | When a visitor arrives from a Meta ad, the fbclid in the link should be saved in the _fbc cookie. Without it, Meta loses the link between the ad click and the conversion, which lowers match quality and reported results. |
Mobile buttons are tracked differently from desktop (meta.mobile_cta_tracking_mismatch) |
medium | A button that sends an event on desktop does not send it on mobile (or the other way round). Most Meta ad traffic is mobile, so conversions may be missing where they matter most. |
Click ID saved by your site code in a non-standard format (meta.custom_fbc_format) |
medium | Your site stores the Meta click ID in its own cookie, but not in the format Meta expects (fb.1. |
Two different browser IDs (_fbp) (meta.conflicting_fbp) |
medium | Two _fbp cookies with different values exist. The pixel and your server code may send different browser IDs for the same visitor, which weakens matching between browser and server events. |
More than one Meta Pixel (meta.multiple_pixels) |
low | Several different pixel IDs are active. This is fine if intended (e.g. agency and client), otherwise data is split. |
No advanced matching (meta.no_advanced_matching) |
low | Events carry no hashed customer data, which lowers Meta's event match quality. |
No server-side tracking detected (general.server_side_not_detected) |
info | We saw no sign of server-side tracking (Conversions API, server-side GTM). Server-to-server traffic is invisible from a browser, so this is not proof it is absent. |
Server-side tracking detected (general.server_side_detected) |
info | We saw signs of server-side tracking. We cannot see server-to-server traffic, so we cannot tell whether it works. |
The site blocked our checker (general.blocked_by_site) |
n/a | The site refused automated access, so we could not check it and show no grade. |
Cookie banner could not be operated automatically (general.cmp_not_operable) |
info | We found a cookie banner but could not accept it automatically, so checks that depend on consent were skipped rather than guessed. |
Purchase events were not tested (general.purchase_events_not_tested) |
info | We found buy or add-to-cart buttons but never click them on sites that have not been verified, to avoid creating carts or fake conversions. |
Button testing stopped early (general.cta_coverage_partial) |
info | After a click we saw a request that looked like a tracking event sent to the site's own server. To avoid feeding test events into ad accounts, we stopped clicking. |
Tracking through the site's own domain (general.first_party_tracking_detected) |
info | Requests to the site's own domain looked like tracking events (heuristic). This usually means server-side tagging. |
Some findings are marked as possible. These come from heuristics (for example, matching buttons between desktop and mobile by their text) and are more likely to be wrong than the others.
Server-side tracking
Server-to-server traffic (for example the Meta Conversions API sending events from your server) is invisible from a browser. We look for signs of server-side tracking, such as known Conversions API tools, server-side Google Tag Manager, tracking requests to your own domain, or ad click IDs that your site code saves in its own cookies (for Meta and TikTok), and report "detected" or "not detected". We never say that your Conversions API works or is broken: we cannot see it. When we see such signs, missing event IDs on Meta or TikTok events count as high severity, because without them the platform cannot deduplicate browser and server events.
Known limitations
- Location. We check from one EU country at one moment. Behaviour can differ by country (cookie banners, geo-redirects, prices, content).
- Automated browser. We use a full Chrome browser in headless mode. It openly identifies as automated, and a few things differ from a normal visitor's browser (for example, some background browser features are turned off so we can reliably stop tracking requests). Some sites or scripts behave differently for automated browsers.
- A/B tests and personalization. If your site shows different versions to different visitors, we see one of them per run, and the runs may see different versions.
- Bot protection. Some sites block automated browsers. When that happens we report "The site blocked our checker" and show no grade rather than a misleading one.
- Server-side tracking is invisible to us, as explained above.
- One page. We check the URL you give us (plus pages that buttons lead to on the same site, and on monitoring plans at most one internal link on mobile), not your whole website.
- Timing. We wait a fixed time after loading and after each click. Tracking that only fires much later (for example after scrolling or a long delay) may not be seen.
- Point in time. Websites, tags and consent tools change. A report describes what we saw when the check ran.
What we do not do
- We do not give legal advice. A finding like "fires before consent" describes technical behaviour, not whether your site complies with GDPR or any other law.
- We do not issue compliance certificates, and a good grade is not one.
- We do not install tracking or send events to ad platforms for you. We check; we do not replace your tracking tools.
- Our findings and grade never depend on which tracking tool or agency you use. When a fix option mentions a tool or service built by our own team, we say so.