Ecommerce
Matomo's ecommerce reports need three things: what a visitor looked at, what is in their cart, and what they eventually bought. All three are server-side hits here, which matters for orders in particular — a purchase confirmed in your database should not depend on a browser still being open.
use MatomoAnalytics\Facades\Matomo;
use MatomoAnalytics\Tracking\EcommerceItem;
// A product (or category-only) view
Matomo::ecommerceView(sku: 'TSHIRT-01', name: 'T-Shirt', category: 'Apparel', price: 29.90);
// The cart changed — send its current contents and grand total
Matomo::ecommerceCartUpdate(grandTotal: 59.80, items: [
new EcommerceItem('TSHIRT-01', 'T-Shirt', 'Apparel', 29.90, quantity: 2),
]);
// A completed order
Matomo::ecommerceOrder(
orderId: 'ORDER-1001',
grandTotal: 59.80,
items: [new EcommerceItem('TSHIRT-01', 'T-Shirt', 'Apparel', 29.90, quantity: 2)],
subTotal: 50.00, tax: 9.80, shipping: 0.00, discount: 0.00,
);
Product views
ecommerceView() records that a visitor looked at a product. Every argument is
optional, so it also covers the category-only case — a listing page with no single
product on it:
Matomo::ecommerceView(category: 'Apparel');
It also accepts title and url to override what the hit reports as the page,
which is useful when you call it from somewhere other than the product page itself.
Cart updates
ecommerceCartUpdate() sends the cart's current state, not a delta. Pass the
grand total and every item still in the cart. Matomo replaces its picture of the
cart with what you send, which is what makes abandoned-cart reporting work: the last
cart update before a visit ends is the abandoned cart.
Send one on every change — add, remove, quantity change. Sending none until checkout means Matomo sees no cart at all for a visitor who leaves.
Orders
ecommerceOrder() requires an orderId and a grandTotal; items, subTotal,
tax, shipping and discount are optional. The order id is the identifier Matomo
files the order under, so pass your real order identifier rather than a generated
one — that is what lets you reconcile a Matomo report against your own records.
Call it where the order becomes real in your own system. If that is a queued job or a payment webhook, it works there: server-side tracking has no dependency on a request from the visitor's browser.
Items
EcommerceItem is a plain value object:
new EcommerceItem(
sku: 'TSHIRT-01',
name: 'T-Shirt',
category: 'Apparel',
price: 29.90,
quantity: 2,
);
sku is required; the rest have defaults, and quantity defaults to 1. Items are
serialized to Matomo's positional item shape — SKU, name, category, price, quantity
— and the parameter names and their wire encoding follow Matomo's own PHP tracker,
so the reports populate the same way they would with Matomo's client.
What applies to all of them
Every ecommerce hit passes through the tracking gate and the fail-safe delivery path like any other hit. A Matomo outage cannot fail a checkout, and a bot browsing your catalog does not appear in the ecommerce funnel.
For assertions in tests, Matomo::fake() records ecommerce hits like every other
type — see testing.