Orders containing a specific product
This report identifies every order that contains a specific product and shows all line items within those orders — not just the matching product row. The goal is a full view of basket composition and co-purchase behaviour for any product of interest. It is most useful when evaluating cross-sell opportunities, assessing promotional impact, or reviewing order mix for a specific product across your catalogue.
In this article
- How the report works
- Steps to build the report
- Interpreting the results
- Variations and extensions
- Need more support?
How the report works
The report is built on the Agreement Lines root table, where each row represents a single line item event on an order. This is the correct table for any analysis that needs line-item detail alongside revenue metrics.
One custom field is required: Order Contains @Product. This field cannot be built from native fields alone because the containment check must evaluate across all line items in an order and return a result on every row — including rows that do not match the product. A native filter would remove non-matching rows entirely. Instead, a window function partitioned by Order Id evaluates whether any row in the order matches the selected product and propagates that result across all rows in the order. The field returns true or false on every line item, and filtering for true keeps all rows from qualifying orders intact.
The report uses a single filter on Order Contains @Product = true , which keeps all line items from orders containing the selected product.
The report is started from a copy of the built-in Line item details report, which already includes the most useful line item dimensions and revenue measures.
💡 Prefer to skip the setup? If you'd like this report built for you, contact our team through the Help widget in the bottom-right corner. We typically respond within one business day.
Steps to build the report
Step 1 — Start from the Line Item Details report
Rather than starting from a blank report, this report is built from a copy of the built-in Line item details report, which already includes the key line item dimensions and revenue measures needed. To open it:
- Open the Reports tab and open the Line item details report in the Agreement lines table group.
Step 2 — Create the Order Contains @Product custom field
This custom dimension evaluates every line item row within an order and returns true if any of them matches the selected product title. The window function groups the evaluation by Order Id, so the result reflects the entire order rather than the current row alone — if any line item in the order matches, all rows in that order return true .
- Select Edit
- Select + Create new, then select Create Dimension
- Set the Root table to Agreement Lines
- Set the Display name to
Order Contains {@Product} - Set the Data type to Yes/No
- Select + Add parameter and configure the
Productparameter as follows:
| Setting | Value |
|---|---|
| Display name | Product |
| BRQL name | Product |
| Data type | Text |
| Value(s) | Single value |
| Required | Yes |
| Default value | None |
| Input mode | Choose from a drop-down list |
Enter the following expression to populate the drop-down with product titles from your store, sorted alphabetically:
SELECT DISTINCT [p.Title] FROM [$Products p] ORDER BY [p.Title]
- Select OK to save the parameter
- Enter the following expression in the custom field Expression section:
MAXB(IS_TRUE([$.ProductTitle] = [@Product])) OVER(PARTITION BY [$.OrderId])
- Select OK
How the expression works:
| Part | What it does |
|---|---|
[@Product] |
The parameter value — the product title selected when the report is run |
IS_TRUE([$.ProductTitle] = [@Product]) |
Returns true on any row where the product title matches the selected product |
MAXB(...) |
Propagates the true value across all rows in the partition — if any row is true , all rows become true |
OVER(PARTITION BY [$.OrderId]) |
Defines the partition as all line items sharing the same Order ID |
💡 The Order Contains @Product field can be added to other reports as a dimension or filter without rebuilding from scratch — it is reusable across any report rooted in Agreement Lines.
Step 3 — Filter by the selected products
To restrict the report to orders that contain the selected product:
- Select Add filter, choose Order Contains @Product
- In the parameter popup, select the product you want to analyse
- Select OK
The filter will be added as Order Contains [selected product] = TRUE . This keeps all line items from orders that contain the selected product and removes orders where the product does not appear.
The filter label above the report displays the selected product name once applied.
To learn more about adding filters, see Filter a report.
Step 4 — Sort the report
The report is sorted by descending date and order name by default, showing the most recent orders first. Adjust the sort if you prefer a different view — for example, sorting by order name groups all line items from the same order together, which can make basket composition easier to read. See Sorting and subtotals.
Step 5 — Save the report
Select Save as and save a copy of the report with a name such as Orders containing a specific product.
The parameter value is saved with the report but can be changed freely each time the report is opened without affecting the saved configuration.
Interpreting the results
Each row is a single line item. Rows are grouped implicitly by order through the sort, so you can read across the full basket for each qualifying order. Every order shown contains the selected product somewhere within it.
Useful patterns to look for:
- The selected product's own row — visible as one line among the others in each order. Its net sales, quantity, and discount values are reported at the line item level like any other row.
- Frequently co-purchased products — scan which product titles appear most often across qualifying orders. A product that consistently appears alongside the selected item is a strong candidate for bundling or cross-sell placement. For a structured frequency view, use the co-purchase frequency variation below.
- Single-line orders — orders where the selected product is the only line item. A high proportion of single-line orders may indicate a missed bundling or recommendation opportunity — consider whether a post-purchase or cart upsell would be appropriate.
- Order value distribution — orders containing the selected product may skew higher or lower in total value than your store average. A consistent skew toward high-value baskets suggests the product attracts strong buyers; a skew toward low-value baskets may indicate it is purchased as a standalone low-cost item.
Variations and extensions
Identify orders containing any product from a set
To match orders that contain any product from a selected list — useful for a product range, a campaign group, or a collection — create a new version of the field using a multi-value parameter and an IN comparison.
This requires a different parameter configuration from the single-product version. When creating the field, set Value(s) to Multiple values and use the same drop-down list expression as the base field. Set the display name to Order Contains @Products .
| Setting | Value |
|---|---|
| Display name | Products |
| BRQL name | Products |
| Data type | Text |
| Value(s) | Multiple values |
| Required | Yes |
| Input mode | Choose from a drop-down list |
With the parameter configured for multiple values, use the following custom field expression:
MAXB(IS_TRUE([$.ProductTitle] IN (SELECT VALUE FROM [@Products]))) OVER(PARTITION BY [$.OrderId])
The IN (SELECT VALUE FROM [@Products]) syntax is required when a parameter accepts multiple values — it evaluates each selected value in turn rather than treating the selection as a single input. Any qualifying order containing at least one of the selected products will be included.
Analyse orders by customer across all order history
To evaluate which customers have ever ordered a product and see their full purchase history across all orders — useful for B2B accounts or VIP customer review — change the partition from Order Id to Customer Id. The parameter configuration remains the same as the base field.
Replace the expression from Step 2 with:
MAXB(IS_TRUE([$.ProductTitle] = [@Product])) OVER(PARTITION BY [$.CustomerId])
This returns true on every line item belonging to a customer who has ordered the selected product at any point, across all their orders — not just the order in which the product appeared. Add Customer email or Customer Id as a dimension and sort by customer to group each customer's full order history together.
Summarise co-purchased products by frequency
The base report shows every order in full, which is useful for reviewing individual baskets but makes it hard to see overall patterns across many orders. To identify which products are most commonly purchased alongside the selected product, remove the order-level dimensions and aggregate the results by product title.
Remove the following fields from the report:
| Field | Reason |
|---|---|
| Order name | Order-level identifier — not needed for an aggregated view |
| Date | Order-level date — collapses away when aggregating |
| Customer name | Order-level detail — not relevant to product frequency |
If any of these fields are not present in your report, skip that row.
With these fields removed, each row in the report represents a product title rather than a single line item. Add the Total orders measure to the report to show the number of times each product was included in a distinct order.
Sort by descending Total orders. The selected product itself will appear at the top as every qualifying order in the report contained this product — the products ranked below it are its most common co-purchase companions, ordered by how frequently they share an order.
💡 This view answers a different question from the full order detail view: not what did a specific order contain, but across all qualifying orders, which products appear most often alongside the selected product. Consider saving it as a separate report alongside the base version rather than replacing it.
Need more support?
If you get stuck or have additional questions, you can contact our team directly through the Help widget in the bottom-right corner — we typically respond within one business day.