amitdusane.com Adobe Analytics Learning

Start with the foundationsVariables: Props, eVars, and Events

The Products String

Default and reserved variables flagged this one as the exception. Most reserved variables do one small job, but the products variable runs your entire ecommerce funnel through a single string: what was viewed, added, checked out, and bought, how many, for how much, and even why. It is also where several earlier threads meet: the hit-scoping of props, the attribution behavior of eVars, and the reserved commerce events all converge inside it. Get it right and the whole commerce side of Adobe Analytics works. Get a single delimiter wrong and revenue quietly breaks with no error message. It is the most powerful and the most punishing variable in the product, which is exactly why it earns its own section.

One string, one order, many products

The plural name fools people. You set one s.products string per hit. On a purchase, that single string represents the whole order, and it can carry many products inside it, separated by commas. So "products" means the basket, not one item.

Anatomy, and the three delimiters that decide everything

The string is positional: meaning comes from which slot a value sits in, not from any label. Six fields per product, in this fixed order:

One product, six fields, separated by semicolons — and the empty ones still count
s.products = Apparel category Blue Shirt the only required one 2 qty 59.98 qty × unit price event1=1|event2=5 events, pipe-separated eVar1=blue|eVar2=cotton merchandising eVars ; ; ; ; ; five semicolons, always — a field you are not using is left empty, not left out Only the product name is required. The order of the rest is fixed. Drop a semicolon and every field after it lands in the wrong place

Three delimiters do all the structural work, and confusing them is the number-one cause of broken commerce data:

DelimiterSeparatesExample
Semicolon ;the six fields within one productApparel;Blue Shirt;2
Comma ,one product from the nextShirt;1;29.99,Socks;3;26.91
Pipe |multiple events, or multiple merchandising eVars, inside a fieldevent1=1|event2=5

What becomes which KPI

Three pieces of the string turn directly into the metrics your business lives by:

Three fields of the string become three of the numbers everyone quotes.

Field in s.productsBecomes
the purchase eventOrders
the price fieldRevenue
the quantity fieldUnits

The catch most people hit at least once: the purchase event must be explicitly fired in s.events for Orders to register, and quantity and price are only counted on the hit where purchase fires. A products string without the purchase event on the order page means revenue silently goes nowhere.

It has no memory: set it on every funnel hit

Here's the trait that surprises people: the products variable does not persist. It's hit-scoped, like a prop (the pencil behavior from props), the value vanishes after the hit it rode in on, even though it carries events and merchandising eVars that behave with attribution like eVars. So it straddles both worlds: a non-persistent carrier of persistent data. Practically, that means you must re-send s.products on every funnel hit where product context matters, alongside the reserved commerce events from default and reserved variables (prodView, scAdd, scCheckout, purchase).

The string does not carry forward — send it again at every step
Product view prodView + s.products Cart add scAdd + s.products Checkout scCheckout + s.products Purchase purchase + s.products Unlike an eVar, the products string is spent on the hit that carries it Omit it at checkout and the checkout simply has no product detail — the purchase is still fine

Product-level events (and the caveat that bites)

Slot 5 lets you attribute a metric to a single product, give one product an event another doesn't get. Three rules govern it:

  • It must also appear in s.events. Otherwise Adobe ignores it entirely. The events variable is the gatekeeper; the products string only assigns the event to a product.
  • Don't set the same numeric event in both places. If a numeric value is set in both s.events and the products string, the events value wins.
  • Usually numeric or currency, occasionally counter. They typically carry a per-product number (product revenue, shipping), but a counter is allowed, the same event types from events.
JavaScript
// event1 must be in BOTH places, or it won't count
s.events = "purchase,event1";
s.products = "Apparel;Blue Shirt;2;59.98;event1=5;eVar1=blue";

// Two products, an event credited only to the second
s.events = "event1";
s.products = "Apparel;Shirt;1;29.99,Footwear;Socks;3;26.91;event1=3";

Merchandising eVars: bound to a product, not the visitor

