Skip to content

Product String Builder

The Product String Builder action constructs the Adobe Analytics &&products string from structured product data in the event payload — no app code changes required. It handles the Category;Product;Quantity;Price;events;eVars wire format, per-product merchandising, and merges with any existing products string already on the hit.

Screenshot needed

Capture: The Product String Builder action UI in Launch, showing the product data source field and at least one merchandising row.


What is &&products?

Adobe Analytics uses the &&products contextdata key to populate s.products. Each product entry in the semicolon-delimited string has this shape:

Category;Product Name;Quantity;Price;Events;Merchandising eVars

Multiple products are separated by commas:

Electronics;SKU-123;1;49.99;event1=1;eVar10=blue,Apparel;SKU-456;2;19.99;;

Constructing this string correctly from mobile app data has traditionally required app code. The Product String Builder builds it from a Launch rule.


When to use this action

Use it when:

  • The app sends product data as a structured array or dictionary in the track event payload
  • You need merchandising eVars or product-scoped events set per product
  • You want parity with web implementations that use the s.products string

Don't use it when:

  • The app already constructs and sends &&products itself — use Modify Data to pass it through instead
  • You only need to set s.events without product context — use Set Serialized Events

Product data source

The action reads product data from the event payload. It supports three input shapes:

Input shape Example payload
Array of product dicts contextdata.products = [{...}, {...}]
JSON string contextdata.products = "[{...}, {...}]"
Single product dict contextdata.product = {...} (auto-wrapped into an array)

Set the Source path to the dot-notation path in the event (e.g. contextdata.products).

Each product dict should contain the fields you'll map in the action — for example name, category, quantity, price, sku.


Field mapping

Map event payload fields to the &&products columns:

Column What to configure
Category Dot-notation path into the product dict (e.g. category), or a static value
Product Path or static value (e.g. sku)
Quantity Path or static value. Defaults to 1 if absent.
Unit price Path or static value. Airlock multiplies quantity × unit price to get the total price column.

Leave any column blank to omit it from that column's slot (the semicolons are still present in the output).


Merchandising eVars

Add one row per merchandising eVar. Each row has:

  • eVar number (e.g. 10 for eVar10)
  • Value path — dot-notation into the product dict
  • Condition (optional) — only include this eVar if a specified field on the product matches a value (exact match or glob)
eVar10 = product.colour        (condition: category matches "Apparel*")
eVar11 = product.size

Custom events

Add product-scoped events (e.g. prodView, scAdd). Each row has:

  • Event name (e.g. prodView)
  • Value path (optional) — for numeric/currency events
  • Boolean coercion — when enabled, values like true, yes, or 1 are coerced to "1" (useful for flag fields in the payload)

Custom event names are also automatically added to &&events on the hit.


Reset behaviour

Controls what happens when &&products already exists on the event (from the app or an upstream rule):

Mode Behaviour
Reset Replaces any existing &&products value entirely
Append Merges new product entries into the existing string

Default is Reset. Use Append when the app sets some products and the rule adds others.


The buildProductString() JS helper

If the rule already has an Evaluate JavaScript Rules action, you can build the products string from your script using the built-in helper:

var products = event.contextdata.products; // array of product dicts

event.contextdata['&&products'] = buildProductString({
  products: products,
  category: 'category',
  name: 'sku',
  quantity: 'qty',
  unitPrice: 'price',
  merchandising: [
    { evar: 10, value: 'colour' },
    { evar: 11, value: 'size' }
  ],
  events: ['prodView']
});

return event;

The helper uses exact-equality conditions only (glob matching is available in the standalone action UI but not the JS helper in v1).

When to use which: Use the action UI for non-technical authors and clean separation of concerns. Use the JS helper when the rule already has a script and you want to keep the product string logic alongside it.


Worked example: retail purchase

The app sends:

trackAction("purchase", contextData: [
  "order_id": "ORD-98765",
  "products": [
    {"sku": "SKU-123", "name": "Blue Widget", "qty": 2, "price": 24.99, "category": "Widgets", "colour": "blue"},
    {"sku": "SKU-456", "name": "Red Gadget",  "qty": 1, "price": 49.99, "category": "Gadgets", "colour": "red"}
  ]
])

Action configuration:

  • Source path: contextdata.products
  • Category: category
  • Product: sku
  • Quantity: qty
  • Unit price: price
  • Merchandising eVar: eVar10 = colour
  • Custom events: purchase
  • Reset mode: Reset

Output &&products:

Widgets;SKU-123;2;49.98;purchase;eVar10=blue,Gadgets;SKU-456;1;49.99;purchase;eVar10=red

Note: Airlock multiplied qty × price for the price column (2 × 24.99 = 49.98).


Reserved character handling

The &&products format uses ;, ,, and | as delimiters. Airlock strips these characters from field values at build time — a product name like Widget, Large becomes Widget Large in the output rather than forging phantom columns.


Verifying with Assurance

  1. Connect the test app to Assurance.
  2. Fire the track event that triggers the rule.
  3. Find the Airlock Processed Track event. Confirm:
  4. contextdata.&&products is present with the expected shape
  5. contextdata.&&events includes any custom events you configured
  6. contextdata.airlock.status is ok
  7. Cross-check the product count and price arithmetic match the payload.

Screenshot needed

Capture: Assurance showing the Airlock Processed Track event with contextdata.&&products expanded.


Common mistakes

Products string is empty. The source path doesn't resolve — check the exact path in the raw trackAction payload in Assurance. Paths are case-sensitive.

Price column is wrong. The action multiplies quantity × unit price. If the app already sends a total price, map it to a static quantity of 1, or leave the quantity blank and map price to the total directly.

Merchandising eVar appears on some products but not others. The condition on that eVar row doesn't match all products. Either remove the condition to apply it universally, or verify the condition field/value against the actual product dicts in the payload.

&&events is missing the product event. Custom event names are added to &&events automatically — but only if at least one product row produces output. If the source path resolves to an empty array, no products are built and no events are added.


See also