Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.elasticfunnels.io/llms.txt

Use this file to discover all available pages before exploring further.

ElasticFunnels provides two ways to display order information on your pages: the <order> HTML tag (for the visual builder) and backend functions like getOrders() / getOrder() / getSessionOrders() / getPurchasedProducts() for code-based pages. Both retrieve data from the customer’s purchase history.

Two Approaches

ApproachBest forUsed in
<order> tagVisual builder pages, simple layoutsDrag-and-drop editor
getOrders() / getOrder()Code-based pages, full order historyBackend scripts / .ef pages
getSessionOrders()Thank-you pages — current purchase onlyBackend scripts / .ef pages
getPurchasedProducts()Member-area “library” pages — purchased products with their bonuses + downloadsBackend scripts / .ef pages
For a member-area page that needs each purchased product with its included bonuses and download links, prefer getPurchasedProducts() over manually joining getOrders() + getAllProducts() + getBonusProducts() on the client. It returns a flat list with same-order bonuses already attached and a pre-rolled-up downloads[] array (each entry tagged with kind). See the data-functions reference and the “My Library” pattern for examples.

Using the <order> Tag

The <order> tag is processed server-side and automatically loops through the customer’s purchase history. See the full Order Tag reference for all placeholders and options.
<order sort-by="newest" limit="5">
  <h3>Order #{order_number}</h3>
  <p>Date: {order_date}</p>
  <p>Shipping: {shipping_address}</p>

  <order-product>
    <img src="{product_image_url}" alt="{product_name}" />
    <p>{product_name} — {price}</p>
  </order-product>

  <order-bonus-product>
    <p>Bonus: {bonus_product_name}</p>
    <a href="{bonus_download}">Download</a>
  </order-bonus-product>
</order>

Using getOrders() in Backend Scripts

For code-based pages (.ef files or pages with backend scripts), getOrders() gives you full control over the layout. It returns an array of order objects you can loop through with @foreach.

Basic Usage

<script scope="backend">
var orders = getOrders('newest', 10);
setVariable('orders', orders);
</script>

@if(orders.length gt 0)
  @foreach(order in orders)
  <div class="order-card">
    <h3>Order #{{ order.order_number }}</h3>
    <p>{{ order.created_at | date:'dd, MMM yyyy' }}</p>

    @foreach(product in order.products)
    <div class="product-row">
      <img src="{{ product.image_url }}" alt="{{ product.name }}" />
      <span>{{ product.name }}</span>
      <span>{{ product.price | formatPrice:product.currency_code }}</span>
    </div>
    @endforeach
  </div>
  @endforeach
@else
  <p>No orders found.</p>
@endif

Parameters (getOrders)

ParameterTypeDefaultDescription
sortBystring'newest'Sort order: 'newest' or 'oldest'
limitnumber50Maximum number of orders to return (max 1000)

Alternative: Inline Call

You can also call getOrders() directly in a @set directive without a backend script block:
@set(orders = getOrders('newest', 5))

@foreach(order in orders)
  <p>#{{ order.order_number }} — {{ order.created_at | date:'dd MMM yyyy' }}</p>
@endforeach

Using getOrder() for a Single Order Detail Page

When you already know which order to show, use getOrder(code) instead of loading the full order list and searching manually. This is ideal for pages like /members-order?order=EF-12345. getOrder() uses the same customer/session scope as getOrders(), so it only returns orders that belong to the currently logged-in customer for that brand.

Example: Single order page

<script scope="backend">
var code = request.query.order;
var order = getOrder(code);
setVariable('order', order);
</script>

@if(order)
  <h1>Order #{{ order.order_number }}</h1>
  <p>{{ order.created_at | date:'dd MMM yyyy' }}</p>

  @foreach(product in order.products)
  <div>
    <span>{{ product.name }}</span>
    <span>{{ product.price | formatPrice:product.currency_code }}</span>
  </div>
  @endforeach
@else
  <p>Order not found.</p>
@endif

What code can be

getOrder(code) matches any of these values within the current customer’s orders:
  • order_number / public order ID
  • internal order_id
  • conversion code

Parameters

