Ecommerce TrackingTutorialIntermediate

Shopware 6 tracking done properly: an app with signed webhooks, the paid transaction as the purchase, and the storefront snippet

How the Track Shopware app registers itself, which order events map to purchase and refund, how the shopware-shop-signature is verified, why the paid transaction state beats the placed order, and where the snippet goes in the theme.

By
Track editorial team
Published
Last reviewed
Reading time
3 min read

Key takeaways

  • The Track app is a manifest, not a plugin: Shopware sends signed webhooks, nothing from Track runs in the shop, and the API credentials from registration are deliberately discarded.
  • By default the paid transaction state becomes the purchase and the refunded state the refund; shops where placement is the meaningful moment can switch the connection to placed orders.
  • A missing currency falls back to the connection's setting or is reported as a missing field rather than guessed.
  • The storefront snippet in base.html.twig creates the browser purchase whose consent the verified server purchase inherits by order id.

Why an app and not a plugin

A Shopware plugin is PHP that runs inside the shop; an app is a manifest that tells Shopware which URLs to call. For order tracking the app is enough: Shopware sends signed webhooks for the events you subscribe to, and nothing from Track executes in the shop. integrations/shopware/manifest.xml is that manifest.

Registration

On app:install Shopware calls the app's registration URL with shop-id, shop-url and a timestamp, signed in the shopware-app-signature header with the app secret from the manifest. The collector verifies the signature, answers with a proof (HMAC-SHA256 over shop id, shop url and app name) and a shop secret, and Shopware confirms by posting API credentials to the confirmation URL. Track deliberately discards those credentials: the integration only receives webhooks and never calls the shop's API. The same secret you stored in the connection serves as app secret and shop secret, so every later webhook is verified with shopware-shop-signature, the hex HMAC-SHA256 of the raw body.

Which events become which

Shopware eventTrack event
state_enter.order_transaction.state.paidpurchase
state_enter.order_transaction.state.refundedrefund (order total)
checkout.order.placedpurchase only when the connection is set to count placed orders

The default counts the paid transaction, not the placed order. For prepayment and invoice shops an order can sit unpaid for days or never be paid; counting it at placement inflates revenue and teaches ad platforms the wrong thing. Shops where placement is the meaningful moment (payment on delivery, B2B invoicing) switch the connection to placed.

The purchase carries the order id, the order number as transaction id, total and net amounts (tax as their difference), shipping, currency, product line items keyed by product number, and the order customer's e-mail, name and billing city, postcode and country as raw matching data the router hashes. Promotion and shipping line items are not products and are skipped.

Currency

The paid and refunded events carry the order with its currency association in current Shopware versions. If a version omits it, the connection's fallback currency applies; without either, the event is stored without currency and the destination monitor reports the missing field instead of guessing.

The storefront snippet

Add the standard snippet to your theme's base.html.twig in the base_head block. It covers the storefront and the checkout finish page, which Shopware renders itself, so the browser purchase — with the visitor's consent record and click ids — exists alongside the webhook. Pairing by order id then lets the verified server purchase inherit that consent; without a browser purchase the server record stays operational and reaches no advertising destination.

Setup

  1. Site → Shop connection → Shopware 6: shop domain, fallback currency, purchase moment; store a secret (32 random characters); copy the registration URL.
  2. Put the manifest into custom/apps/TrackSite/manifest.xml, replace tracking id, path token and secret, run bin/console app:install --activate TrackSite.
  3. Mark a test order's transaction as paid. The connection reports the registration and the first webhook; the debugger shows the shopware purchase.

Limits

  • A second partial refund on the same order is deduplicated by order id; the first is recorded.
  • Apps cannot inject storefront scripts by themselves; the snippet is a theme change, documented in the README.
  • Orders edited in the admin after payment do not resend the paid event; value corrections happen in your own reporting, not at the vendors.

Primary sources

Documentation and standards this article is based on.

  1. Shopware — App base guidedeveloper.shopware.com
  2. Shopware — Webhooks for appsdeveloper.shopware.com

Was this article helpful?

Responsible editor

Track editorial team

Product & engineering

The people building Track: engineers and analysts who work on server-side tracking, consent tooling and connector integrations every day.