Google Ads can show a conversion for a Shopify order without explaining where the number came from. Three different pipelines feed the same account, and all three end up as a conversion action with a similar name.
This guide compares them at mechanism level: what fires the conversion, who owns the action, how an order is deduplicated, how consent is honoured, and what each can prove against a Shopify orders export. It picks no winner, quotes no vendor costs — check the Google & YouTube app listing — and does not rank the options.
What does the Google & YouTube app send to Google Ads?
The Google & YouTube app is a Google-developed Shopify sales channel app. It loads Google tags on the store, maps Shopify’s standard events to destinations you choose, and — when you link a Google Ads account — creates a purchase conversion action for you. Google and Shopify maintain the mapping.
You connect the Google account, link a Google Ads account, then review the Shopify events and destinations. With an account linked, purchase, add to cart and checkout started are suggested defaults. Check each action’s primary or secondary setting and the campaign’s bidding goals rather than assuming the non-purchase actions are observation-only. Per event you can create an action, pick an existing one, skip it, or paste a custom AW-CONVERSION_ID/CONVERSION_LABEL or Floodlight destination.
Connecting Google Analytics is separate: the app can also send Shopify events to a GA4 property, and a Google Ads conversion created from a GA4 purchase key event is its own action. Deduplication by transaction ID works within one action, so the two do not merge — two actions counting one order are two conversions.
Deduplication is the overlooked part. Google documents a Data Manager connection where Shopify sends purchase conversions server to server, deduplicated against the Google tag’s events inside the conversion action before attribution. It supports the Checkout completed event only.
The constraints are structural, not bugs. The app supports standard event and tag configuration; Google states that some custom settings and code-based customizations are unavailable, and that in-code privacy or feature settings are not replicated. Google also states that Tag Manager cannot be set up through the app, and that only one Google Ads account can be linked directly — further accounts go in manually by ID and label.
What does a conversion tag you own actually do?
A conversion tag is code you place that fires the conversion with parameters you choose. On Shopify it runs as a custom web pixel that subscribes to Shopify’s customer events and reads the order’s identifier and value from the checkout event. In Tag Manager you build the Ads tag, reference that dynamic transaction_id and add a Conversion Linker.
Shopify loads web pixels in a sandbox on the visitor’s browser, and Google’s position is explicit: running Google tags inside Shopify’s custom pixel feature is not a supported implementation. Data may still flow while features fail, and Google support will not troubleshoot it. What may not work from the pixel sandbox includes Preview mode, many trigger and variable types, enhanced conversions and Consent Mode URL passthrough.
The rule to design around is the transaction ID. Google Ads keeps the first conversion it processes for a given conversion action and transaction ID, and treats a second with the same ID as a duplicate that is not counted. The ID must be dynamic per order, unique, within 64 characters and free of personal data. Reusing a static ID undercounts; an empty ID lacks this deduplication safeguard. An ID that does not match exactly between two paths cannot identify them as the same conversion.
window.dataLayer = window.dataLayer || [];
// Hypothetical order payload; values come from the order, never a fixed amount.
window.dataLayer.push({
event: 'purchase',
transaction_id: order.id, // dynamic, unique per order, no personal data
value: order.total, // dynamic: the order's own value
currency: order.currency // dynamic: the store's currency
});
Instead of owning a tag, you can create the conversion in Google Ads from a Google Analytics key event. That needs linked accounts and auto-tagging, and the gclid must not be altered or dropped by redirects. These conversions start as secondary, and their goal category and action optimization are editable only in Google Ads, not the Analytics interface. Importing from Analytics also does not bring view-through conversions, which need native Google Ads measurement.
Consent is the other thing you own: you configure the default consent state for ad_storage, analytics_storage, ad_user_data and ad_personalization — by default Google sets no consent mode values — and update it after the visitor chooses. Basic mode blocks Google tags until consent; advanced mode loads them and sends cookieless measurements while consent is denied. Enhanced conversions require normalised first-party data hashed with hex SHA-256. (This covers technical implementation, not legal advice.)
What does an offline conversion import measure that the browser cannot?
An offline conversion import records a conversion from an identifier you stored earlier rather than from a request at conversion time. You capture the click identifier on landing, keep it with the order or lead record, and upload the outcome later with its date, time, value and order ID.
The mechanism is documented: auto-tagging must be on, the gclid is appended to the landing URL, and Google recommends capturing it on every page and storing it with the order. It is case sensitive, and a file import keys on it. The conversion action, date and time are required; order ID, value and currency are optional, with value falling back to the number defined on the action. Google documents GBRAID support for imports using external attribution, so check your interface’s identifier support rather than assuming the identifiers are interchangeable.
That is what this path proves that a browser cannot: an outcome off the site — a phone sale or a signed contract — and equally a purchase whose browser signal never arrived, provided the identifier was stored. Without one there is no click to match.
Cadence matters: Google’s current guidance directs file imports through Data Manager and API uploads through the Data Manager API. Classic offline conversion import is a legacy feature. After creating a conversion action, Google says to wait 4–6 hours before the first upload. Google recommends including an extra day of data because conversions within one day of the click may not yet be recorded; processing can take 24–48 hours. Keep new conversions and adjustments in separate files. Repeated identifier, conversion name, date and time are treated as duplicates.
Refunds are handled by conversion adjustments, not a tag — and not only for offline imports: any online conversion recorded with a transaction ID can be restated or retracted, including an app or tag purchase. A RESTATE changes the value and leaves the count; a RETRACT removes the conversion from the count and zeroes its value, and cannot be adjusted again. Adjustments are keyed on the order ID with the conversion action name, or on gclid and conversion time when the conversion had no order ID — with a gbraid, only the order ID works. Google advises uploading adjustments at least 24 hours after the original, gives up to 7 days after a conversion is recorded for autobidding readability (54 days outside it), and recommends uploading every order, because Ads cannot tell which orders came from its clicks, so error rows are expected. Enhanced conversions for leads is Google’s successor, matching hashed user-provided data as well.
Side-by-side
The app is the least work and the least configurable; a tag you own buys parameters, consent control and deduplication at the cost of maintenance; an offline import is the only path that records an outcome that happens off the site. All three answer to the same transaction-ID and consent rules, and none replaces reconciliation against your orders.
Comparison table — scroll horizontally to see all columns
| Criterion | Google & YouTube app | Conversion tag you own (GTM or custom pixel) | Offline conversion import |
|---|---|---|---|
| Event source | Shopify events, mapped by the app | Your subscriptions, tag and triggers | A stored click identifier |
| Purchase and refunds | Purchase mapped for you; refunds need a separate adjustment | Purchase you define; refunds need a separate adjustment | Records off-site outcomes; refunds by adjustment |
| Deduplication | Inside the action, including server-to-server | Your transaction_id, one action | Order ID, or identifier plus time |
| Consent | Shopify pixel privacy API | Your Consent Mode defaults and gating | Obligations travel with the upload |
| Data ownership | Mapping by Google and Shopify; events land in the linked Ads account | Tag, parameters and destination you administer | Capture, storage and upload destination under your control |
| Dependency | App, sales channel, Google’s mapping | Shopify’s sandbox, GTM, your code | Your backend plus the Ads upload |
| Maintenance | Vendor maintains the mapping | You maintain schemas and tests | You maintain capture and schedule |
| Who it suits | Minimal code, standard events | Parameters the app lacks | Off-site outcomes |
Decision table
Choose the app for standard purchase measurement with minimal code, a tag you own when you need a parameter or consent gate the app lacks, and an offline import when the outcome happens off-site or long after the click. Refunds are always a separate adjustment upload, and a reporting mismatch is a reconciliation problem, not a switch.
Comparison table — scroll horizontally to see all columns
| If your situation is … | Choose … |
|---|---|
| You want purchase measurement with no code to maintain | Google & YouTube app |
| You need a value, parameter or consent gate the app lacks | A conversion tag you build |
| The conversion is a lead outside Shopify’s sandbox | GTM tag, or a GA4 key event imported |
| The outcome happens off-site or long after the click | Offline import, or enhanced conversions for leads |
| Refunds must stop inflating reported value | Conversion adjustments, keyed on order ID |
| You run the app and are considering a second tag | Remove one path first, then verify |
| The symptom is Google Ads and Shopify disagreeing | Neither — start from reconciliation |
When not to use each option
The app is wrong when you need configuration it does not expose; the tag is wrong when nobody can maintain it; the import is wrong when no identifier was ever stored.
Do not reach for the Google & YouTube app when:
- You need a refund event, a custom value formula or a parameter the mapping does not carry.
- You need Google tags in Tag Manager on checkout pages, which Google states the app cannot set up and does not support in a custom pixel.
- You want every destination configured in one place: the app links one Google Ads account directly, and extra accounts are added manually by conversion ID and label or Google tag.
Do not reach for a conversion tag you own when:
- Nobody will own it: every Shopify schema change becomes something to notice and fix.
- You rely on Preview mode, Tag Assistant or conversion diagnostics inside the pixel sandbox, where Google documents that some will not work.
- You want Google’s supported configuration on checkout pages.
Do not reach for an offline conversion import when:
- The identifier was never captured or stored before the order; there is nothing to match.
- You want it to replace on-site measurement; it supplements a working tag rather than repairing a broken one.
- Nobody owns the schedule; an import out of cadence drifts from the action it feeds.
How I verify this in real implementations
I verify by counting and by naming the cause of every difference: one order, one conversion per action you intend to count, with a non-empty transaction ID identical on every path.
- List every conversion action that can count a purchase. Read action optimization, the standard goals those actions belong to, and any custom goals. Primary actions bid when their standard goal is bidding; secondary actions still report in All conversions, and an action in a custom goal bids even when secondary.
- Identify every path that sends a purchase. Review Customer events and the app settings in Shopify, and any Ads conversion tag in Tag Manager. One path should own the purchase.
- Trace one live test order end to end. Tag Assistant and GTM Preview where they work, GA4 DebugView for the event and its
transaction_id, conversion diagnostics for the action’s status. Test more than one checkout route. - Check the key against the order. Non-empty, unique to that order, identical wherever it appears.
- Read the settings that shape the number. Counting method, attribution window, value source and primary or secondary status decide what the figure means; Analytics-imported conversions can carry different editable settings.
- Test a refund. Process one, upload the adjustment, and read the upload report to confirm the row matched. A retracted conversion cannot be adjusted again, and a removed website conversion cannot be restored to reports. For offline imports counted as “every conversion”, Google documents re-uploading with a slightly later timestamp. I test on an order I can afford to lose.
- Reconcile a closed period. Compare Ads conversions for a finished window with a Shopify orders export and write down why they differ, alongside order reconciliation.
Common failure modes
Most failures are mundane: two paths running, an empty key, a value defined differently on each side, or an upload out of cadence.
- Two paths, one order. Google’s instructions say to check for duplicate tags and remove legacy ones; two actions in one campaign can count an order twice.
- A transaction ID that differs between paths. Prefixes, suffixes and stray spaces defeat deduplication, and a reused ID across orders undercounts.
- An identifier captured but not stored. A gclid read on landing and never attached to the order leaves nothing to upload later.
- Uploads before the action or data is ready. Wait 4–6 hours after creating a conversion action before the first upload, and include an extra day with each import. Upload adjustments at least 24 hours after the original conversion. Processing can take 24–48 hours; an accepted file does not prove that every row was attributed.
- Sandbox assumptions. Tags expecting Preview mode, a full trigger set or URL passthrough inside a Shopify custom pixel behave differently.
- Consent treated as a bypass. In basic consent mode nothing should reach Google before consent; in advanced mode tags load, then send cookieless measurements while consent is denied. Check the consent state the tags receive, not just a request leaving the browser.
Limitations
All three paths start from the same constraint: there must be an identifier, and it must survive from the click to the recorded outcome.
The app runs both a Google tag on the store and a server-to-server integration for the checkout event; a tag you own is browser-delivered, and the import depends on capture, storage and a schedule you maintain. None of them makes Google Ads agree with Shopify: Ads reports attributed, view-through and modeled conversions inside its own windows and models, while Shopify counts orders from every source, so reconciling the gap is a method rather than a setting. Transaction IDs are not reported in Google Ads, so reconciliation stays aggregate. These are also moving targets — Shopify’s checkout migration and Google’s move to enhanced conversions for leads have changed the documented path.
Alternatives
If the loss you care about is blocked or truncated requests rather than the mapping, the answer is transport — see the server-side tracking guide.
If the purchase event itself is broken, rebuild it with Fix the GA4 purchase event on Shopify, and if consent configuration is the open question, start from Consent Mode v2. For the account side — conversion actions, value definitions and gclid hygiene — see Google Ads conversion tracking, and for outcomes that never touch the site, offline conversion tracking. If the symptom is the mismatch, begin with Google Ads conversions not matching or Shopify checkout tracking broken.