A neutral, versioned in-browser contract for partner web tracking
Alongside the REST API, every Eshop-rychle store publishes a neutral frontend dataLayer —
structured data and events available directly in the visitor's browser. You connect a small JavaScript
loader (deployed as a measuring code through the API), read the data and map it to your own
tracking format. It covers visitor activity, cart contents, customer identification and completed orders.
The data lives in its own global, window.eshopDataLayer, so the contract stays stable and is
versioned through the version field.
window.eshopDataLayer.eshop and fires the EshopDataLayerUpdated event on
document.window.eshopDataLayer array and the snapshot is refreshed.window.eshopDataLayer.eshopwindow.getEshopDataLayer(key) (or without an argument for the whole snapshot)EshopDataLayerUpdated event on document (e.detail is the snapshot)
Events are published as entries in the window.eshopDataLayer array. An event is only a
signal — read the details from the snapshot. Some events (pageVisit,
loggedUser, categoryView, productView, orderSubmitted,
the initial cookieConsent) are queued
at page load, before your loader runs, so iterate the existing array first and then wrap
push to catch later ones — the loader skeleton below does both.
| Event | When | Payload |
|---|---|---|
cookieConsent | Initial load and on every consent change | { event, cookieConsent: { marketing, analytics } } |
pageVisit | Every page load | { event, pageType } |
loggedUser | Page load for a signed-in customer | { event, customer } |
categoryView | Category / listing page load | { event, category } |
productView | Product detail page load | { event, product } |
cartUpdated | Item added / removed / quantity changed | { event, action: 'add' | 'remove' | 'update', cart, product } |
orderSubmitted | Thank-you page (completed order) | { event, order } |
Fields marked PII are present only with granted consent (see below). The order block is present on the thank-you page only, category on category pages and product on product detail pages.
Note on types: prices, totals, orderNumber and all product ids are strings; orderId and quantities are numbers.
window.eshopDataLayer.eshop = {
version: "1.0",
pageType: "homepage" | "category" | "productDetail" | "cart" | "checkout" | "thankYou",
currency: "CZK", // ISO currency code
language: "cs", // cs | sk
cart: {
items: [{ id, name, price /* excl. VAT */, priceWithVat, quantity, variant, category, brand }],
totalWithVat, totalWithoutVat, coupon
},
customer: { isLoggedIn, group, registered, city, countryCode, email*, name* },
category: { // category / listing pages only
name, path: [/* breadcrumb category names */],
products: [{ id, name, price /* excl. VAT */, position }]
},
product: { // product detail pages only
id, name, price /* excl. VAT */, priceWithVat, currency,
availability: "InStock" | "BackOrder" | "OutOfStock",
description, brand, imageUrl, category, variant
},
order: { // thankYou only
orderId, orderNumber, priceWithVat, priceWithoutVat, tax, shipping, coupon, currency,
items: [{ id, name, price /* excl. VAT */, quantity, category, brand }],
customer: { group, registered, city, countryCode, email*, name*, street*, zip* }
},
cookieConsent: { marketing: "granted" | "denied", analytics: "granted" | "denied" }
}
// * PII — present in the snapshot only with granted marketing/analytics consent| Value | Page |
|---|---|
homepage | Store homepage |
category | Category / product listing |
productDetail | Product detail |
cart | Cart |
checkout | Checkout steps |
thankYou | Order confirmation — carries the order block |
| Field | Type | Description |
|---|---|---|
items[].id | string | Product id |
items[].name | string | Product name |
items[].price | string | Unit price excl. VAT |
items[].priceWithVat | string | Unit price incl. VAT |
items[].quantity | number | Quantity in the cart |
items[].variant | string | null | Selected variant label |
items[].category | string | null | Product category |
items[].brand | string | null | Product brand |
totalWithVat | string | Cart total incl. VAT |
totalWithoutVat | string | Cart total excl. VAT |
coupon | string | Applied coupon code ("" if none) |
| Field | Type | Description |
|---|---|---|
isLoggedIn | boolean | Whether a customer is signed in |
group | string | null | Customer pricing / loyalty group |
registered | boolean | Whether the customer has an account |
city | string | null | Customer city |
countryCode | string | null | ISO country code |
email PII | string | null | Only with granted consent |
name PII | string | null | Only with granted consent |
| Field | Type | Description |
|---|---|---|
name | string | null | Viewed category name (last breadcrumb node) |
path | string[] | Breadcrumb category names, root first |
products[].id | string | Product id |
products[].name | string | null | Product name |
products[].price | string | Unit price excl. VAT |
products[].position | number | 1-based position in the listing |
| Field | Type | Description |
|---|---|---|
id | string | Product id |
name | string | Product name |
price | string | Unit price excl. VAT |
priceWithVat | string | Unit price incl. VAT |
currency | string | ISO currency code |
availability | string | InStock | BackOrder | OutOfStock |
description | string | null | Short plain-text description |
brand | string | null | Product brand |
imageUrl | string | null | Absolute URL of the main product image |
category | string | null | Product category |
variant | string | null | Selected variant label |
product field
On add and remove the cartUpdated event carries a product
object for the specific item changed: { id, name, price /* excl. VAT */, quantity, variant, category, brand }.
On a quantity update there is no single changed item, so product is null.
The full cart is always in cart.
| Field | Type | Description |
|---|---|---|
orderId | number | Internal order id |
orderNumber | string | Human-readable order number |
priceWithVat / priceWithoutVat | string | Order total incl. / excl. VAT |
tax | string | VAT amount |
shipping | string | Shipping price |
coupon | string | Applied coupon code ("" if none) |
currency | string | ISO currency code |
items[] | array | Line items: id, name, price (excl. VAT), quantity, category, brand |
customer | object | group, registered, city, countryCode, and PII email, name, street, zip |
Your loader is always injected into the page; the store owner does not gate it with their consent settings. Respecting consent is therefore your responsibility:
cookieConsent.marketing (or analytics) is granted.cookieConsent event when the visitor changes their choice.email, name, street, zip) appear only with granted consent.function consentGranted() {
var c = window.getEshopDataLayer && window.getEshopDataLayer('cookieConsent');
return !!c && (c.marketing === 'granted' || c.analytics === 'granted');
}
// initial state + react to later changes (the cookieConsent event fires on every change)
if (consentGranted()) startTracking();
window.eshopDataLayer = window.eshopDataLayer || [];
var push = window.eshopDataLayer.push;
window.eshopDataLayer.push = function (e) {
if (e && e.event === 'cookieConsent') { consentGranted() ? startTracking() : stopTracking(); }
return push.apply(this, arguments);
};(function () {
// 1) Current state — read the snapshot (available as soon as the page renders it).
function read() {
var eshop = window.getEshopDataLayer && window.getEshopDataLayer();
if (eshop) { /* map eshop.* to your format */ }
}
if (window.getEshopDataLayer) { read(); }
else { document.addEventListener('EshopDataLayerUpdated', read, { once: true }); }
// 2) Events — handle those already queued at page load, then catch every later push.
window.eshopDataLayer = window.eshopDataLayer || [];
function handle(entry) {
if (entry && entry.event) {
// entry.event: cookieConsent | pageVisit | loggedUser | categoryView | productView | cartUpdated | orderSubmitted
// the entry carries its own payload; the full snapshot is at window.getEshopDataLayer()
}
}
window.eshopDataLayer.forEach(handle);
var push = window.eshopDataLayer.push;
window.eshopDataLayer.push = function () {
for (var i = 0; i < arguments.length; i++) { handle(arguments[i]); }
return push.apply(this, arguments);
};
})();Verify everything straight from the browser console on any store page:
// full current snapshot
window.getEshopDataLayer();
// a single block
window.getEshopDataLayer('cart');
// log every snapshot refresh
document.addEventListener('EshopDataLayerUpdated', function (e) { console.log('snapshot', e.detail); });
// log every event
var push = window.eshopDataLayer.push;
window.eshopDataLayer.push = function () { console.log('event', arguments[0]); return push.apply(this, arguments); };
Add a product to the cart and you should see a cartUpdated event followed by a refreshed
snapshot; complete an order and the thank-you page carries the order block together with an
orderSubmitted event.
eshop.version guards backward compatibility of the contract. A breaking schema change
increments the major version — react to it in your loader (at least log an unknown major).