# Exporting Your Data

> Get bundle performance data out of Flex Bundles: CSV exports, the Analytics API, and order-level exports for warehouses and dashboards.

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](#csv-export) from the Analytics page |
| A recurring feed into a Sheet or dashboard | The [Analytics API](#the-analytics-api) |
| Unlimited history, order-level detail, warehouse loads | [Order metafields](#order-level-data) 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](https://flexbundles.com/docs/admin-api#analytics).

```bash
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.

```javascript
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_breakdown`** metafield: the bundles in the order with their revenue, units, and exact component variants and quantities.

```graphql
{
  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:

```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](https://shopify.dev/docs/api/usage/bulk-operations/queries) 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.count` divided by `orders_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_breakdown` records 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.
