Skip to main content

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.