order metafields

Metafields reference

Origin writes to JSON metafields for every processed order under the reserved app--90823720961 namespace. Each metafield holds one attribution model's data of the touches that drove the order.

Namespace and access#

All metafields are owned by the Order resource in the app--90823720961 namespace. Every definition uses type: json, access.admin = "merchant_read", and access.storefront = "none".

noteStorefront access is disabled. These metafields are not readable from Liquid themes or the Storefront API — only through the Admin GraphQL API, Shopify Flow, and order exports.

Available metafields#

FieldTypeDescription
attribution_first_touch* required
SingleTouchFirst-touch attribution — the earliest touch in the window.
attribution_last_touch* required
SingleTouchLast-touch attribution — the converting touch.
attribution_linear* required
MultiTouchLinear attribution — credit shared evenly across all touches.
attribution_any_click* required
MultiTouchAny-click attribution — every touch credited in full.
attribution_last_non_direct* required
SingleTouchLast non-direct attribution — the most recent touch carrying a UTM.
attribution_origin* required
MultiTouchOrigin's model — the most recent touch in each channel.

How each model assigns credit and attributed_revenue is described in Attribution models.

How to read them#

Read Metafield values through the Shopify Admin GraphQL API, Shopify Flow, or an order export (anywhere the merchant’s Admin scope reaches). They are not exposed to the storefront or Storefront API.

Admin GraphQL APIgraphql
query OrderAttribution($id: ID!) {
  order(id: $id) {
    metafield(namespace: "app--90823720961", key: "attribution_origin") {
      type
      value
    }
  }
}
warningMetafield values are JSON encoded as a string. Parse metafield.value before reading fields from it.

Value shape#

Every value is an object carrying the attribution window and touches.

  • single-touch models hold one touch or null
  • multi-touch models hold an ordered touches array (touch_ts ascending, except for attribution_origin which is unordered)

Attribution window#

Currently Origin only supports 30-day attribution windows for metafield data: only touches whose touch_ts falls within 30 days before the order are included. The window is recorded on each value as attribution_window_days, so every metafield is self-describing.

SingleTouch

ts
type SingleTouch = {
  attribution_window_days: number;
  touch: AttributionTouch | null;  // null when no touch falls in the window
}

MultiTouch

ts
type MultiTouch = {
  attribution_window_days: number;
  touches: AttributionTouch[];     // [] when no touch falls in the window
}

The touch object#

Each AttributionTouch describes one touchpoint and the credit it received under that model. String fields default to "" when Origin has no value for them.

FieldTypeDescription
utm_source
stringutm_source captured on the touch.
utm_medium
stringutm_medium captured on the touch.
utm_campaign
stringutm_campaign captured on the touch.
utm_content
stringutm_content captured on the touch.
utm_term
stringutm_term captured on the touch.
landing_page
stringURL the visitor landed on for this touch.
touch_ts* required
stringISO 8601 timestamp of the touch, in UTC.
credit* required
numberCredit assigned by the touch between 0 - 1.
attributed_revenue* required
numberOrder revenue attributed to this touch: credit * order total, in the order’s currency.
ad_platform_key
stringAd platform when the touch is linked to an ad or campaign, e.g. meta or google. Empty otherwise.
ad_external_id
stringPlatform ad ID, when the touch is linked to a specific ad.
ad_campaign_external_id
stringPlatform campaign ID, when the touch is linked to a campaign but not a specific ad.
noteAd linkage is resolved in order of precedence: a touch linked to a specific ad fills ad_external_id; a touch linked only to a campaign fills ad_campaign_external_id.

Example#

attribution_linear for an order of 129.00 with two touches in the window — credit and revenue split evenly:

$app.attribution_linearjson
{
  "attribution_window_days": 30,
  "touches": [
    {
      "utm_source": "google",
      "utm_medium": "cpc",
      "utm_campaign": "brand-search",
      "utm_content": "",
      "utm_term": "",
      "landing_page": "https://shop.example.com/?utm_source=google&utm_medium=cpc&utm_campaign=brand-search",
      "touch_ts": "2026-05-10T14:02:11.000Z",
      "credit": 0.5,
      "attributed_revenue": 64.5,
      "ad_platform_key": "google",
      "ad_external_id": "",
      "ad_campaign_external_id": "97431001"
    },
    {
      "utm_source": "facebook",
      "utm_medium": "paid_social",
      "utm_campaign": "spring-retargeting",
      "utm_content": "carousel-a",
      "utm_term": "",
      "landing_page": "https://shop.example.com/products/hydrating-serum?utm_source=facebook&utm_medium=paid_social&utm_campaign=spring-retargeting&utm_content=carousel-a",
      "touch_ts": "2026-05-18T09:47:55.000Z",
      "credit": 0.5,
      "attributed_revenue": 64.5,
      "ad_platform_key": "meta",
      "ad_external_id": "120210000000123456",
      "ad_campaign_external_id": ""
    }
  ]
}

A model with no qualifying touch in the window still records the window:

json
// attribution_last_non_direct — every in-window touch was direct
{ "attribution_window_days": 30, "touch": null }

// attribution_linear — no touches in the window
{ "attribution_window_days": 30, "touches": [] }