> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usecharlie.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Performance Routing

> Rank locations into performance tiers by an analytics metric, starting with average time to ship, and route to your best performers first

Performance routing ranks your locations into tiers based on a performance metric and sends orders to your best performers first. The first available metric is **average time to ship** — how quickly each location fulfills its orders — so you can steer orders toward the locations that ship fastest.

<Info>
  This rule is called the **Analytics metric location rule** in Shopify's Order Routing settings. It's a routing rule — a soft signal that ranks locations — not a constraint, so it never blocks a location from fulfilling.
</Info>

## How performance routing works

Charlie measures each location's **average time to ship** over a rolling 7-day window and stores it as a per-location snapshot. The rule reads that snapshot and sorts your locations into the performance tiers you define:

```
Matches an earlier tier → Higher rank
```

You build an ordered list of tiers. Each tier is a condition like "time to ship is less than 24 hours." A location takes the rank of the **first tier its metric satisfies** — so the order of your tiers is how you express best-to-worst.

```mermaid theme={"system"}
flowchart TD
    A[Order placed] --> B[Read each location's<br/>average time to ship]
    B --> C{First tier the<br/>location matches?}
    C -->|Under 24h| D[Tier 1 → Rank 1]
    C -->|Under 48h| E[Tier 2 → Rank 2]
    C -->|No tier| F[Ranked last]
    D --> G[Try the fastest tier first]
```

<Note>
  Average time to ship is measured over a rolling 7-day window and **excludes instant fulfillments** — such as in-store POS sales that ship immediately — so the metric reflects genuine fulfillment speed.
</Note>

## Setup overview

Performance routing takes two steps:

1. **Add the Analytics metric location rule** in Shopify Order Routing
2. **Configure the performance tiers** on the rule

## Step 1: Add the routing rule in Shopify

<Steps>
  <Step title="Open Order routing">
    Go to **Charlie → Settings → Order routing** or **Shopify → Settings → Shipping and delivery → Order routing**.
  </Step>

  <Step title="Add the Analytics metric location rule">
    Find Charlie's **Analytics metric location rule** in the available rules list and add it to your routing strategy.
  </Step>
</Steps>

## Step 2: Configure performance tiers

Open the rule to configure it.

<Steps>
  <Step title="Enable the rule">
    In the **Status** section, switch the rule to **Enabled**. While it's disabled, the rule has no effect on routing and you can edit it freely.
  </Step>

  <Step title="Add a tier">
    Click **Add tier**. Each tier is a single condition made of three parts:

    | Part                         | Description                                                                                                     |
    | ---------------------------- | --------------------------------------------------------------------------------------------------------------- |
    | **Metric**                   | The performance metric to rank by. Currently **Time to ship**.                                                  |
    | **Operator**                 | How to compare — Greater than, Less than, Equal to, Greater than or equal, Less than or equal, or Not equal to. |
    | **Max time to ship (hours)** | The threshold, in **whole hours** (minimum 1).                                                                  |
  </Step>

  <Step title="Order your tiers">
    Tiers are evaluated **top to bottom** and the first match wins, so put your most-preferred tier first. Use the **⋯** menu on each row to **Move up**, **Move down**, or **Delete**. You can add up to **10 tiers**.
  </Step>

  <Step title="Save">
    Save the rule. Your tiers are kept in order and the rule starts ranking locations on the next order.
  </Step>
</Steps>

<Tip>
  Charlie shows your network's current spread — for example, "Your locations currently range from 6h to 72h average time to ship" — right above the tiers, so you can choose thresholds that actually split your locations into meaningful groups.
</Tip>

## How ranking works

### First match wins

Tiers are checked in the order you arrange them. A location is placed in the **first tier whose condition it satisfies**, and tiers are not auto-sorted — the order you set is the priority order.

| Location    | Avg time to ship | First matching tier    | Rank    |
| ----------- | ---------------- | ---------------------- | ------- |
| Warehouse A | 8h               | Tier 1 (less than 24h) | 1 (top) |
| Store Paris | 30h              | Tier 2 (less than 48h) | 2       |
| Store Lyon  | 60h              | Tier 3 (less than 72h) | 3       |
| Store Nice  | 120h             | none                   | last    |

