Skip to main content

How It Works

Understanding the execution model and data flow in Function Lab.

Architecture Overview

┌─────────────────┐
│  Shopify Cart   │
│   / Checkout    │
└────────┬────────┘


┌─────────────────┐
│  Shopify        │
│  Functions API  │
└────────┬────────┘


┌─────────────────┐
│  Function Lab   │
│  Rules Engine   │
└────────┬────────┘


┌─────────────────┐
│   Your Rules    │
│  Configuration  │
└────────┬────────┘


┌─────────────────┐
│  Discounts or   │
│  Customizations │
└─────────────────┘

Execution Phases

1. Input Processing

When a customer interacts with their cart or checkout, Shopify calls your Function Lab configuration with cart data: Input Structure:
{
  "cart": {
    "lines": [...],
    "buyerIdentity": {
      "customer": {...}
    },
    "deliveryGroups": [...]
  }
}
This input is parsed and made available for querying via conditions and facts.

2. Facts Computation

If your rules define facts, they’re evaluated first:
{
  "facts": {
    "total_items": "cart.lines[].quantity | sum(@)",
    "has_sale_items": "cart.lines[?merchandise.product.collections[?handle=='sale']] | length(@) > `0`"
  }
}
Facts are:
  • Computed once per rule execution
  • Available to all conditions and events
  • Cached for performance
  • Referenced with $ prefix: $total_items

3. Condition Evaluation

For each rule, conditions are evaluated against the input data and computed facts:
{
  "conditions": {
    "$total_items": { "gte": 5 },
    "customer.tags": { "includes": "VIP" }
  }
}
Evaluation Logic:
  • Multiple conditions = implicit AND (all must be true)
  • Array properties use ANY semantics (any element can match)
  • or operator for alternative conditions
  • not operator for negation
  • Short-circuit evaluation for performance
Result: true (fire events) or false (skip events)

4. Event Execution

When conditions match, events are executed to generate outputs:
{
  "events": [
    {
      "discount": "product_discount",
      "params": {
        "discount_type": "percentage",
        "value": 15,
        "message": "VIP Bulk Discount"
      }
    }
  ]
}
Event Processing:
  • Each event generates one or more discount/operation objects
  • Multiple events in a rule = multiple outputs
  • Parameterized events expand to multiple outputs
  • Events can reference facts for dynamic values

5. Output Assembly

All outputs from matching rules are collected and returned to Shopify: For Discounts:
{
  "discounts": [
    {
      "targets": [...],
      "value": { "percentage": { "value": "15" } },
      "message": "VIP Bulk Discount"
    }
  ],
  "discountApplicationStrategy": "FIRST"
}
For Customizations:
{
  "operations": [
    {
      "hide": {
        "deliveryOptionHandle": "expedited-shipping"
      }
    }
  ]
}

Rule Execution Order

Multiple rules are evaluated in order:
{
  "rules": [
    { /* Rule 1 - evaluated first */ },
    { /* Rule 2 - evaluated second */ },
    { /* Rule 3 - evaluated third */ }
  ]
}
Important:
  • All rules are evaluated independently
  • Facts are isolated per rule
  • Results from all matching rules are combined
  • Use discountApplicationStrategy to control how discounts stack

Discount Application Strategies

Control how multiple discounts combine:

FIRST (Default for most scenarios)

{
  "discountApplicationStrategy": "FIRST"
}
Only the first matching discount is applied. Use when discounts shouldn’t stack.

MAXIMUM

{
  "discountApplicationStrategy": "MAXIMUM"
}
Apply the largest discount found. Good for “best deal” scenarios.

ALL

{
  "discountApplicationStrategy": "ALL"
}
All matching discounts are applied (if Shopify allows stacking for the function type).

Performance Considerations

Efficient Condition Ordering

Place simple conditions first:
{
  "conditions": {
    "customer.tags": { "includes": "VIP" },  // Fast: simple lookup
    "$complex_calculation": { "gte": 100 }    // Slower: fact computation
  }
}

Fact Reuse

Calculate once, use everywhere: Inefficient:
{
  "rules": [
    {
      "conditions": {
        "cart.lines[?merchandise.product.vendor=='Acme'].quantity | sum(@)": { "gte": 5 }
      }
    }
  ]
}
Efficient:
{
  "rules": [
    {
      "facts": {
        "acme_quantity": "cart.lines[?merchandise.product.vendor=='Acme'].quantity | sum(@)"
      },
      "conditions": {
        "$acme_quantity": { "gte": 5 }
      }
    }
  ]
}

Selector Optimization

Use direct targeting when possible: Slower:
{
  "selector": "cart.lines[?merchandise.product.handle=='t-shirt'].id"
}
Faster:
{
  "handles": ["t-shirt"]
}

Shopify Integration

Function Types

Function Lab supports all Shopify Function types:
  • Product Discounts: Line item price adjustments
  • Order Discounts: Cart-level discounts
  • Shipping Discounts: Delivery cost adjustments
  • Delivery Customization: Show/hide/reorder shipping methods
  • Payment Customization: Control payment method availability
  • Cart Transform: Merge/update line items
Each has specific input/output schemas - see Function Types.

Metafield Access

Access custom data via metafields:
{
  "conditions": {
    "customer.metafields[?namespace=='custom' && key=='tier'].value": {
      "is": "gold"
    }
  }
}

GID Handling

Shopify IDs are Global IDs (GIDs):
gid://shopify/ProductVariant/12345678
Function Lab handles conversion automatically:
  • Accept numeric IDs: "variant_ids": [12345678]
  • Auto-converts to GIDs internally
  • Returns proper GID format to Shopify

Error Handling

Invalid Configuration

  • Rules with syntax errors are skipped
  • Logs show validation errors
  • Other rules continue executing

Runtime Errors

  • Fact computation errors return null
  • Selector errors skip that event
  • Functions fail safely (no discount rather than cart breakage)

Testing

Always test in Shopify admin preview mode before activating.

Next Steps

I