Fetch Experience Data

Analyze experience

Analyze analytics data for a specific experience using a POST request body for filters and request settings.

The legacy GET /analytics/resource/{experienceId} endpoint remains available only as a beta compatibility path for existing integrations. It is deprecated, limited to its original query-parameter contract, and will be removed when the beta version ends.

view is optional and defaults to overview; a body of {} returns the same payload as {"view": "overview"}. Valid values are overview, audience, and post_test. The value summary is not supported. When view is audience, you must also provide the audience field. When view is post_test, the audience field is optional (supply it to break the post-test metrics down by that dimension). The audience field is not allowed when view is overview — including when view is omitted and therefore defaulted, which rejects audience with a 400.

A request body is required even when every field is optional: sending no body at all returns 400 with { "errors": ["Invalid input: expected object, received undefined"] }. Send {}.

Use startTs and endTs in the request body to match the backend contract. These values must be 10-digit Unix epoch timestamps in seconds, not milliseconds. Use the filters object for all advanced filtering instead of query parameters.

Audience breakdowns (view=audience)

When view is audience, metrics are segmented by the selected audience dimension — one row per (variation × segment) — ordered by visitor count.

Accepted audience dimensions are device_type, visitor_type, source_channel, source_site, country_code, landing_page_full_path, and purchase_likelihood.

Only the high-cardinality dimensions country_code and landing_page_full_path are limited by default: when you omit topN, they return the top 10 segments by visitor count. The other dimensions — device_type, visitor_type, source_channel, source_site, and purchase_likelihood — are low-cardinality and are not limited by default; they return all their segments.

Segment values in the response are display-cased, not the lowercase wire values used by the request filters: device_type returns "Mobile" / "Desktop", visitor_type returns "New" / "Returning". Match on those exact strings, not on the filters.deviceType enum values.

Use the topN field to control this. It accepts an integer between 1 and 1000:

  • Omit topN — country_code and landing_page_full_path return their top 10; all other dimensions return every segment.
  • Set topN to a value between 1 and 1000 — caps the selected dimension at that many top segments (applies to any dimension). Values above 1000 are rejected.

The 1000 maximum bounds the response size and query cost, so a breakdown can never degrade into the unbounded scan that caused earlier timeouts. This is why landing_page_full_path, which can have thousands of distinct URLs, is never returned in full — request the top segments you need (up to 1000).

Upsell metrics (includeUpsellMetrics)

Set includeUpsellMetrics: true (boolean, default false) with view=overview to add per-variation upsell performance to the metrics array. This answers whether a variation drove a higher upsell take rate, not just higher overall revenue.

view=overview is the supported combination. The flag is currently also honoured under view=audience, where it adds the same fifteen fields to every (variation × segment) row, but that is not a guaranteed behaviour — the request schema documents the flag as overview-only, so treat the audience case as incidental and do not build on it. Under view=post_test the flag is ignored and no upsell fields are returned.

Metrics are returned for each of the three Intelligems upsell surfaces, which are distinct and reported separately:

SurfaceWhat it is
checkout_upsellAn upsell block in the checkout extension.
onsite_upsellThe onsite upsell widget, which renders on the product page or the cart.
post_purchase_offerAn offer presented after checkout completed.

For each surface <s>, five metrics are added:

MetricDefinition
net_revenue_from_<s>Net revenue from lines added by that surface.
pct_orders_with_<s>Share of orders containing at least one line from that surface (the upsell take rate).
pct_revenue_from_<s>That surface's revenue as a share of total net revenue.
n_units_from_<s>Units sold through that surface.
net_revenue_from_<s>_per_order_with_upsellAOV contribution — revenue divided by the orders that took the offer, not by all orders.

Note the denominator in net_revenue_from_<s>_per_order_with_upsell: it divides by the orders that took the offer, not by every order. It answers "how much does an upsell add when it lands", not "how much does this surface add per order overall".

The all-orders variant, net_revenue_from_<s>_per_order, exists in the internal metric catalogue but is not reachable through the external API — includeUpsellMetrics: true returns only the fifteen fields listed above, and _per_order is not a valid graphs.ids value either. To get a per-all-orders figure, divide net_revenue_from_<s> by n_orders from the same response.

This is off by default because computing it adds per-line-item aggregation that stores without upsells should not pay for on every request.

To see which individual line items an upsell added, use the order_line_items export and its upsell_type column.

Post-test metrics (view=post_test)

Post-test metrics look at customers who converted during the test and track their purchase behavior after that conversion, split by variation — answering "which variation produced more valuable customers over time?". Tracking is at the customer level (not cookie). Order filters narrow the in-test customer set only; they do not constrain the post-test orders.

The includeInTestOrders field (boolean, default true) controls whether in-test orders are folded into the metrics:

  • true (default) — returns all three families. total_* is the LTV view (post-test + in-test combined), and the in-test eso_* family is included.
  • false — the eso_* family is omitted entirely, and total_* collapses to equal post_* (since no in-test orders are folded in). The post_* family and headcounts are returned as usual.

Headcounts and rates are always present: n_visitors, n_customers, customers_per_visitor, pct_repeat_customers.

