You installed the Google Ads conversion snippet. Nothing fired. You tried Google Tag Manager instead. Still nothing. You checked Meta Events Manager and the numbers there don’t match what’s actually in your Odoo sales orders — and you can’t tell whether you’re seeing too few conversions or too many.
If you searched “odoo conversion tracking not working,” you are not doing it wrong, and you are not alone.
Odoo conversion tracking fails for a structural reason: the data that ad platforms need is split across three places that don’t naturally talk to each other — the Odoo database (where the sales order lives), the browser session (where the visitor’s identity and consent live), and the frontend JavaScript (where the click events happen). Standard tracking scripts only see the third one. That’s why pasting a snippet into your Odoo website settings doesn’t reliably produce accurate conversions.
This article explains how to tell which failure mode you actually have. It doesn’t sell you a module — a companion piece covers how the fix is architected once you know what you’re fixing.
Odoo conversion tracking not working: is it Odoo’s fault, or did I set it up wrong?
This is the real question behind the search, so let’s answer it directly: it’s mostly Odoo’s architecture, and partly the wider collapse of browser-based tracking. In the implementations we’ve audited, misconfiguration is rarely the whole story — though it’s worth ruling out the simple causes first, and we’ll show you how below.
Two things are true at once:
Odoo’s native tracking is limited by design. Odoo supports Google Analytics 4 out of the box. By the account of the vendors who build tracking modules for Odoo, what it emits natively is a set of basic ecommerce events — page view, view item, add to cart, begin checkout, purchase — carrying minimal product detail and nothing meaningful about the visitor. Those vendors sell the solution to the limitation they’re describing, so weigh it accordingly; the practical point is that it takes about ten minutes to check against your own GA4 property, and we’d suggest you do. For GA4 reporting, what’s there may be adequate. For Google Ads and Meta conversion optimization, which need identity matching and verified transaction values, it isn’t.
One genuine configuration gotcha worth eliminating immediately: Odoo doesn’t run website tracking scripts for logged-in internal users. This is documented in the setup instructions for the main third-party Odoo tracking modules, which all advise logging out or switching browsers before testing. If you’ve been checking your own tracking while signed into Odoo as an internal user, you’d see nothing fire regardless of whether the setup is correct. Log out, or test in a private window, before concluding anything is broken.
Browser-based tracking is failing everywhere, not just in Odoo. Ad blockers, Safari’s privacy restrictions, and consent requirements have made client-side pixels unreliable across every platform. Odoo is harder than most because of the data-split problem, but a Shopify merchant running pixel-only tracking has a version of the same issue.
You can see how common this is on Odoo’s own community forum. Three threads asking essentially this question — Google Ads Conversion Tracking (9,749 views), Meta ads and google ads tracking conversion not working (4,384 views), and a related thread on Google Ads in Odoo (14,717 views) — have accumulated roughly 29,000 combined views, and between them, seven replies. The second of those was opened by someone who had already read the first, reporting the problem persisting across both Google and Meta. The imbalance between how many people have this problem and how few answers exist is the reason this article exists.
The two ways Odoo conversion tracking fails
Almost every broken-tracking situation is one of these two, or both at once. They have opposite symptoms and opposite fixes, so identifying yours is the first useful step.
Failure mode 1: Under-reporting — real sales that never get counted
Your ad platform shows fewer conversions than your Odoo sales orders. Campaigns look unprofitable when they aren’t. Automated bidding optimizes against incomplete data and gets progressively worse.
Ad blockers and browser privacy protections stop the script before it runs. If the tracking script never loads, no event fires. Nothing about your Odoo configuration can prevent this, because the failure happens on the visitor’s machine before your code executes.
The customer closes the tab before the confirmation page finishes loading. Browser-side purchase events fire on page load. If the page never fully loads, the sale happened and the event didn’t.
Attribution decays before the purchase happens. Safari’s Intelligent Tracking Prevention restricts cookies created by JavaScript — via document.cookie — to a lifespan tied to roughly seven days of visitor inactivity on your site. Cookies set server-side, in an HTTP response header, are not subject to that restriction. Where a visitor arrives from a referrer WebKit classifies as a tracker with query parameters attached, the window shrinks to as little as one day.
Sources: WebKit ITP 2.1 introduced the seven-day cap; Full Third-Party Cookie Blocking changed it from a flat seven days to seven days of inactivity; ITP 2.2 covers the one-day case.
That distinction — JavaScript-set cookies get purged, server-set cookies don’t — is the clearest preview of why the fix has to be architectural.
Failure mode 2: Over-reporting — conversions that never happened
Your ad platform shows more conversions than you have sales orders. Reported ROAS looks great. You scale spend against numbers that aren’t real.
Page refreshes double-count. A customer reloads the confirmation page to check their order. The browser script fires again. That’s two purchases from one sale.
Back-button navigation re-triggers events. The customer navigates back to the confirmation page from their email. Another purchase event.
Failed payments get counted as sales. A browser script fires when the page loads. It has no way of knowing whether the payment later declined, or whether the order was cancelled in Odoo an hour afterwards. The ad platform recorded revenue. Your accounts never will. Of the over-reporting causes, this is the one we see cause the most damage, because it inflates exactly the campaigns you’re most likely to scale.
Pixel and server events both fire without deduplication. If you’ve partially implemented server-side tracking alongside a browser pixel, Meta will count the same purchase twice unless both signals carry a matching identifier. Meta’s Conversions API documentation is specific about this: the browser Pixel and the server payload must carry a matching event ID and the same event_name for Meta to recognize them as one event. Where both arrive matched, Meta keeps one.
How to tell which one you have
You don’t need new tooling for this. You need one comparison, run over a fixed window.
- Pick a clean date range — a full week, at least a few weeks in the past so attribution windows have closed.
- Count confirmed sales orders in Odoo for that range. Filter to orders that actually reached a paid or confirmed state. This is your ground truth, because it’s the number your bank agrees with.
- Count reported conversions in Google Ads and in Meta Events Manager for the same range.
- Compare.
| What you see | Likely failure mode | Where to look first |
|---|---|---|
| Platforms show materially fewer than Odoo | Under-reporting | Ad blockers, Safari/iOS traffic share, attribution window vs. your sales cycle |
| Platforms show materially more than Odoo | Over-reporting | Confirmation page refreshes, declined payments still counted, pixel firing on page load |
| Google roughly matches, Meta doesn’t (or vice versa) | Platform-specific config | Deduplication setup, consent handling differences between platforms |
| Both platforms are wildly off in both directions across different weeks | Both modes at once | Usually means no server-side verification anywhere in the stack |
| Numbers match closely | Tracking is probably fine | Investigate campaign performance, not measurement |
A caution on interpretation: some divergence is normal and always will be. Ad platforms use modelled conversions and different attribution windows than your accounting does. You are looking for a persistent, material gap in a consistent direction — not perfect agreement, which you will never get.
Be careful with the statistics you’ll find on this
Searching this topic surfaces a widely-repeated claim that ad platforms capture only 40–60% of iOS conversions. We went looking for the source of that number and couldn’t find one. It appears near-verbatim across several marketing blogs, none of which cite a study, a platform disclosure, or an attribution vendor’s data. Nor do the major attribution vendors — AppsFlyer, Adjust, Singular — publish a figure like it. Treat it as marketing, not measurement.
What is attributable is narrower and less dramatic. Meta stated in 2022 that it had reduced iOS web conversion under-reporting from around 15% to around 8% after improving its modelling, as reported by AdExchanger and The Drum. That’s Meta’s own account of its own gap, which is worth what it’s worth — but at least it has a name attached.
The honest position: iOS and Safari restrictions do cause real under-reporting, the size varies substantially by advertiser and traffic mix, and the only number that means anything for your business is the one you get from comparing your own platform reports against your own Odoo sales orders. That’s why the comparison above matters more than any industry benchmark.
What about consent? Doesn’t that make this worse?
It complicates it, but not in the way most people assume.
Odoo’s native website cookie bar does support Google Consent Mode v2 — that’s stated in Odoo’s own documentation, and it blocks Google and other third-party tracking scripts until a visitor consents. So the common assumption that Odoo has no consent handling is wrong.
The subtler issue is evidentiary. GDPR’s accountability principle places the burden on you to demonstrate that a specific visitor consented, to what, and when (GDPR Recital 42; the UK ICO’s cookies guidance recommends retaining records of who consented, when, and to what). Odoo’s documentation doesn’t describe a built-in feature for storing timestamped, per-visitor consent records. We want to be careful here: that’s an absence in the documentation rather than an independently audited finding, and the parties most loudly pointing it out are companies selling consent management platforms. But if you’re operating under GDPR, it’s worth confirming you could actually produce that evidence if a regulator asked.
There’s also a design question underneath this that nobody in the Odoo space seems to discuss: consent enforced in the browser can be bypassed; consent enforced in your database cannot. If your consent logic lives entirely in front-end scripts, someone with browser dev tools can circumvent it. If the check happens server-side before any API call is made, it can’t be. That distinction becomes relevant as soon as you move to server-side tracking, which is the subject of the next piece.
What actually fixes this
Short version: stop asking the browser to report your revenue.
The browser is a reasonable place to track engagement — product views, searches, add-to-cart. It’s a bad place to track money, because it can be blocked, closed, refreshed, and it has no idea whether a payment succeeded.
Your Odoo database knows all of those things. It knows the order is real, knows the payment cleared, knows the exact value, and knows if the order was later cancelled. Reporting conversions from Odoo rather than from the visitor’s browser removes the entire class of failures described above.
That’s a hybrid architecture: browser tracking for engagement signals, server-side transmission from Odoo for transactions, with deduplication so the platforms don’t count both. It’s more involved than pasting a snippet, and it’s the only approach that produces numbers you can actually spend against.
You don’t have to be technical to evaluate this
The most common reason this problem goes unfixed isn’t cost. It’s that the person who owns the ad budget doesn’t feel qualified to judge whether a developer or agency actually knows what they’re doing — so the conversation stalls.
You don’t need to write the code to assess the answer. Four questions separate someone who has built this from someone who hasn’t:
- “When exactly does the conversion get sent?” You want to hear that it fires when the sales order reaches a confirmed or paid state — not on a timer that batches events every 30 minutes or overnight. Batched sending is common and it costs you attribution accuracy.
- “How do you stop double-counting between the pixel and the server?” The answer should mention a shared event ID passed on both signals. If deduplication doesn’t come up unprompted, they haven’t thought it through.
- “What happens when the message to Google or Meta fails to send?” There should be an automatic retry, a limit on how many times it retries, and an alert to a human when it gives up. “It gets logged” is not sufficient — a log nobody reads means silent failure, and silent failure means permanently lost attribution.
- “Where is cookie consent actually enforced?” If the answer is entirely front-end, it can be bypassed. Enforcement before the API call, on the server, is the defensible version.
Anyone who answers those four clearly can probably do the work. Anyone who deflects on more than one probably can’t.
Read next: Server-Side Conversion Tracking for Odoo: How the Architecture Actually Works — a full walkthrough of the hybrid design, including identifier capture, deduplication, consent enforcement, and failure recovery. It’s the long-form answer to all four questions above.
Frequently asked questions
Why doesn’t the Google Ads conversion snippet work on my Odoo site?
Because the snippet fires on page load in the browser, and the data it needs — verified order value, customer identity, payment status — lives in the Odoo database, not on the page. It also fires regardless of whether the payment succeeded. Adding the snippet correctly still produces unreliable conversions.
Is my Odoo tracking broken, or is my configuration wrong?
Usually neither exactly. Native Odoo tracking works as designed, but it’s designed for basic GA4 analytics rather than ad platform conversion optimization. First rule out the common gotcha — Odoo tracking scripts don’t run for logged-in internal users, which the major tracking modules’ own setup guides all warn about, so test while logged out. If the gap persists, compare your Odoo confirmed sales orders against platform-reported conversions for a fixed period. A persistent gap in either direction points to architecture, not configuration.
Why does Meta show more purchases than I actually had?
Most commonly: confirmation page refreshes re-firing the pixel, purchase events firing before payment confirmation so declined transactions get counted, or a pixel and a server-side integration both reporting the same event without a matching event ID to deduplicate them.
Does Odoo support Google Consent Mode v2?
Yes. Odoo’s native cookie bar supports Consent Mode v2 and blocks third-party tracking scripts until the visitor consents, per Odoo’s own documentation. Whether that alone meets your full GDPR obligations — particularly around demonstrating that a specific visitor consented — is a separate question worth confirming.
Will a paid Odoo tracking module fix this?
Sometimes. Modules can be a good fit for standard web-checkout tracking, and some are well built. They’re less likely to cover orders created manually by staff, immediate transmission on order confirmation rather than batched sending, or automated retry when an API call fails. Whether you need a module or a custom implementation depends on which of those matter to your business.
