Export experience data
Export order-level or line-item-level data for an experience (A/B test) as a CSV file.
POST /analytics/experience/{experienceId}/export
Returns a presigned S3 URL to download a CSV file containing the requested export data. The URL is valid for 15 minutes.
Parameters
- experienceId (path) — required. UUID of the experience.
- exportType — required. Type of export: orders, order_line_items, or order_reconciliation (see table below).
- startTs — optional 10-digit epoch timestamp in seconds. Defaults to experience start date.
- endTs — optional 10-digit epoch timestamp in seconds. Defaults to now or experience end date.
- filters — optional analytics filters object. See below and the Filters Reference for available fields.
Export Types
| Value | Description |
|---|---|
| orders | Order-level data — one row per order with revenue, discount, variation assignment, and visitor |
| order_line_items | Line-item-level data — one row per line item with product, quantity, price, and variation |
| order_reconciliation | Reconciliation export joining Intelligems order attribution against the underlying order data |
order_reconciliation columns
Unlike the other two export types, this one is a narrow audit list rather than a metrics export. It has five columns and one row per store order in the window — including orders excluded from the analysis, not only orders attributed to the experience — so it answers "why is this order not in my numbers?".
| Column | Description |
|---|---|
| order_id | Shopify order ID. |
| order_name | Shopify order name (for example #1234). |
| order_created_ts | Order creation timestamp. |
| is_excluded | Whether the order was excluded from the experience's analytics. |
| exclusion_reason | Why it was excluded, as a numbered code and label (for example 05/Order could not be matched to a session). Included orders have 99/Not excluded, not an empty value. A bare Other with no numbered prefix also occurs, so parse the code defensively rather than assuming every value splits on /. |
Because excluded orders are included, the row count is normally higher than the orders export for the same window.
Upsell columns
Both the orders and order_line_items exports identify lines that an Intelligems upsell put in the cart, so you can separate upsell revenue from organic revenue.
order_line_items adds one column:
| Column | Description |
|---|---|
| upsell_type | Which Intelligems upsell surface added this line. Empty when none did. See values below. |
| Value | Meaning |
|---|---|
| (empty) | No Intelligems upsell added this line — see scoping below. |
| checkout_upsell | Added from an upsell block in the checkout extension. |
| onsite_upsell | Added from the onsite upsell widget, which renders on the product page or the cart. |
| post_purchase_offer | Added from a post-purchase offer, after checkout completed. |
The surfaces are mutually exclusive, so a line has exactly one value. Filter or pivot on this column to split upsell revenue from organic revenue. To see which variation an upsell line belongs to, use test_group_name, which is already in the export.
Scoping — what an empty value means
When the experience has its own checkout upsell blocks or onsite upsell components, upsell_type is scoped to them. checkout_upsell then means "added by this experience's checkout upsell", not "is an upsell of any kind". A line added by a different, concurrently-running upsell experience is left empty.
This is deliberate: it stops an export of one upsell test from attributing an overlapping test's upsells to itself. When the experience has no upsell surfaces of its own, no scoping is applied and the values mean "from any Intelligems upsell".
So read an empty upsell_type as "no upsell attributable to this experience", not strictly as "organic line item".
orders adds three order-level columns rolled up from the same scoped classification, so the two exports always agree on whether an order contains an upsell:
| Column | Description |
|---|---|
| upsell_types | Array of the distinct upsell surfaces present on the order. Empty array when there are none. |
| net_revenue_from_upsell | Net revenue across every upsell line on the order, all surfaces combined. |
| unit_quantity_from_upsell | Units across every upsell line on the order, all surfaces combined. |
For a per-surface revenue split, use the order_line_items export and group by upsell_type, or request the per-variation upsell metrics from POST /analytics/resource/{experienceId} with includeUpsellMetrics: true.
Filters
This endpoint accepts the same filters as POST /analytics/resource/{experienceId}. Key filters include:
| Field | Type | Description |
|---|---|---|
| deviceType | string | "any", "mobile", or "desktop" |
| visitorType | string | "any", "new", or "returning" |
| countryCodes | string[] | ISO 3166-1 alpha-2 codes, e.g. ["US", "GB"] |
| sourceSitesOrChannels | string[] | Traffic channel names (see Filters Reference) |
| userBehavior | object | Visitor behavior filter (see sub-fields below) |
| experimentProductsOnly | boolean | Only include products in the experiment (target products) |
| onlyProductIds | string[] | Shopify product IDs to include |
| onlyProductHandles | string[] | Shopify product handles to include |
userBehavior sub-fields
All fields are optional booleans. Set to true to filter to only visitors who performed that action.
| Field | Description |
|---|---|
| viewedProductPage | Visitor viewed a product page |
| viewedCollectionPage | Visitor viewed a collection page |
| addedToCart | Visitor added an item to cart |
| viewedCheckout | Visitor reached checkout |
See the Filters Reference section for the full list of available filter fields.
Response Structure
The response contains:
| Field | Type | Description |
|---|---|---|
| exportType | string | The export type requested (orders, order_line_items, or order_reconciliation) |
| experienceId | string | UUID of the experience |
| experienceName | string | Display name of the experience |
| url | string|null | Presigned S3 URL to download the CSV. Null if the export timed out. |
| expiresIn | number | Seconds until the URL expires (900 = 15 minutes). 0 if url is null. |
| format | string | Always "csv" |
| message | string | Human-readable status (e.g. "Export ready", "Export timed out, please retry") |
Date Range Behavior
- When startTs and endTs are omitted, the date range defaults to the experience's full lifetime (start date through end/pause date or now).
- If the experience is paused or ended, the export is automatically truncated at the pause/end date.
- If the provided startTs is before the experience start date, it is clamped to the experience start. Similarly, endTs is clamped to the experience end/pause date.
- Clamping only applies to a window that overlaps the experience lifetime. A window that falls entirely outside it is rejected rather than clamped: HTTP 400 with { "error": "Requested time range falls outside the experience lifetime" }.
Presigned URL
The returned URL is a time-limited presigned S3 URL. It expires after 15 minutes (900 seconds). After expiry, the URL returns a 403 Forbidden. Call the endpoint again to generate a new URL.
Rate Limit: 20 requests per 60s window, refilling 10 tokens every 60s.
Request
- Base URLhttps://api.intelligems.io
- AuthAPI key in header intelligems-access-token
- TypeScriptA function with typed inputs. Its response is checked against the schema.
Path parameters
Request body
Response
OK
Changes
No recorded changes to this operation across all 1 revision of this API.