Order Data
Order data is a specialized data source type designed for the Recommendation Strip widget. Unlike traditional text-based data sources, order data uses structured CSV or JSON to store purchase history, enabling the AI to analyze buying patterns and generate intelligent product recommendations.
Order data sources are exclusively used with Recommendation Strip agents. They cannot be used with AI Assistant, Quiz, or Nudge agents, which require standard file uploads or website scrapes.
Upload Options
There are two ways to upload order data: Standard Upload (requires data in the exact schema format) and AI-Assisted Upload (automatically maps your fields).
Standard Upload (Recommended)
For maximum accuracy and full control over your data, use the Upload Order Data tab with data pre-formatted to match the schema documented below. Standard upload is recommended when:
- You need precise control over how your data is structured
- You want to include custom
metadatafields at order or product levels - You've already formatted your data to match our schema
- You need guaranteed accuracy for production use
AI-Assisted Upload
The AI-Assisted Upload option allows you to upload order data exports as-is from most e-commerce platforms. Our AI analyzes your file structure and automatically maps your fields to the required schema format. This is useful for quickly importing data without manual formatting.
Upload up to 3 CSV or JSON files, give your dataset a name, and let the AI transform your data. The AI identifies fields like order IDs, dates, product names, prices, and URLs—even if they use different column names than our schema.
AI-assisted mapping is not perfect. After processing, review your data in the Preview panel to ensure accuracy. Common issues to check:
- Product URLs: Verify
productPathvalues match your actual product page URLs - Prices: Confirm prices are correctly extracted and formatted
- Categories: Check that category assignments are accurate
- Thumbnail URLs: Ensure image URLs are valid and accessible
Correcting AI-Mapped Data
If you notice systematic errors in your AI-processed data (e.g., incorrect URL patterns), you have several options:
- Fix Source Data: Correct your original export file and re-upload using AI-Assisted Upload again
- Use Find & Replace: In spreadsheet software, use find and replace to fix URL patterns before uploading (e.g., replace
/p/with/products/) - Standard Upload: Pre-format your data to match the exact schema documented below and use the standard Upload tab
Import with Integration
If you have a connected integration (Shopify, BigCommerce, or WooCommerce), you can import order data directly from your store using the Import Data tab. This pulls your order history directly from the platform API and automatically converts it to the required schema format.
- Shopify: Imports orders via the Shopify Admin API
- BigCommerce: Imports orders via the BigCommerce API
- WooCommerce: Imports orders via the WooCommerce REST API
Integration imports are processed in the background. Once complete, you can preview the data, download it for review, and confirm the upload. This is the easiest way to get started if you have a supported e-commerce platform.
See the Integrations documentation for setup instructions for each platform.
Supported File Formats
Order data sources accept both CSV and JSON files. CSV files are automatically converted to JSON when uploaded. For standard uploads, your data must match the required schema format documented below.
CSV Format
CSV files work well for exports where each row represents one line item. Products with the same order ID will be automatically grouped into a single order.
orderId,orderDate,displayName,productPath,category,productCode,sku,thumbUrl,purchasePrice,orderValue,currency,quantityORD-12345,2024-01-15T10:30:00Z,Wireless Bluetooth Headphones,/products/wireless-headphones,Electronics,WBH-001,WBH-001-BLK,https://example.com/images/headphones.jpg,79.99,159.98,USD,1ORD-12345,2024-01-15T10:30:00Z,USB-C Charging Cable,/products/usb-c-cable,Electronics,USB-001,USB-001-WHT,https://example.com/images/cable.jpg,19.99,159.98,USD,2ORD-67890,2024-01-16T14:22:00Z,Running Shoes Pro,/products/running-shoes,Footwear,RS-500,RS-500-BLU,https://example.com/images/shoes.jpg,129.99,129.99,USD,1
Tip: Rows with the same orderId will be automatically grouped, with each row becoming a product in that order.
JSON Format
JSON format is ideal when your data is already structured with orders containing nested product arrays.
Example Structure
[{"orderId": "ORD-12345","orderDate": "2024-01-15T10:30:00Z","orderValue": "92.98","currency": "USD","metadata": { "source": "website", "campaign": "summer-sale" },"products": [{"displayName": "Wireless Bluetooth Headphones","productPath": "/products/wireless-headphones","category": "Electronics","productCode": "WBH-001","sku": "WBH-001-BLK","thumbUrl": "https://example.com/images/headphones.jpg","purchasePrice": "79.99","quantity": 1},{"displayName": "USB-C Charging Cable","productPath": "/products/usb-c-cable","category": "Accessories","productCode": "USBC-002","sku": "USBC-002-6FT","thumbUrl": "https://example.com/images/cable.jpg","purchasePrice": "12.99","quantity": 1,"metadata": { "variant": "6ft-white" }}]},{"orderId": "ORD-12346","orderDate": "2024-01-16T14:22:00Z","orderValue": "59.98","currency": "USD","products": [{"displayName": "Wireless Mouse","productPath": "/products/wireless-mouse","category": "Electronics","productCode": "WM-003","sku": "WM-003-WHT","thumbUrl": "https://example.com/images/mouse.jpg","purchasePrice": "29.99","quantity": 2}]}]
Required Fields
Every order and product must include the following fields:
Order Level
orderId— Unique identifier for the order (string)orderDate— Order date in ISO 8601 format (string)orderValue— Total order value as a string (e.g., "129.99" or "1299")currency— ISO 4217 currency code (3-letter uppercase, e.g., "USD", "EUR", "GBP")products— Array of product objects (at least one required)metadata— Optional object for custom fields (e.g., source, campaign)
The currency field accepts standard ISO 4217 currency codes. Common codes include: USD (US Dollar), EUR (Euro), GBP (British Pound), JPY (Japanese Yen), AUD (Australian Dollar), CAD (Canadian Dollar), CHF (Swiss Franc), CNY (Chinese Yuan), INR (Indian Rupee), BRL (Brazilian Real), and many more.
Product Level
displayName— Product name shown in the recommendation stripproductPath— URL path to the product page (e.g., "/products/my-item")category— Product category (used for recommendation grouping)productCode— Parent product identifiersku— Specific variant SKUthumbUrl— URL to a 1:1 aspect ratio product thumbnailpurchasePrice— Unit price as a string (e.g., "29.99" or "$29.99")quantity— Number of units purchased (integer, minimum 1)metadata— Optional object for custom fields (e.g., variant info)
Data Requirements
For optimal recommendation quality, ensure your order data meets these guidelines:
- Minimum Orders: At least 1,000 orders recommended for accurate pattern detection
- History Depth: Include at least 3 months of order history
- Valid Orders Only: Exclude cancelled, refunded, or incomplete orders
- Consistent Categories: Use standardized category names across all products
- Valid URLs: Ensure all product and thumbnail URLs are accessible
- Duplicate Prevention: Orders with duplicate
orderIdvalues are automatically skipped during processing, so you can safely re-upload files without creating duplicate entries
Automatic Order Capture
In addition to manual file uploads, you can automatically capture order data from your store's confirmation page using the embedded widget's JavaScript API. This keeps your data source continuously updated with new purchases.
Using the addOrder API
The window.badgerfyai.addOrder() method allows you to submit order data directly from your order confirmation page:
// Call this on your order confirmation pagewindow.badgerfyai.addOrder('YOUR_DATASOURCE_ID', {orderId: 'ORD-12345',orderDate: new Date().toISOString(),orderValue: '79.99',currency: 'USD',metadata: { source: 'website' },products: [{displayName: 'Wireless Bluetooth Headphones',productPath: '/products/wireless-headphones',category: 'Electronics',productCode: 'WBH-001',sku: 'WBH-001-BLK',thumbUrl: 'https://yourstore.com/images/headphones.jpg',purchasePrice: '79.99',quantity: 1}]}).then(result => {if (result.success) {console.log('Order submitted successfully');} else {console.error('Failed to submit order:', result.message);}});
The addOrder() method requires your order data source ID (encoded). You can find this ID in your data source settings in the dashboard.
API Response
The addOrder() method returns a promise that resolves to an object with the following properties:
success— Boolean indicating if the order was queuedmessage— Human-readable status messageerrors— Array of validation errors (if applicable)
Validation
Orders are validated before submission. Common validation errors include:
- Missing required fields (orderId, orderDate, orderValue, currency, products)
- Empty products array
- Invalid thumbnail URL format
- Invalid or negative purchase price or order value
- Invalid or missing quantity (must be at least 1)
- Invalid currency code (must be a valid ISO 4217 3-letter code like USD, EUR, GBP)
Consumer API
For bulk uploads and automated data pipelines, Pro and Business plan users can upload order data programmatically using the Consumer API. This is ideal for syncing large batches of historical orders or integrating with your backend systems.
The Consumer API is available on Pro and Business plans only. Basic plan users can use the dashboard file upload or the addOrder() widget method.
Both dashboard and API uploads require data in the exact schema format documented above. Ensure your JSON matches the required field names and structure for successful processing.
The API supports both creating new order data and updating existing datasets with zero downtime—your recommendation strips continue using the current data until new uploads are fully processed.
See the Consumer API documentation for complete endpoint details, authentication, and example automation scripts.
Storage Management
Order data counts toward your plan's storage limits. As your order history grows, you may need to manage storage to stay within your plan's allocation.
Plan Storage Limits
- Basic Plan: 50MB maximum total storage
- Pro Plan: 100MB maximum total storage
- Business Plan: 500MB maximum total storage
Clearing Old Orders
To free up storage space, you can periodically remove older order data using the Clear Storage Options button on the data source upload page. This allows you to:
- Remove orders older than a specified date
- Clear all order data and start fresh
- Delete specific order files while keeping others
We recommend keeping 6–12 months of order history for optimal recommendations. Orders older than this typically have diminishing impact on recommendation quality and can be safely cleared to free up storage.
Platform Integration Guides
The following examples demonstrate how to extract order data from popular e-commerce platforms and transform it to the required format. These scripts can be run as scheduled jobs to keep your order data synchronized.
Shopify
Use Shopify's Admin API to fetch orders and map them to the required format. You'll need to create a custom app with read_orders and read_products scopes.
// Shopify order data extractionconst SHOPIFY_STORE = 'your-store.myshopify.com';const ACCESS_TOKEN = process.env.SHOPIFY_ACCESS_TOKEN;async function fetchShopifyOrders(sinceDate) {const url = `https://${SHOPIFY_STORE}/admin/api/2024-01/orders.json?status=any&created_at_min=${sinceDate}&limit=250`;const response = await fetch(url, {headers: { 'X-Shopify-Access-Token': ACCESS_TOKEN }});const { orders } = await response.json();return orders;}async function fetchProductDetails(productId) {const url = `https://${SHOPIFY_STORE}/admin/api/2024-01/products/${productId}.json`;const response = await fetch(url, {headers: { 'X-Shopify-Access-Token': ACCESS_TOKEN }});const { product } = await response.json();return product;}async function mapShopifyOrders(orders) {const productCache = new Map();const mappedOrders = [];for (const order of orders) {// Skip cancelled/refunded ordersif (order.cancelled_at || order.financial_status === 'refunded') continue;const products = [];for (const item of order.line_items) {// Fetch product details for URL and image (with caching)let product = productCache.get(item.product_id);if (!product) {product = await fetchProductDetails(item.product_id);productCache.set(item.product_id, product);}products.push({displayName: item.title,productPath: `/products/${product?.handle || item.product_id}`,category: item.vendor || product?.product_type || 'Uncategorized',productCode: String(item.product_id),sku: item.sku || String(item.variant_id),thumbUrl: product?.image?.src || '',purchasePrice: item.price,quantity: item.quantity});}if (products.length > 0) {mappedOrders.push({orderId: order.name, // e.g., "#1001"orderDate: order.created_at,orderValue: order.total_price,currency: order.currency, // e.g., "USD", "EUR"products});}}return mappedOrders;}
- Use pagination (
page_info) for stores with 250+ orders - Cache product details to avoid rate limits (40 requests/second)
- Consider using GraphQL Bulk Operations for large historical exports
BigCommerce
BigCommerce provides order data through their V2/V3 APIs. Create an API account in your store's control panel under Settings → API Accounts with Orders and Products read permissions.
// BigCommerce order data extractionconst STORE_HASH = process.env.BC_STORE_HASH;const ACCESS_TOKEN = process.env.BC_ACCESS_TOKEN;async function fetchBigCommerceOrders(minDateCreated) {const url = `https://api.bigcommerce.com/stores/${STORE_HASH}/v2/orders?min_date_created=${minDateCreated}&status_id=11`; // 11 = Completedconst response = await fetch(url, {headers: {'X-Auth-Token': ACCESS_TOKEN,'Accept': 'application/json'}});return response.json();}async function fetchOrderProducts(orderId) {const url = `https://api.bigcommerce.com/stores/${STORE_HASH}/v2/orders/${orderId}/products`;const response = await fetch(url, {headers: {'X-Auth-Token': ACCESS_TOKEN,'Accept': 'application/json'}});return response.json();}async function fetchProductDetails(productId) {const url = `https://api.bigcommerce.com/stores/${STORE_HASH}/v3/catalog/products/${productId}?include=images`;const response = await fetch(url, {headers: {'X-Auth-Token': ACCESS_TOKEN,'Accept': 'application/json'}});const { data } = await response.json();return data;}async function mapBigCommerceOrders(orders) {const productCache = new Map();const mappedOrders = [];for (const order of orders) {const orderProducts = await fetchOrderProducts(order.id);const products = [];for (const item of orderProducts) {let product = productCache.get(item.product_id);if (!product) {product = await fetchProductDetails(item.product_id);productCache.set(item.product_id, product);}const thumbnail = product?.images?.find(img => img.is_thumbnail) || product?.images?.[0];products.push({displayName: item.name,productPath: product?.custom_url?.url || `/products/${item.product_id}`,category: product?.categories?.[0]?.toString() || 'Uncategorized',productCode: String(item.product_id),sku: item.sku,thumbUrl: thumbnail?.url_thumbnail || '',purchasePrice: String(item.base_price),quantity: item.quantity});}if (products.length > 0) {mappedOrders.push({orderId: String(order.id),orderDate: new Date(order.date_created).toISOString(),orderValue: String(order.total_inc_tax),currency: order.currency_code, // e.g., "USD", "EUR"products});}}return mappedOrders;}
- Filter by
status_idto include only completed orders - Fetch category names separately via the Categories API if needed
- Use V3 API for products (includes images) and V2 for orders
Adobe Commerce (Magento 2)
Adobe Commerce exposes order data through its REST API. Generate an integration token in System → Integrations with access to Sales and Catalog resources.
// Adobe Commerce (Magento 2) order data extractionconst MAGENTO_URL = process.env.MAGENTO_BASE_URL;const ACCESS_TOKEN = process.env.MAGENTO_ACCESS_TOKEN;async function fetchMagentoOrders(fromDate) {const searchCriteria = encodeURIComponent(`searchCriteria[filter_groups][0][filters][0][field]=created_at&` +`searchCriteria[filter_groups][0][filters][0][value]=${fromDate}&` +`searchCriteria[filter_groups][0][filters][0][condition_type]=gteq&` +`searchCriteria[filter_groups][1][filters][0][field]=status&` +`searchCriteria[filter_groups][1][filters][0][value]=complete&` +`searchCriteria[pageSize]=100`);const url = `${MAGENTO_URL}/rest/V1/orders?${searchCriteria}`;const response = await fetch(url, {headers: { 'Authorization': `Bearer ${ACCESS_TOKEN}` }});const { items } = await response.json();return items;}async function fetchProductBySku(sku) {const url = `${MAGENTO_URL}/rest/V1/products/${encodeURIComponent(sku)}`;const response = await fetch(url, {headers: { 'Authorization': `Bearer ${ACCESS_TOKEN}` }});return response.json();}async function fetchCategoryName(categoryId) {const url = `${MAGENTO_URL}/rest/V1/categories/${categoryId}`;const response = await fetch(url, {headers: { 'Authorization': `Bearer ${ACCESS_TOKEN}` }});const category = await response.json();return category.name;}async function mapMagentoOrders(orders) {const productCache = new Map();const categoryCache = new Map();const mappedOrders = [];for (const order of orders) {const products = [];// Filter to simple/configurable products onlyconst validItems = order.items.filter(item =>['simple', 'configurable'].includes(item.product_type));for (const item of validItems) {let product = productCache.get(item.sku);if (!product) {product = await fetchProductBySku(item.sku);productCache.set(item.sku, product);}// Get first category namelet categoryName = 'Uncategorized';const categoryIds = product?.custom_attributes?.find(attr => attr.attribute_code === 'category_ids')?.value;if (categoryIds?.[0]) {if (!categoryCache.has(categoryIds[0])) {categoryCache.set(categoryIds[0], await fetchCategoryName(categoryIds[0]));}categoryName = categoryCache.get(categoryIds[0]);}// Build thumbnail URLconst thumbnail = product?.custom_attributes?.find(attr => attr.attribute_code === 'thumbnail')?.value;const thumbUrl = thumbnail? `${MAGENTO_URL}/media/catalog/product${thumbnail}`: '';products.push({displayName: item.name,productPath: `/${product?.custom_attributes?.find(attr => attr.attribute_code === 'url_key')?.value || item.sku}.html`,category: categoryName,productCode: String(item.product_id),sku: item.sku,thumbUrl,purchasePrice: String(item.price),quantity: item.qty_ordered});}if (products.length > 0) {mappedOrders.push({orderId: order.increment_id,orderDate: new Date(order.created_at).toISOString(),orderValue: String(order.grand_total),currency: order.order_currency_code, // e.g., "USD", "EUR"products});}}return mappedOrders;}
- Use search criteria to filter by date and order status
- Product attributes like
url_keyandthumbnailare incustom_attributes - Consider async/batch processing for large catalogs
- Media URLs follow the pattern:
{base_url}/media/catalog/product{path}
Integration Best Practices
- Rate Limiting: Add delays between API calls to respect platform rate limits. Use exponential backoff for retries.
- Caching: Cache product details to minimize API calls—products rarely change between order syncs.
- Incremental Sync: Track the last sync date and only fetch new orders since then, rather than the full history each time.
- Error Handling: Log failed orders and retry them separately. Don't let one bad order block the entire sync.
- Scheduling: Run syncs during off-peak hours to minimize impact on your store's performance.
Best Practices
- Automate Capture: Implement the
addOrder()call on your order confirmation page to continuously build your dataset - Quality Thumbnails: Use high-quality, consistently-sized square images (1:1 aspect ratio) for the best visual presentation
- Standardize Categories: Use consistent, lowercase category names to improve recommendation grouping
- Regular Maintenance: Schedule periodic storage reviews to clear old orders and maintain optimal performance
- Test Integration: Test your
addOrder()integration in a development environment before deploying to production