ParameterTypeRequiredDescription
codestringYesPublic order ID, internal order ID, or conversion code to match
For an order detail page, prefer getOrder(request.query.order) over getOrders() plus a manual loop/filter. It is shorter, clearer, and communicates intent directly.

Fulfillment status and shipments

Use getOrderFulfillment(code) on an order detail page to show 3PL fulfillment status and timestamps. Responses are allowlisted (no raw provider payloads). Use getOrderFulfillments() with no arguments to list every tracking row across all of the customer’s orders—each row includes order_number so you can link to /members-order?order=…. For a single order, order.tracking from getOrder / getOrders is often enough for carrier links. The fulfillment helpers add lifecycle status (getOrderFulfillment) and a cross-order shipment list (getOrderFulfillments).

Example: order detail with fulfillment summary

<script scope="backend">
var code = request.query.order;
setVariable('order', getOrder(code));
setVariable('fulfillment', getOrderFulfillment(code));
</script>

@if(fulfillment)
  <p>Fulfillment: {{ fulfillment.status }}</p>
  @if(fulfillment.sent_at)
    <p>Sent: {{ fulfillment.sent_at | date:'dd MMM yyyy' }}</p>
  @endif
@endif

Example: all shipments for the account

<script scope="backend">
setVariable('shipments', getOrderFulfillments());
</script>

@if(shipments.length gt 0)
  @foreach(row in shipments)
  <div>
    <a href="/members-order?order={{ row.order_number }}">Order #{{ row.order_number }}</a>
    — {{ row.carrier }}: <a href="{{ row.tracking_url }}" target="_blank" rel="noopener">{{ row.tracking_number }}</a>
  </div>
  @endforeach
@endif

Order Object Structure

Each order returned by getOrders() or getOrder() contains:
{
  order_number: "EF-12345",        // Public order ID
  created_at: "2026-03-15T...",    // ISO date string
  currency: "USD",                 // Order currency code

  // Billing address
  billing_address: "123 Main St",
  billing_city: "New York",
  billing_state: "NY",
  billing_zip: "10001",
  billing_country: "US",

  // Shipping address
  shipping_address: "123 Main St",
  shipping_address2: "",
  shipping_city: "New York",
  shipping_state: "NY",
  shipping_zip: "10001",
  shipping_country: "US",

  // Customer info
  customer_name: "John Doe",
  customer_email: "john@example.com",

  // Products array
  products: [
    {
      name: "Premium Course",
      image_url: "https://...",
      price: 97.00,
      quantity: 1,
      currency_code: "USD",
      is_bonus: false
    }
  ],

  // Tracking array (if fulfilled)
  tracking: [
    {
      tracking_number: "9400111899223456789012",
      tracking_url: "https://t.17track.net/en#nums=...",
      carrier: "USPS"
    }
  ]
}

Displaying Tracking Information

If your orders have physical shipments, tracking information is automatically extracted from fulfillment data. The system checks multiple sources for tracking numbers:
  1. Direct conversion fields (tracking_number, tracking_url)
  2. Fulfillment provider response data
  3. Fulfillment order data
Carriers are auto-detected from tracking number patterns (USPS, FedEx, UPS, DHL, UniUni). If no tracking URL is provided, a universal tracking link via 17track.net is generated. order.tracking is always an array. When the order has not yet been fulfilled it is empty ([]). Use order.shipping_address as the signal that the order contains a physical product — if there is a shipping address but no tracking yet, show a “being processed” message.

Example: Physical order with processing/tracking states

@set(orders = getOrders('newest', 5))

@foreach(order in orders)
<div class="order">
  <h3>Order #{{ order.order_number }}</h3>
  <p>{{ order.created_at | date:'dd MMM yyyy' }}</p>

  @if(order.shipping_address)
  <div class="shipping-address">
    <h4>Ships to</h4>
    <p>{{ order.shipping_address }}</p>
    <p>{{ order.shipping_city }}, {{ order.shipping_state }} {{ order.shipping_zip }}</p>
    <p>{{ order.shipping_country }}</p>
  </div>

  @if(order.tracking.length gt 0)
  <div class="tracking-info">
    <h4>Shipment Tracking</h4>
    @foreach(t in order.tracking)
    <div class="tracking-row">
      <span>{{ t.carrier }}</span>
      <a href="{{ t.tracking_url }}" target="_blank">{{ t.tracking_number }}</a>
    </div>
    @endforeach
  </div>
  @else
  <div class="tracking-pending">
    <p>Your order is being processed. Tracking information will appear here once your order ships.</p>
  </div>
  @endif

  @endif
