Experiment Tracking
Report exposure to externally managed experiments and attach experiment contexts to interactions.
Experiment tracking is available in @psykhe-ai/browser-plugin-snowplow-ecommerce version
0.2.0 and later. Use trackExperimentExposure to report participation and attach repeatable
experiment contexts to ecommerce interactions.
Report exposure when your integration's chosen condition occurs, such as opening a page or reaching 50% scroll. Send it for every variant, including baseline, at the same condition. Support any number of variants and concurrent experiments. Requesting recommendations does not establish exposure: the storefront may later suppress their display.
Install the plugin
Install or upgrade the plugin, then use the tracker configured in Getting Started:
pnpm add @psykhe-ai/browser-plugin-snowplow-ecommerce@^0.2.0Report an exposure
Supply one entry per experiment involved in the action. The plugin builds the exposure event and experiment contexts. The tracker supplies page, browser, session, time, and event identifiers.
import {
trackExperimentExposure,
type Experiment,
} from "@psykhe-ai/browser-plugin-snowplow-ecommerce";
// Supply the decisions when they become available in your integration.
const experiments: Experiment[] = [
{
experimentId: "recommendations-2026-10",
variationId: "baseline",
custom: [{ key: "placement", value: "product_page" }],
},
{
experimentId: "product-layout-2026-10",
variationId: "compact",
},
];
// Call when the configured exposure condition is reached.
trackExperimentExposure(
{ experiments, trigger: "scroll_50_percent" },
["psykhe-ai"],
);trigger is an optional string of up to 128 characters that describes the condition. Omit it and
call trackExperimentExposure({ experiments }, ["psykhe-ai"]) when you do not need a description.
At least one experiment is required. Every entry must have nonblank experiment and variation
identifiers. The helper rejects incomplete identifiers and invalid optional fields before tracking.
Exposures without a complete experiment context are rejected by PSYKHE AI.
An exposure reports that the chosen condition occurred. It does not automatically prove that a recommendation rendered or became visible. Keep the condition consistent between variants and use your usual interaction events to report views and clicks.
Experiment fields
| Field | Required | Type and limit | Meaning |
|---|---|---|---|
experimentId | Yes | Nonblank string, up to 160 characters | Stable experiment identifier or tracking key. Use a new identifier for a distinct test run. |
variationId | Yes | Nonblank string, up to 100 characters | The variant the shopper receives, including baseline. Supports any number of variants. |
hashAttribute | No | String or null, up to 100 characters | Name of the attribute used to assign the variant, such as customerId. |
hashValue | No | String or null, up to 160 characters | Original value of that assignment attribute, such as customer-123. |
custom | No | Array or null | Optional key/value entries with string key and string or null value for additional experiment data. |
Keep identifiers consistent across exposure and interaction events. Send only additional data you
need in custom; omit unavailable optional fields. Experiment and variant names are not required.
Optional assignment inputs
Send hashAttribute and hashValue when your experimentation logic makes its assignment inputs
available. For example, if it assigns variants by hashing a customer identifier:
trackExperimentExposure(
{
experiments: [
{
experimentId: "recommendations-2026-10",
variationId: "baseline",
hashAttribute: "customerId",
hashValue: "customer-123",
},
],
trigger: "scroll_50_percent",
},
["psykhe-ai"],
);hashValue contains the value that was hashed. Use the original assignment input; you do not need
to calculate another hash for tracking. These details can help explain assignments when the test
uses a customer, account, or device identifier that differs from the tracker's browser identity.
PSYKHE AI records the supplied values with the experiment; your experimentation logic chooses
the variant.
Both fields are optional. If the inputs are unavailable or unnecessary for your analysis, omit
them or use null. An exposure requires only experimentId and variationId in each experiment
entry. The tracker supplies its normal identity fields independently.
Every integration uses the same contract, regardless of which system chooses the variant. The plugin validates supplied values against the types and limits above without inferring assignment inputs or checking how the variant was chosen. Do not substitute the tracker's browser identifier unless you know the experiment used it for assignment. These optional fields do not change tracker identity or control traffic allocation.
Attach contexts to later interactions
When decisions are available, pass the same experiments array on list views, list clicks,
cart actions, transactions, and other ecommerce helpers. This option is optional on ordinary
interactions and works alongside recommendation contexts:
import {
trackProductListView,
withRecommendIdCtx,
} from "@psykhe-ai/browser-plugin-snowplow-ecommerce";
trackProductListView(
{
name: "recommendations",
products: [{ product_id: "sku-123", price: 100, currency: "usd" }],
context: [withRecommendIdCtx("recommendation-id")],
experiments,
},
["psykhe-ai"],
);For standard Snowplow functions, use withExperimentCtx to build contexts:
import { trackPageView } from "@snowplow/browser-tracker";
import { withExperimentCtx } from "@psykhe-ai/browser-plugin-snowplow-ecommerce";
trackPageView({ context: experiments.map(withExperimentCtx) }, ["psykhe-ai"]);Attaching experiments describes that interaction; it does not create another exposure. Your integration supplies the currently applicable experiments on each page. The plugin does not remember them automatically. Stop attaching experiments when they no longer apply. If a later event cannot carry them, still send the separate exposure event using the same tracker and browser identity.
Event Categories
Required and recommended tracking events for PSYKHE AI.
Create new ingestion POST
Creates a new ingestion job for processing product data. ### Which processing mode should I use? | Scenario | Use this mode | |---|---| | Webhook updates (single product or small batch) | `insert` | | Incremental sync (only changed products) | `insert` | | **Full catalog sync** (you are sending the *entire* active catalog) | `soft_replace` | | Hourly / daily catalog dump | `soft_replace` | Set the mode via the `X-PSYKHE-PROCESSING-MODE` header. - **`insert` (default)** - Upserts products present in the feed. Products *not* in the feed are left untouched. This is the safe default for webhooks and incremental batches because it never disables anything. - **`soft_replace`** - Upserts products present in the feed *and marks every other active product in your catalog as inactive* (excluded from recommendations; data is preserved, not hard-deleted). Only use this when the payload contains your **complete** catalog. Sending a partial catalog with `soft_replace` will disable every product you omitted. Request body is newline-delimited JSON (JSONL), one product per line. Gzip compression is supported via `Content-Encoding: gzip`. The ingestion is processed asynchronously - the response returns immediately with an `ingestion_id` you can poll via `GET /ingestion/{id}`.