A normal eVar attaches its value to the visitor. A merchandising eVar, first mentioned back in the eVar section, binds it to a specific product instead, so you can answer "revenue by the on-site search term that surfaced this product." Two syntaxes:

  • Product syntax (recommended): set the eVar right in slot 6 of the products string. Use this when you know the value at the moment the product is set.
  • Conversion variable syntax: set the eVar separately and bind it via a binding event, for when the value isn't known at product time.

The conversion-syntax trap: the eVar value, the products variable, and the binding event must all line up on the right hit, or the instance lands in "None / Unspecified."

The mindset shift: don't treat a merchandising eVar like a normal one. It doesn't simply persist to the visitor, its association is product-scoped and deliberate, so you repopulate or rebind it as products change.

Order-level vs product-level: put data where it belongs

A clean design separates the two. Mixing them up is one of the most common implementation design mistakes, and it's painful to unwind later.

📦
Outside the string (order-level)
Facts about the whole order: order ID, user ID, order date, payment method. These belong in their own eVars and events, not in products.
🏷️
Inside the string (product-level)
Facts about a single product: color, size, seller, finding method. These belong inside the products string as merchandising eVars.
Why the products string never truncates

Props cap at 100 bytes and eVars at 255, but the products string can hold up to 64k bytes, effectively unlimited for any real basket. When a hit's request grows long (beyond about 2047 bytes), AppMeasurement automatically switches the beacon from a GET to a POST request, and POST data is not truncated regardless of length. So large multi-product orders are handled fine, you just won't see the whole string in the request URL when you're debugging a GET.

Build it once, the right way

Don't hand-concatenate the products string inside each Launch rule, that's how delimiter bugs breed. The durable pattern: have developers expose product data as parallel arrays in the data layer with one entry per product, even when there's only one, then write a single formatting function, placed just below doPlugins so it's globally available, that assembles the string correctly. Call that one function from every relevant Tags rule, cart add, checkout, purchase. One function, one source of truth, no per-rule string-building.

JavaScript
// Data layer exposes parallel arrays (works for 1 or many products)
// digitalData.products.name[], .category[], .qty[], .price[]

// One global formatter, defined just below doPlugins
function buildProducts(p) {
  return p.name.map(function (n, i) {
    return [p.category[i], n, p.qty[i], p.price[i]].join(";");
  }).join(",");   // products joined by comma
}
// Reuse from any rule:
s.products = buildProducts(digitalData.products);
Inspect it, don't trust it blind

Use a debugger to see the products string broken into its products and fields. Adobe's own Experience Platform Debugger is the official option; many practitioners also use a community Chrome extension that lays out each product and parameter clearly (Adobe Analytics debugger extension, third-party, not an Adobe product). Either way these are read-only inspectors, perfect for verifying the string, not for fixing it.

The traps that silently corrupt commerce data

This variable punishes small mistakes without a single error message. The recurring ones:

  • A missing semicolon shifts every later value into the wrong slot, with no error.
  • Price is the line total (qty × unit), but the Tags "Product String" extension takes the unit price and multiplies, so know which your tool expects.
  • A duplicate purchaseID discards the entire hit, every product, eVar, and event on it, which makes refreshable confirmation pages dangerous.
  • Reserved characters break the string: never put a comma, semicolon, or pipe inside a product name or value.
  • An event missing from s.events is silently ignored, even if it's in the products string.
  • A conversion-syntax merchandising eVar without its binding event lands in "None."

One last thread to pull. Underneath all its commerce machinery, the products string is really a way to pack many values into a single hit: several products, each with its own events and eVars. That idea, many values carried in one hit, is common enough to have a dedicated variable type of its own, List Variables and List Props, and that is exactly what list variables covers.

Where to Find in Adobe Analytics

Set via implementation/Tags, not report suite settings. Commerce reports appear under Components → Dimensions → Products and the Commerce metrics (Orders, Revenue, Units).

Need implementation steps?

This article focuses on the concepts, architecture, and practical guidance behind the topic. For the latest UI walkthroughs and step-by-step implementation instructions, use the links below. They leave this site and open Adobe's own documentation in a new tab.