Skip to content

Tracking

Conversion tracking for Magento 2 stores on Hyvä, for Meta, Google (GA4 + Google Ads), ChatGPT Ads and TikTok, with every purchase sent from both the browser and the server and deduplicated, consent enforced on both sides, and the value each ad platform bids on computed the way its invoice is: net.

  • Browser and server, deduplicated. Each purchase is sent by the pixel on the success page and by your server (Meta Conversions API, GA4 Measurement Protocol, ChatGPT Ads Conversions API, TikTok Events API), with the same event id. Ad blockers, Safari’s ITP and a closed tab no longer lose the conversion; the platform counts it once.
  • Consent on both sides. Reads the visitor’s choice from Google Consent Mode v2 — so it works with any consent platform that sends it (Cookiebot, CookieYes, Usercentrics, OneTrust, Complianz…) — or from Magento’s Cookie Restriction Mode. Server-side sends obey the same decision as the browser tags. Without consent, nothing leaves the browser for Meta, ChatGPT Ads or TikTok, and GA4 receives only Consent Mode’s cookieless pings.
  • The right value for bidding. Ad platforms usually invoice net of VAT, so by default Meta, Google Ads, ChatGPT Ads and TikTok receive product revenue without shipping and tax, derived from each order’s own totals (no tax rate in code; mixed rates and rate changes are handled). GA4 keeps the gross value with shipping and tax sent separately.
  • Lost sales come back out of GA4. A purchase is reported when the order is placed; when it is later cancelled, refused at delivery, returned or refunded, the module sends GA4 a refund for exactly what was reported — once, and only for sales that were reported. Your revenue in GA4 is what you kept, not what was ordered. See Returns and cancellations.
  • Full funnel: view_item, add_to_wishlist, add_to_cart, begin_checkout, purchase, plus sign_up for new accounts. Add to cart and add to wishlist are captured on the server from what was actually saved (the chosen variant of a configurable product, the bundle, each product of a grouped product), for form posts and AJAX alike, on full-page-cached pages.
  • Brand on every product event, from the attribute you choose — for stores that sell many brands, so GA4 reports and TikTok can break results down by brand.
  • Bundles that match your feed: reported as one product under the bundle’s catalog SKU, or as their components with the bundle price split across them (money conserved).
  • Click ids that survive: fbclid, gclid, ChatGPT’s oppref and TikTok’s ttclid are stored in durable first-party cookies set by your server.
  • Performance: third-party scripts (several hundred KB) load on the first interaction or after a configurable delay, outside the critical rendering window; the success page is never delayed.
  • Google Customer Reviews opt-in on the success page, behind marketing consent.
Magento Open Source / Adobe Commerce 2.4.8 (tested on 2.4.8-p5)
Hyvä Theme 1.3 or newer (tested on 1.5.3)
PHP 8.3 – 8.4 (as required by Magento 2.4.8)
Checkout Magento’s standard checkout page (checkout_index_index), including Hyvä’s; custom checkouts: see Custom checkout below

The storefront templates use Hyvä’s view models and CSP integration; Luma storefronts are not supported. hyva-themes/magento2-theme-module comes from Hyvä’s own Composer repository, which every Hyvä store already has configured. Magento_Wishlist is optional: without it there is simply no add_to_wishlist event.

Add the repository you received with your license to composer.json (once), then:

Terminal window
composer require slova/module-tracking:^1.0
bin/magento module:enable Slova_Tracking
bin/magento setup:upgrade
bin/magento setup:di:compile # production mode
bin/magento cache:flush

setup:upgrade adds three columns to sales_order (the ledger of reported values used for retractions). Nothing is sent anywhere until you enable tracking and switch Send Mode to Live (see Configuration).

Terminal window
composer update slova/module-tracking
bin/magento setup:upgrade
bin/magento setup:di:compile # production mode
bin/magento cache:flush

Read CHANGELOG.md first; settings are kept across versions.

Terminal window
bin/magento module:uninstall Slova_Tracking --remove-data