### Locations that match no tier

A location whose metric satisfies **none** of your tiers is **ranked last**. A location with no measured time to ship yet — for example, one that hasn't shipped anything recently — is also ranked last until it has data.

### When the rule stays out of the way

If no location matches any tier, the rule emits **no ranking at all**, so it won't flatten the order produced by your other routing rules. The same is true when the rule is disabled or has no tiers configured.

## Combining with other rules

### With Inventory Rules

1. **Inventory Rules** — Rank by available stock
2. **Performance routing** — Among in-stock locations, prefer the fastest shippers

**Result:** Orders go to locations that both have the inventory and ship quickly.

### With Ranked Location Groups

1. **Ranked Location Groups** — Warehouses (Group 1) → Stores (Group 2)
2. **Performance routing** — Within each group, prefer the faster locations

### With Backlog Routing

Performance and backlog answer different questions:

| Signal          | Question                                        |
| --------------- | ----------------------------------------------- |
| **Performance** | How fast does this location ship, historically? |
| **Backlog**     | How many orders is it sitting on right now?     |

Use both to prefer locations that are both fast and not currently overwhelmed.

## Where the metric comes from

Charlie computes each location's average time to ship from your fulfillment analytics over a rolling 7-day window and stores it on the location as a private app metafield:

| Metafield                                | Type            | Description                            |
| ---------------------------------------- | --------------- | -------------------------------------- |
| `$app:location.time_to_ship_avg_minutes` | number\_integer | 7-day average time to ship, in minutes |

<Note>
  This metafield is **app-private** — it powers the routing rule and the in-app range hint, but it isn't exposed to your storefront or other apps.
</Note>

### How fresh the data is

The snapshot updates **as your locations ship orders**. Each fulfillment shifts the rolling average, so Charlie recomputes shortly after — new ship-time data is typically reflected within a couple of minutes. To avoid excess work on busy stores, recomputes are debounced to at most once every 15 minutes per shop. If a recompute can't run, the last good snapshot is kept, so the rule never falls back to ranking on missing data.

## Best practices

<CardGroup cols={2}>
  <Card title="Build tiers fastest-first" icon="arrow-down-1-9">
    Put your tightest threshold (for example, under 24h) at the top so your quickest locations earn the top rank.
  </Card>

  <Card title="Use the range hint" icon="ruler">
    Pick thresholds from the range Charlie shows above the tiers so each tier actually separates your locations.
  </Card>

  <Card title="Pair with inventory" icon="warehouse">
    Combine with Inventory Rules so speed only decides among locations that can actually fulfill.
  </Card>

  <Card title="Let new locations warm up" icon="hourglass-start">
    A location needs recent shipments before it has a time-to-ship value — until then it ranks last under this rule.
  </Card>
</CardGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Orders aren't shifting toward faster locations">
    **Check:**

    1. Is the **Analytics metric location rule** enabled in Shopify Order Routing?
    2. Do your tiers actually split your locations? If every location matches the first tier, they all tie. Use the range hint to set thresholds that separate them.
    3. Are there higher-priority rules above this one that override its ranking?
    4. Have the locations shipped recently enough to have a time-to-ship value?
  </Accordion>

  <Accordion title="A location is always ranked last">
    **Check:**

    1. Does its average time to ship match any tier? If it's slower than every threshold, it falls to last by design.
    2. Has it shipped anything in the last 7 days? With no recent data it has no metric and ranks last until it does.
  </Accordion>

  <Accordion title="Thresholds only accept whole hours">
    Thresholds are entered in whole hours (minimum 1) — decimals are rejected. Charlie stores them precisely under the hood, so a 24-hour threshold compares against the exact measured time to ship.
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Backlog Routing" icon="list-check" href="/order-routing/backlog-routing">
    Prefer locations with shorter open queues
  </Card>

  <Card title="Order routing overview" icon="memo-circle-info" href="/order-routing/overview">
    All available routing rules
  </Card>

  <Card title="Inventory Rules" icon="warehouse" href="/order-routing/inventory-rules">
    Prioritize locations with more stock
  </Card>

  <Card title="Capacity Rules" icon="gauge-high" href="/order-routing/capacity-rules">
    Daily order limit per location
  </Card>
</CardGroup>
