Campaigns
Docs chevron_right Campaigns chevron_right Conversion tracking

Conversion tracking

Conversion tracking connects the purchases and sign-ups happening in your product to the campaign or automation email that drove them — count, attributed revenue, conversion rate, and revenue per recipient, on the reports you already read. This page explains the model exactly: what a goal is, how attribution decides, where the numbers surface, and what the model deliberately does not claim.

Conversion goals

A goal defines what counts as a conversion for your account. You manage goals under Settings → Analytics; each one has:

  • An event binding. Every conversion enters the platform as a trigger-event fire — there is exactly one ingestion pipeline. Bind the goal to any event you already fire: a Stripe event such as stripe.invoice.paid, a Shopify event such as shopify.order.paid, or one of your own custom events. Or pick Generic API and the goal provisions its own reserved event (conversion.<goal-uid>), fired by POST /api/v1/conversions — see below.
  • A revenue path (optional). A dot-path into the fire's payload where the amount lives — total_price for Shopify orders, order.amount_paid, or the default amount for generic goals. The value is recorded verbatim as a number in your account's own currency; the platform never converts currencies. Leave the path empty (or let it miss) and conversions are still counted — just without revenue.
  • Two attribution windows. How many days before the conversion to look back for a click (default 5) and for an open (default 1). Each window accepts 0–90 days; 0 disables that touch type.
  • An active toggle. Paused goals stop matching new fires; everything already recorded stays reportable.
emailflow.ai/rui/account/analytics
The Settings Analytics page showing a 30-day conversions summary strip with four stat cards above a table of conversion goals, each row listing the bound event, revenue path, conversion count, attributed revenue, status, and tracking windows
Settings → Analytics: the account-wide 30-day summary above your goals. Each row shows its "tracking since" date — attribution never reaches further back.

The attribution model

One model, applied to every conversion: last-touch, clicks beat opens.

  1. When a goal-matching event fires, an attribution job finds every send the converting address received from you — campaign sends and automation sends both qualify.
  2. It looks for the most recent click inside the goal's click window before the conversion. If one exists, that email's campaign or automation gets the conversion, attribution click. Click priority is absolute: a qualifying click wins even over a newer open.
  3. Only when no click qualifies does it look for the most recent open inside the (typically shorter) open window — attribution open.
  4. No qualifying touch at all? The conversion is recorded with attribution none — counted honestly in your totals, credited to no email. A touch after the conversion never qualifies; you cannot be converted by an email you read later.

Touches are matched by email address across all your lists — the converting human is one person, however many subscriber rows share the address. Each event fire attributes at most once per goal: replays and webhook retries of the same fire cannot inflate your numbers.

Recording conversions via the API

For stacks without a Stripe or Shopify connection, POST /api/v1/conversions records a conversion directly. It requires the analytics scope and internally fires the goal's bound trigger event through the standard pipeline — a conversion is a fire, so automations listening for the event enroll the contact as usual.

# Record a purchase against a goal (find goal uids in Settings → Analytics
# or via GET /api/v1/conversions/goals)
curl -X POST https://emailflow.ai/api/v1/conversions \
  -H "Authorization: Bearer efa_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-8412-conversion" \
  -d '{
    "goal_uid": "68a91b2c7de31",
    "email": "alice@example.com",
    "amount": 129.90,
    "occurred_at": "2026-07-05T13:30:00Z"
  }'

# Response (201) — attribution resolves asynchronously
{
  "data": {
    "fire_id": "68a91b2c7de99",
    "goal_uid": "68a91b2c7de31",
    "email": "alice@example.com",
    "status": "recorded",
    "occurred_at": "2026-07-05T13:30:00+00:00"
  }
}
  • amount is optional and lands on the fire payload's amount key — picked up automatically by generic goals, whose revenue path defaults to amount.
  • occurred_at (optional, ISO 8601) backdates the conversion — the attribution windows anchor to it, so a webhook that reaches you an hour late still attributes against the right day. Defaults to now.
  • An inactive goal, or a goal whose bound event was deleted, refuses with 409 CONFLICT; an unknown goal_uid is 404. Retries are safe with an Idempotency-Key header.
  • GET /api/v1/conversions/goals lists your goals read-only (uid, bound event, windows, lifetime conversion count) so integrating code can discover uids without hard-coding them.

Where the numbers appear

Once at least one goal exists, a Conversions card appears on the surfaces you already use:

  • Campaign reports — conversions attributed to that campaign: count, attributed revenue, conversion rate per delivered recipient, and revenue per recipient.
  • Automation statistics — the same four numbers for conversions attributed to the flow's emails.
  • The dashboard — an account-wide 30-day rollup: total conversions, attributed revenue, how many were attributed to email, and how many were counted unattributed.
  • Settings → Analytics — the same 30-day summary above the goals table, plus a lifetime count and revenue per goal.

The aggregates also ground the analytics Q&A chat — once revenue flows, questions like “which campaign drove the most revenue this month?” are answered from your own attributed numbers.

emailflow.ai/dashboard
The Conversions last-30-days card on the dashboard showing total conversions, attributed revenue, conversions attributed to email, and unattributed conversions, with a Manage goals link
The dashboard rollup: 30 days of conversions across every goal, split into attributed-to-email and honestly unattributed.

What the model does not claim

Attribution is a model, not a confession — these are its documented edges:

  • No retroactivity. Attribution starts the moment a goal is created; the UI shows each goal's “tracking since” date. Conversions that happened before the goal existed were never recorded, and no backfill invents them.
  • One model. Last-touch with click-over-open priority — no configurable multi-touch, no fractional credit. Every number on every card is explainable by the four steps above.
  • Marketing sends only. Campaign and automation emails are qualifying touches. Transactional messages are deliberately not — a password-reset email should never claim your revenue.
  • Amounts are verbatim. Whatever number sits at the revenue path is recorded as-is, assumed to be your account's currency. Mixed-currency stores should normalize before sending.
  • Deleting a goal deletes its history. The goal's recorded conversions go with it — reports stop showing them immediately. Pause a goal instead when you only want to stop new matching.