Every metric is { value }. There is no pct_change field.

uplift is only present on rate metrics. On a non-control variation, per-visitor and per-customer rate metrics additionally carry uplift: { value } — the ratio vs control as a fraction. Two rules govern it:

  1. The control variation never carries uplift.
  2. Raw counts and absolute totals never carry uplift, on any variation. That covers n_visitors, n_customers, n_post_orders, n_eso_orders, n_total_orders, post_net_revenue, post_gross_profit, eso_net_revenue, eso_gross_profit, total_net_revenue, and total_gross_profit — all of which are always bare { value }. Compute a comparison on those yourself if you need one.

The metrics that do carry uplift are the eighteen *_per_visitor / *_per_customer rates across the three families (six per family — orders, revenue, and profit, each per visitor and per customer), plus customers_per_visitor and pct_repeat_customers. That is twenty uplift-carrying fields on a non-control variation when includeInTestOrders is true, and fourteen when it is false (the eso_* family drops out, taking six of the rates with it).

Metric families:

  • post_* — post-test orders only (after the customer's in-test conversion): n_post_orders, post_net_revenue, post_gross_profit, post_orders_per_visitor, post_revenue_per_visitor, post_profit_per_visitor, post_orders_per_customer, post_revenue_per_customer, post_profit_per_customer.
  • eso_* — in-test ("experiment span") orders, only when includeInTestOrders=true: n_eso_orders, eso_net_revenue, eso_gross_profit, eso_orders_per_visitor, eso_revenue_per_visitor, eso_profit_per_visitor, eso_orders_per_customer, eso_revenue_per_customer, eso_profit_per_customer.
  • total_* — post + in-test combined (LTV view): n_total_orders, total_net_revenue, total_gross_profit, total_orders_per_visitor, total_revenue_per_visitor, total_profit_per_visitor, total_orders_per_customer, total_revenue_per_customer, total_profit_per_customer. Always present, but when includeInTestOrders=false these values equal the corresponding post_* values.

When view=post_test is combined with audience, each metric row additionally carries an audience key (the bucket value, e.g. "mobile"), with one row per (variation × audience value), and audienceOrder is populated.

Graphs

When requesting graphs via the graphs object, graphs.ids accepts an array of metric identifiers.

The authoritative list of valid values is the graphs.ids enum in this endpoint's request schema, which is generated from the metric catalogue — see the schema for the current set. It is deliberately not duplicated in prose here: the previous hand-maintained list had fallen four values behind the enum (net_revenue_from_upsell, pct_orders_with_upsell, net_revenue_from_post_purchase_offer, pct_orders_with_post_purchase_offer were all accepted but undocumented).

Note: revenue_per_visitor is not a valid graph ID — use net_revenue_per_visitor instead.

Invalid IDs are rejected with a 400 validation error on this endpoint. The deprecated GET /analytics/resource/{experienceId} instead silently drops them and returns graphs: [].

graphs.outputFormat is optional and defaults to "png", so {"graphs": {"ids": [...]}} returns CDN URLs.

Each graph object in the response includes id (string), key (the original metric key), type (chart type, e.g. "bar"), title (display title), and either url (CDN URL when outputFormat is "png") or data (base64-encoded PNG when outputFormat is "base64").

The graphs key is omitted from the response entirely when the request does not ask for graphs; it is only present (possibly as []) when graphs was sent. A valid graphs.ids value for a surface this store has no data for yields graphs: [] rather than an error.

Additional Response Fields

Response payloads include impact (object with est_monthly_revenue_increase: the projected 30-day revenue lift from the best non-control variation vs. control, or null when there is insufficient data) plus the ordering helper audienceOrder (segment display ordering, populated only for view=audience and for view=post_test with an audience; an empty array otherwise).

impact is calculated from whole-variation overview metrics with the same filters and time window, including when view=audience. Audience segmentation and topN do not change this experience-level calculation. Under view=post_test, the estimate is null.

histogram, kde, and cdf are also always present alongside the primary metrics and variations arrays, but this endpoint does not currently populate them — they are returned as empty arrays regardless of view, analyticsViewType, or date range. Do not build on them here. For an order-value distribution, use POST /analytics/sitewide/order-distribution, which returns a populated orderValueDistribution.kernel_density_estimate and orderValueDistribution.cumulative_distribution_function.

audienceOrder

audienceOrder is a display ordering hint, not the order of the metrics array. The metrics rows come back in the order the analytics store returned them, so do not assume the two line up — sort or index by the audience key if you need them to.

The ordering is by total visitors summed across all variations, descending. Two consequences:

  • It will not match a descending sort of any single variation's n_visitors, because the sort key is the cross-variation total.
  • "Other" and "Unknown" are pinned to the end regardless of size, in that order, so they can appear after segments with fewer visitors.

Rate Limit: 50 requests per 30s window, refilling 25 tokens every 30s.

post/v25-10-beta/analytics/resource/{experienceId}

Request

Path parameters

experienceIdstring uuid required

Request body

view'overview' | 'audience' | 'post_test'

Resource view to analyze. Supported values are 'overview' for variation-level metrics, 'audience' for a breakdown by the selected audience dimension, and 'post_test' for post-test metrics (customers who converted during the test, tracked by their purchase behavior after that conversion, split by variation).

audience'device_type' | 'visitor_type' | 'source_channel' | 'source_site' | 'country_code' | 'landing_page_full_path' | 'purchase_likelihood'

Audience breakdown dimension. Required when view is audience. Optional when view is post_test (returns the post-test breakdown by the selected dimension). Not allowed when view is overview. Use one of the supported audience fields such as device_type, visitor_type, or source_channel.

includeInTestOrdersboolean

Only applies when view is post_test. Controls whether in-test orders are folded into the metrics. When true (default), the in-test eso_* family is included and total_* is the LTV view (post-test + in-test combined). When false, the eso_* family is omitted and total_* collapses to equal post_*. The post_* family and headcounts/rates are always returned.

analyticsViewType'test_orders_only' | 'sitewide_orders' | 'none'

Optional analytics view preset used by the backend when building the analysis request.

includeUpsellMetricsboolean

When true, adds the per-variation upsell metric families to the response for all three Intelligems upsell surfaces — checkout upsell, onsite upsell (rendered on the PDP or cart), and post-purchase offer. Each surface contributes revenue (net_revenue_from_<surface>), take rate (pct_orders_with_<surface> — the share of orders containing at least one line from that surface), revenue share (pct_revenue_from_<surface>), units (n_units_from_<surface>), and AOV contribution (net_revenue_from_<surface>_per_order_with_upsell — revenue divided by the orders that actually took the offer, not by all orders). Off by default because computing them adds per-line-item aggregation that stores without upsells should not pay for. Only applies when view is overview.

endTsstring

Optional analysis end timestamp as a 10-digit Unix epoch string in seconds (not milliseconds). Maps directly to the backend endTs field.

startTsstring

Optional analysis start timestamp as a 10-digit Unix epoch string in seconds (not milliseconds). Maps directly to the backend startTs field.

topNinteger

Only applies when view is audience. Caps the breakdown to the top N segments by visitor count, where N is an integer between 1 and 1000. By default, only the high-cardinality dimensions country_code and landing_page_full_path are capped at 10; the other dimensions (device_type, visitor_type, source_channel, source_site) are low-cardinality and returned in full. Set a value between 1 and 1000 to override the cap for any dimension. The 1000 maximum bounds the response size and query cost — this is why landing_page_full_path, which can have thousands of distinct URLs, is never returned in full.

testResultboolean

When true, compute and return the opt-in test verdict alongside the overview. The verdict is returned on the response as testResult. Only an unfiltered verdict is persisted in DynamoDB for re-use on later requests. If any filter is set, the verdict is computed fresh on that filtered subset for this request only — it is neither read from nor written to the stored verdict — so it can differ from the unfiltered verdict for the same experience. A filter that narrows the population — including a startTs/endTs that covers less than the whole experience — means the verdict no longer describes the full randomized group the thresholds were validated on, so it is not a test result: the label comes back prefixed (filtered_directional_win, filtered_not_ready, …) and action_to_take is a refusal naming the filters it was computed under. The one exception is a price test scoped to its own target products, which narrows the metric rather than the population: it keeps its normal label and recommendation, but is still not persisted. Every computed verdict, filtered or not, is recorded in Snowflake for analysis.

Response

OK

datasetId'order_line_items' | 'orders' | 'aiProfit' | 'variation_overview' | 'variation_audience' | 'variation_timeseries_discrete' | 'variation_timeseries_cumulative' | 'experience_countries' | 'variation_shipping_method' | 'variation_histogram' | 'variation_products' | 'variation_product_groups' | 'variation_order_unit_mix' | 'custom_events_plugin' | 'custom_events_server' | 'order_reconciliation' | 'order_reconciliation_export' | 'experience_session_order' | 'timeseries' | 'country_codes' | 'snapshots' | 'experience_shipping_methods' | 'timeseries_audience' | 'snapshots_audience' | 'holiday_benchmarking_single_day' | 'holiday_benchmarking_multiple_days' | 'order_distribution_histogram' | 'order_distribution_unit_mix' | 'conversion_snapshots' | 'conversion_funnel' | 'conversion_timeseries' | 'variation_post_metrics' | 'variation_post_metrics_audience' required
latestRunTsnumber required
cogsConfiguredboolean

Whether cost of goods sold (COGS) is configured for the store (any revenue has COGS data). When false, all profit metric values are null because they cannot be computed; use revenue metrics instead. Only present when the request includes a profit metric.

cogsCoveragePctnumber

Fraction of revenue (0-1) backed by line items that have COGS data. 0 means profit metrics are unavailable and returned as null. A value between 0 and 1 means profit is based on partial COGS coverage; 1 means full coverage. Only present when the request includes a profit metric.

audienceOrderunknown required
histogramunknown required
kdeunknown required
cdfunknown required
experienceIdstring uuid
experienceNamestring

Changes

No recorded changes to this operation across all 1 revision of this API.