</div>
@endforeach
The key pattern:
  • order.shipping_address is present → physical product → show the shipping address block.
  • Inside that block, order.tracking.length gt 0 → shipment is on the way → show carrier + tracking link.
  • Otherwise → show “Your order is being processed.”
Tracking numbers are auto-linked to 17track.net when no carrier URL is provided. The carrier is auto-detected from the number pattern (USPS, UPS, FedEx, DHL, UniUni). You do not need to map carriers yourself.

getSessionOrders() — Current Session Orders

getSessionOrders() returns only the orders that were placed during the current browser session. Unlike getOrders(), which returns the full purchase history for a customer, getSessionOrders() is scoped to the active checkout session — making it the right choice for thank-you pages where you only want to show what was just bought. By default it returns all orders from the current session. Pass an optional limit to cap the count.

Parameters (getSessionOrders)

ParameterTypeDefaultDescription
sortBystring'newest'Sort order: 'newest' or 'oldest'
limitnumber(all)Maximum number of orders to return; omit to return all session orders

Basic Usage

@set(orders = getSessionOrders())

@foreach(order in orders)
<div class="order-summary">
  <p>Order #{{ order.order_number }}</p>
  @foreach(product in order.products)
  <div>{{ product.name }} — {{ product.price | formatPrice:product.currency_code }}</div>
  @endforeach
</div>
@endforeach
Prefer getSessionOrders() over getOrders('newest', 1) on thank-you pages. A customer with an existing purchase history could see a previous order with getOrders if the new conversion hasn’t been indexed yet. getSessionOrders() is scoped to the current session so it only shows what was just purchased.

Thank You Pages

Thank-you pages are a natural place to show order details. Since the customer is auto-authenticated from checkout, order data is available immediately. Use getSessionOrders() on thank-you pages so that only the orders from the current checkout session are shown — not the customer’s full history.

Example: Thank You Page with Order Summary

@set(orders = getSessionOrders())

<h2>Order Confirmed!</h2>
<p>Thank you for your purchase.</p>

@if(orders.length gt 0)
  @foreach(order in orders)
  <div class="order-summary">
    <p>Order #{{ order.order_number }}</p>
    <p>Date: {{ order.created_at | date:'dd, MMM yyyy' }}</p>

    @foreach(product in order.products)
    <div class="product">
      <span>{{ product.name }}</span>
      <span>{{ product.price | formatPrice:product.currency_code }}</span>
    </div>
    @endforeach
  </div>
  @endforeach
@else
  <div class="processing">
    <p>Your order is still being processed. This page will refresh automatically.</p>
  </div>
@endif

<a href="/members">Access Member Area</a>
If the order hasn’t been indexed yet when the thank-you page loads, getSessionOrders() may return empty. Add a JavaScript auto-refresh timer so the page retries after a few seconds — the order typically appears within 5–10 seconds.

Customer Data Outside of Orders

You can also display customer information directly using the customer template object (populated from the session):
<p>Welcome back, {{ customer.name|default:"Member" }}!</p>
<p>Email: {{ customer.email }}</p>
The customer object includes: name, email, first_name, last_name, phone, order_id, order_ids, and full billing/shipping address fields. It is automatically available in every backend script and template — no function call needed.

Order Grouping

Orders are grouped intelligently — multiple conversions from the same purchase session (e.g., a main product and an upsell bought in the same checkout flow) are combined into a single order. The grouping logic uses:
  • Session ID matching — Conversions from the same browser session
  • Time proximity — Conversions within 6 hours of each other
This means an upsell purchased immediately after the main product shows under the same order, not as a separate entry.

Order Tag Reference

Full reference for the <order> HTML tag and all placeholders

Backend Scripts

Learn about backend scripts and available functions

Template Engine Syntax

Filters, conditionals, and loops for displaying data

Thank You Pages

Best practices for post-purchase confirmation pages