Skip to content
Coritan Docs

How customers and orders are attributed

What we record about where each customer and order came from, how long we keep it, and how the "How did you first hear about us?" answer joins it.

View as Markdown

Attribution is the record of where a customer or an order came from. When a storefront that Coritan serves makes a customer or places an order, we write down the visit behind it: the campaign link or ad the visitor followed, the site that sent them, and the page they landed on. Your team reads it to see which campaigns and channels bring customers who buy.

Attribution needs the storefront's tracker, which sets its cookies on every visit. If you build your own storefront on the Storefront API, the API reads the same cookies from the requests your site forwards, and takes the details in the order itself when your site cannot forward cookies.

The tracker keeps two touches for each browser: the first visit it ever saw, and the last visit that was not direct. A touch holds:

  • The source, medium, campaign, term, content and ID of the utm_ parameters in the link, in lower case for the source and medium.
  • The ad click IDs in the link: gclid, gbraid, wbraid, dclid, fbclid, ttclid, msclkid, rdt_cid, twclid, li_fat_id, epik and sccid.
  • The referrer, which is the site that sent the visitor, and the landing page, which is the first page they saw.
  • A type: paid for a visit with a click ID or a paid medium (cpc, ppc, paid, paid-social, display, retargeting, cpm, banner), utm for any other link with a utm_ parameter, organic for a visit from a search engine or social network, referral for a visit from any other site, and direct.

A visitor who types your address or follows a link from your own storefront does not replace the last touch. A visit that only prefetches a page records nothing.

Every touch belongs to one channel, so reports group traffic the same way everywhere. The channel comes from the click ID first, then the medium, then the source and the referrer.

Channel A visit that
Paid Search Has a Google or Microsoft click ID, or a cpc, ppc or paid medium from a search engine.
Paid Social Has a click ID from a social network, a paid-social medium, or a cpc, ppc or paid medium from a social network.
Display Has a dclid, or a display, retargeting, cpm or banner medium.
Organic Search Comes from a search engine with no ad.
Organic Social Comes from a social network with no ad.
Email Has the medium email, e-mail, newsletter or mail. Your own transactional email counts here.
Affiliate Has the medium affiliate, or a ref parameter in the landing page address.
Referral Comes from any other site.
Direct Has no source we can name.
Other Fits none of the rows above, such as a cpc medium from a source that is neither a search engine nor a social network.

A paid touch also names its ad network: Google Ads, Microsoft Ads, Meta Ads, TikTok Ads, Reddit Ads or X Ads.

When a customer is made through the storefront, we write one record for the account. It holds the first and last touch with their channels, the click IDs, how the account was made, the browser's device type and country, and the visitor's consent choice at that moment.

How the account was made is email for the registration form, code for a sign-in code sent by email, checkout for a guest checkout, or the provider for a social sign-in: discord, github, google or microsoft. An account your team creates, and an account that moved from your old site, has no record.

A sign-in with a social provider carries the visit through the provider's page, so a new customer is credited to the visit they started from.

Each storefront order, from a single plan or a basket, gets one record on its invoice. A basket has one invoice, so it has one record for all its services. We write it once: asking again for the same order never changes it.

An order's record holds:

  • The first and last touch with their channels, and the click IDs.
  • The Meta browser and click IDs (fbp and fbc), and the Google Analytics client and session IDs. When the browser has no fbc but the visit came from a Meta ad, we build it from the fbclid and the time of the click, as Meta describes.
  • The IP address, the browser name and the device type, and the country.
  • The consent choice, the coupon code and the coupon's campaign, and the affiliate or referral code when the browser holds one.
  • Whether the customer was new: they had no earlier invoice that was paid for money. A free server does not count as a purchase, so a customer's first paid order still reads as new.
  • Whether the order was free, which means its invoice total was zero.
  • The customer's answer to "How did you first hear about us?", once they give it.

Orders that your team places for a customer, and renewals, have no record. An order placed in a support session that signs in as the customer has none either, because the visit belongs to your team.

If writing the record fails, we log the failure and the order goes through.

How a customer's answer joins the record

Section titled How a customer's answer joins the record

After a customer pays for an order, or places a free one, the storefront asks "How did you first hear about us?" once. The question shows only in the browser that placed or paid the order, never from a link in an email. The customer taps one answer, and Other opens a field for up to 200 characters. The first answer stays; a second one does not replace it. The answer shows on the order, next to its channels. Take the answer with the Storefront API if you build your own checkout.

The answers are Google search, Google Ads, Bing or other search, Reddit, A forum, YouTube, Discord, Instagram, Facebook, TikTok, X, A friend and Other.

The tracker sets its own cookies before a visitor chooses, because they only say how a visit arrived. Ad tags wait for consent. We copy the visitor's consent choice onto each customer and order record, so a later report or conversion can respect it.

  • In the EEA, the United Kingdom and Switzerland, and wherever we cannot tell the country, both analytics and marketing count as denied until the visitor chooses. Elsewhere both count as granted until they opt out.
  • A browser that sends Global Privacy Control has marketing denied everywhere, even after the visitor chooses to accept all.
  • The record never holds the customer's name, email address or any payment detail.
  • We keep an order's IP address for 30 days. After that a daily job cuts it to its network (the first three parts of an IPv4 address, the first three groups of an IPv6 address) and marks the record.
  • The tracker's visit records are removed after 180 days. The attribution records stay for as long as the customer or the order does, and go when the organization is removed.
  • A customer's privacy request export includes their account record and the record of each order. See Export a customer's data.