--remove-data drops the three sales_order columns and deletes the module’s settings (slova_tracking/*, keys included — note them first if you may reinstall). Without it, columns and settings stay, harmlessly.

Stores → Configuration → Slova → Tracking (Meta, Google, ChatGPT & TikTok)

Start in Send Mode = Log only: every server payload is written to var/log/slova_tracking.log and nothing is sent. Switch to Live once the keys are in place.

Setting What to choose
Consent Source Google Consent Mode v2 if your store has a consent platform; Magento Cookie Restriction Mode if you use Magento’s notice; None only where no consent is legally required.
Value Basis for Ad Platforms Products, excluding tax (recommended). If you switch on a live account, recalibrate tROAS targets the same day.
Bundle Reporting Match your product feed: As one product if the feed lists bundles, As its components if it lists only simple products.
Brand Attribute Code The attribute holding the brand (default manufacturer). Sent as item_brand to GA4 and brand to TikTok; Meta and ChatGPT Ads read the brand from your product catalog.
Statuses That Retract the Sale Your statuses for refused delivery or returns (see Returns and cancellations). Cancellation and credit memos are handled without listing them.
Tag Start Delay 3500 ms recommended. 0 = tags start only on interaction.

Pixel ID, and a Conversions API access token from Events Manager → your dataset → Settings → Conversions API. While validating, put the code from Test Events in Test Event Code, and remove it afterwards.

Measurement ID (G-…) and a Measurement Protocol API secret (GA4 Admin → Data Streams → your stream).

Conversion ID (AW-…) and the purchase conversion label. Enhanced conversions are hashed on your server; the plain values never appear in the page.

The Pixel ID is only the code inside ttq.load('…') in TikTok’s base code — do not paste the whole script; the module renders the pixel itself, deferred and behind consent. For the server side, generate an Events API access token in Events Manager → your pixel → Settings → Events API. While validating, put the code from Test Events in Test Event Code, and remove it afterwards.

In Ads Manager → Conversions, create a data source (its Pixel ID) and a Conversions API key (not the Advertiser API key), and a conversion event for Order created (order_created). Validate Only = Yes makes OpenAI check server events without saving them; set it back to No. ChatGPT Ads has no wishlist event: adds to wishlist arrive as a custom event named add_to_wishlist.

Event Meta GA4 / Google Ads ChatGPT Ads TikTok
Product page ViewContent view_item contents_viewed ViewContent
Add to wishlist AddToWishlist add_to_wishlist custom add_to_wishlist AddToWishlist
Add to cart AddToCart add_to_cart items_added AddToCart
Checkout InitiateCheckout begin_checkout checkout_started InitiateCheckout
Purchase (browser + server) Purchase purchase order_created Purchase
Account created CompleteRegistration sign_up registration_completed CompleteRegistration

sign_up fires for every account created on the storefront — Magento’s registration form, login modals, social login, an account created after checkout — whether or not email confirmation is required; accounts created in admin or through the API are not reported. Wishlist and registration events are browser events, sent only with marketing consent (GA4 under Consent Mode).

Merchant Center ID and the upper end of your delivery window in business days. Product GTINs come from GTIN Attribute Code, or from the SKU when it is the GTIN.

The consent source has a browser half and a server half:

  • In the browser it tells the loader whether analytics (GA4) and marketing (Meta, Google Ads, ChatGPT Ads, TikTok) are granted, and reports changes.
  • It mirrors the decision into a first-party cookie, slova_tracking_consent, which the server reads when the order is placed.

With Google Consent Mode v2 the module never sends gtag('consent', …) itself: your consent platform owns those signals. A Consent Mode default scoped to a region is applied only when it denies — the module cannot know the visitor’s region, so it never uses one to grant more than the global default.

Without a consent platform on the page, nothing is granted. Use None only where consent is not required.

The purchase is reported when the order is placed — the only moment the visitor’s browser is there, and the only one that keeps the conversion signal fast. Some of those sales never happen: a card payment is never completed, a cash-on-delivery parcel is refused, goods come back. Left alone, they stay in your reports as revenue.

The module retracts them from GA4 with a server-side refund event:

What happens to the order What is retracted
It is cancelled — from admin, or automatically (unpaid card orders cancelled by cron) everything still reported
It moves to one of your Statuses That Retract the Sale (refused delivery, returned to sender…) everything still reported
A credit memo is created the amount refunded; a partial memo retracts only the refunded items

How it stays correct:

  • Exactly what was reported. The values sent at the sale are stored on the order (three columns on sales_order). The retraction subtracts those, not a new calculation — a tax rate or value-basis change between the sale and the return does not distort it.
  • Once. Retractions accumulate against what was reported: a cancellation followed by a credit memo, or a memo saved twice, never subtracts twice.
  • Only reported sales. An order placed without consent was never reported, so nothing is retracted for it. Retractions run in admin and cron, where there is no visitor and no consent cookie; they are allowed because the order is in the ledger only if consent existed at the sale.
  • Your workflow, your statuses. The module listens to Magento’s own order save and credit memo save, so it works with any order-status module. List your statuses for lost sales in the setting; cancellation and credit memos need no configuration.

What it does not do:

  • Meta, Google Ads, ChatGPT Ads and TikTok are not corrected. Their conversion APIs have no retraction (Google Ads has one only through the Google Ads API, not included). Their ROAS stays gross of returns: to compensate, raise targets by 1 / (1 − your return rate).
  • Orders placed before installation have no ledger entry, so their returns are not retracted.
  • A status written straight to the database (without saving the order) does not trigger anything — deliberate, so bookkeeping corrections are not mistaken for lost sales.
Platform Browser Server Dedup key
Meta Pixel Purchase Conversions API event_id = purchase.<order increment id>
GA4 gtag purchase Measurement Protocol (same client_id and session_id) transaction_id
Google Ads gtag conversion — transaction_id
ChatGPT Ads oaiq order_created Conversions API event_id / id
TikTok ttq Purchase Events API 2.0 event_id

Item ids are SKUs — the chosen variant’s SKU for configurable products. They must match the id in your product feed.

begin_checkout is emitted on the standard checkout page. For a checkout on another route, add the block to that route’s layout handle:

<!-- view/frontend/layout/<your_route>_index_index.xml -->
<referenceContainer name="content">
<block class="Magento\Framework\View\Element\Template"
name="slova.tracking.begin_checkout"
template="Slova_Tracking::event/begin_checkout.phtml">
<arguments>
<argument name="tracking_config" xsi:type="object">Slova\Tracking\ViewModel\Frontend\Config</argument>
<argument name="checkout" xsi:type="object">Slova\Tracking\ViewModel\Frontend\Checkout</argument>
</arguments>
</block>
</referenceContainer>

Purchases need nothing: they are reported from sales_model_service_quote_submit_success and the standard success page.

  • Another consent platform: implement Slova\Tracking\Api\ConsentSourceInterface (server half) with a template defining window.slovaConsentSource (browser half), and register it in your module’s di.xml on Slova\Tracking\Model\Consent\SourcePool (sources). The interface documents the contract.
  • Another ad platform (server side): implement Slova\Tracking\Api\ProviderInterface and add it to Slova\Tracking\Model\TrackingService (providers).
  • Your own bundle split (to share it with invoicing, for example): prefer your class for Slova\Tracking\Api\OrderLineExpanderInterface. It must conserve money.
  • Browser events from your own code: window.slovaTrack(name, data) fans an event out to every enabled browser tag, under consent.
  • Nothing in the page: the browser tags render only with Enable Tracking = Yes, Send Mode = Live and at least one platform enabled. Flush the full-page cache after changing these settings.
  • Server events: look at var/log/slova_tracking.log — each line says sent, failed: <reason> or skipped — no <category> consent.
  • Meta: use Events Manager → Test Events with a Test Event Code. GA4: validate payloads at /debug/mp/collect — /mp/collect answers 204 to anything. ChatGPT Ads: Ads Manager → Conversions shows events from roughly the last 15 minutes.
  • Testing in an automated browser? Meta silently drops events when it detects automation; that is not a broken pixel.
  • Meta, ChatGPT Ads and TikTok have no retraction mechanism: their ROAS stays gross of returns. Google Ads retractions would need the Google Ads API and are not included.
  • A Consent Mode default scoped to a region is used only when it denies (see How consent works); in such setups GA4 may record visits that Meta and ChatGPT Ads do not.
  • Phone numbers typed in local form are converted for most of the EEA, the UK, Switzerland and North America; elsewhere only numbers in international form (+…, 00…) are matched.
  • Product feeds are not generated by this module.

Personal data (email, phone, name) sent to ad platforms is normalized and SHA-256 hashed on your server; address components are sent as the platforms require. Google Customer Reviews sends the customer’s email and order number to Google, only with marketing consent. Mention the platforms you enable in your privacy policy.

Slova — a trade name of Carusel Multimedia SRL. Commercial software: see the license.