Documentation
Exporting Your Data
Your bundle data belongs to you, and there are three ways to get it out of Flex Bundles depending on what you're building. All three draw on the same underlying records, so the numbers agree.
| You want | Use |
|---|---|
| A spreadsheet, right now | CSV export from the Analytics page |
| A recurring feed into a Sheet or dashboard | The Analytics API |
| Unlimited history, order-level detail, warehouse loads | Order metafields via Shopify's Admin API |
CSV Export
Choose a date range (and optionally a single bundle) on the Analytics page (Flex Bundles → Analytics) and click Export CSV. The file contains three sections: per-bundle totals (revenue, units, orders), per-component units within each bundle, and the AOV comparison between orders with and without bundles.
Any period with recorded data can be exported, so this is the quickest path when you just need the numbers in Excel or Google Sheets. Running the history import from the Analytics page loads orders back to when you installed Flex Bundles, plus roughly 90 days before that as a comparison baseline; the page shows the exact date your data starts.
The Analytics API
For anything recurring, GET /v1/analytics returns a daily series of bundle performance plus range totals as JSON. Full parameters and the response shape are documented in the Bundles Admin API.
curl "https://api.flexbundles.com/v1/analytics?start=2026-07-01&end=2026-07-31" \
-H "Authorization: Bearer fxb_your_api_key"
A small script on a schedule is all it takes to keep a dashboard fresh. For Google Sheets specifically, Google Apps Script works well: paste this into Extensions → Apps Script, add your API key, and set a daily trigger.
const KEY = "fxb_your_api_key"; // store in Script Properties in real use
function pullFlexBundlesAnalytics() {
const res = UrlFetchApp.fetch("https://api.flexbundles.com/v1/analytics", {
headers: { Authorization: "Bearer " + KEY },
});
const data = JSON.parse(res.getContentText());
const rows = [["Date", "Bundle", "Revenue", "Units", "Orders"]];
for (const day of data.days) {
for (const b of day.bundles) {
rows.push([day.date, b.title, b.revenue, b.units, b.orders]);
}
}
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Bundles");
sheet.clearContents();
sheet.getRange(1, 1, rows.length, rows[0].length).setValues(rows);
}
Retention is unlimited: once a day has data, it never expires. Coverage reaches back to your install date plus roughly 90 days as a baseline, and the response's earliest_available field gives the first day with data. A single request covers up to 366 days, so page by year for longer pulls.
Order-Level Data
The daily rollup is an aggregate. The full-fidelity record lives on your orders themselves, in your own store, readable with Shopify's Admin GraphQL API using a custom app token you control:
- Every order containing a Flex Bundles bundle is tagged
flex-bundles-has-bundle, so bundle orders are queryable in order search, admin filters, Segments, and Flow. - Each of those orders carries a
$app:bundle_breakdownmetafield: the bundles in the order with their revenue, units, and exact component variants and quantities.
{
orders(first: 50, query: "tag:flex-bundles-has-bundle created_at:>=2026-01-01") {
nodes {
id
name
createdAt
breakdown: metafield(namespace: "$app", key: "bundle_breakdown") {
value
}
}
}
}
The metafield value is JSON:
{
"v": 1,
"currency": "USD",
"source": "cart",
"bundles": [
{
"parentProductId": "gid://shopify/Product/10309675680045",
"title": "Hydration Kit",
"units": 2,
"revenue": 79.9,
"components": [
{
"productId": "gid://shopify/Product/10309675221293",
"variantId": "gid://shopify/ProductVariant/52199500808493",
"title": "Electrolyte Mix",
"variantTitle": "Citrus",
"qty": 4
}
]
}
]
}
This data persists for the life of the order, so it has no retention limit. For large date ranges, run the same query as a Shopify Bulk Operation to get a JSONL file you can load into a warehouse on a schedule.
What the Numbers Mean
- Revenue is the discounted total of the bundle's line items on each order, net of refunds.
- Units are whole bundles sold, not component items.
- Attach rate is the share of orders containing a bundle:
orders_with_bundles.countdivided byorders_with_bundles.count + orders_without_bundles.count. - AOV lift compares average order value between orders with and without bundles.
- There is no storefront conversion rate: Flex Bundles measures orders, not page views, so pair this data with your web analytics if you need funnel metrics.
- The CSV reports and the Analytics API are net of refunds (values shrink; order counts do not). Order-level
bundle_breakdownrecords describe what was sold at purchase time and are not modified by refunds; join against Shopify's refund data if you need net figures at the order level.