The staff API answers it on the pages your team already uses:

  • GET /staff/orders gives each order a channel, the channel of the last touch as {key, label}, or null for an order with no record.
  • GET /staff/orders/{service_id} gives attribution for the order, and GET /staff/customers/{customer_id} gives it for the customer. Both are null when there is no record. They hold the first and last touch, each with its channel, ad network and utm_ fields, the click_ids with their ad network, the device type, the country and the consent. The order adds the answer to the question, the coupon with its campaign, whether the customer was new and the order free, and which IDs we hold. It never sends the whole IP address: address.state says kept or truncated, and address.network gives the network.

See Staff billing and orders for the list's filters and the rest of the order answer.

The acquisition report adds the records up: where your visits, sign-ups, orders and revenue came from over a period, set against the period before. Your team reads it in the staff console, in the Acquisition section of Insights (Read the acquisition report describes the page). A script reads the same answer from the API:

Who Call Needs
The organization's owner GET /api/v1/orgs/{org_slug}/acquisition The Owner or Admin role
Your team's console GET /api/v1/orgs/{org_slug}/staff/insights/acquisition The Billing role or higher
A platform administrator, for any organization GET /api/v1/admin/orgs/{org_id}/acquisition The orgs.view permission

The three answer alike and read your data only. No address and no email is in the answer.

Shell
curl "https://api.coritan.com/api/v1/orgs/acme/acquisition?from=2026-09-01&to=2026-09-30&compare=previous&currency=USD&limit=10" \
  -H "Authorization: Bearer $TOKEN"
Parameter What it sets
from and to The first and last day, YYYY-MM-DD, both included, in your brand's time zone. The last 30 days when left out. A period is at most 366 days.
compare previous (the default) sets the totals against the same number of days just before the period, or the month before for a calendar month. none leaves the comparison out.
currency A three letter code. Orders and revenue count in this one currency. When left out, it is the currency with the most revenue in the period, or your brand's own currency when there were no orders.
limit The rows in each ranked list, 1 to 50 and 10 by default. The totals always cover every row.

A from after to, a period over 366 days, a compare other than the two words, a currency that is not three letters and a limit outside 1 to 50 answer 422 and say what to change.

  • A visit is a stored session of your storefront with bots left out. We keep sessions for 180 days, so visits_complete is false when the period starts earlier, and the visit figures are then partial.
  • A sign-up is a customer made through the storefront, counted on the day we wrote their record. A customer your team creates has none.
  • An order is a storefront order that is not free and whose invoice is paid, counted on the day we wrote its record. A free server is a sign-up and a visit but never an order, and an invoice nobody paid is not an order yet.
  • Revenue is the invoice total without tax, in the minor units of currency (cents for dollars). An order counts only in the currency of its invoice, so a euro order is never in a dollar report. currencies lists every currency with an order in the period, and money is never added across currencies.
  • A new customer is an order that is the customer's first paid order.
  • The conversion rate is orders over visits.

Every figure that ends in _bp is in basis points: 123 is 1.23 percent. The channel, source, medium, campaign and landing page of an order are those of its last touch.

from, to, zone (your brand's time zone), currency, currencies, basis (what the figures count, as the words last, excluding_tax, first_paid_order and sessions_without_bots) and visits_complete, then:

Key What it holds
totals visits, signups, orders, new_customers, revenue_minor and conversion_rate_bp. previous holds the same figures for the period before, or null when compare is none.
channels Each channel of the last touch with key, label, visits, signups, orders, new_customers, revenue_minor and share_bp, its share of the orders.
first_touch The same figures, without visits, by the channel of the first touch.
matrix Orders and revenue_minor for each pair of a first channel and a last channel.
sources Each source and medium with its channel, visits, orders, new_customers and revenue_minor.
campaigns Each campaign with its source, medium, visits, orders and revenue_minor.
landing_pages Each path with visits, signups, orders and revenue_minor. The path has no query string, and no language prefix when your storefront has languages, so /de/products counts as /products.
devices Each device (desktop, mobile, tablet or unknown) with visits, orders and revenue_minor.
click_ids orders, with_click_id, rate_bp and networks, the orders for each ad network that a click ID names.
heard_about The answers to "How did you first hear about us?" with source, label, orders and share_bp, the share of the answered orders.
return The ad spend return report for the period in currency, as rows, totals and truncated, or null when you have no ad spend in the period.
truncated true when the return report read only the first 50,000 of your orders.

A list ranks its rows by orders, then revenue, then visits, and holds the top limit of them.

GET /api/v1/orgs/{org_slug}/staff/orders takes the exact filters channel, first_channel, source, medium, campaign, device, heard_about and coupon_campaign, each matching the order's record. An order with no record matches none of them. A channel or first_channel that is not one of the ten channels above answers 422 and lists them.

A coupon can name a campaign of up to 80 characters, such as summer-launch. An order that uses the coupon copies the campaign onto its record, so renaming the campaign later does not move old orders. See Manage coupons.

The links in your transactional emails carry utm_source with your organization's slug, utm_medium=email and utm_campaign with the template's name. They are the welcome email, the invoice emails (created, due tomorrow, overdue and paid), the payment failure emails, the service activated email and the free server emails. A visit from one of them counts as the Email channel.

Only links to your own storefront are tagged. A link that signs the reader in or proves something is never tagged: the password reset, the address confirmation and any link with a token, code or key in it. A link that already has a utm_ parameter keeps it.

API operations on this page

MethodPathWhat it does
GET/api/v1/orgs/{org_slug}/acquisitionAcquisition report
GET/api/v1/orgs/{org_slug}/staff/insights/acquisitionAcquisition report