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

# Attribution

> How campaign context reaches a conversion, and what breaks the chain.

Attribution links a conversion back to the click that produced it. This page names every value we capture, and every stage where you can lose one.

## The chain

```text theme={null}
ad click → landing page captures the click ID → identity persists → conversion carries it
```

Every stage writes to first-party storage on your own domain. Nothing here is reconstructed later, so protect the capture stage first: a click ID the landing page never saw can't be recovered.

## What the tracking script captures

### Click IDs

| Parameter                   | Source it maps to |
| --------------------------- | ----------------- |
| `fbclid`                    | facebook          |
| `gclid`, `gbraid`, `wbraid` | google            |
| `ttclid`                    | tiktok            |
| `msclkid`                   | bing              |
| `twclid`                    | twitter           |
| `li_fat_id`                 | linkedin          |
| `sclid`                     | snapchat          |
| `dclid`                     | doubleclick       |
| `epik`                      | pinterest         |
| `rdt_cid`                   | reddit            |
| `obclid`                    | outbrain          |
| `irclid`                    | impact            |
| `ko_click_id`               | klaviyo           |

Two platforms use a different name on the landing URL. The script normalizes both.

| Real landing parameter | Stored as |
| ---------------------- | --------- |
| `ScCid` or `sccid`     | `sclid`   |
| `irclickid`            | `irclid`  |

<Note>
  On the web, pass `oppref`, the OpenAI Ads click ID, as an event property. The iOS and React Native SDKs read it from the landing URL for you.
</Note>

### Campaign parameters

The script captures `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, and `utm_content`.

It also captures `lyr`, `ref`, `source`, `campaign`, `medium`, and `gad_source`.

### Ad cookies

The script reads and writes `_fbp`, `_fbc`, `_gcl_aw`, `_gcl_dc`, `_gcl_gb`, `_gcl_ha`, `_gac`, `_ttp`, `_ttc`, and `_scid`.

These are marketing-scoped. After a marketing denial, the script neither writes nor sends them. It keeps `utm_*` and the Google Analytics cookies, which are analytics-scoped.

The browser attribution window is 90 days.

## How a conversion finds its click

Datalyr searches in this order and stops at the first hit.

| Order | Where it looks                                                         |
| ----- | ---------------------------------------------------------------------- |
| 1     | The conversion event's own click ID field                              |
| 2     | The click ID column on the event's attribution row                     |
| 3     | Earlier events in the same `session_id`                                |
| 4     | Earlier events with the same `distinct id`, inside the platform window |
| 5     | Every visitor linked to the same `user_id`                             |

Step 5 is what carries a web click through to a server-side purchase. It works only after your code calls `identify()` on both the browser and the server with the same ID. That one call is usually the difference between a purchase that credits a campaign and one that reads `direct`.

| Platform | Window used for steps 3 to 5 |
| -------- | ---------------------------- |
| Google   | 90 days                      |
| Snapchat | 28 days                      |
| Meta     | 7 days                       |
| TikTok   | 7 days                       |
| OpenAI   | 7 days                       |

The default model is first click. A rule can select last click instead. A same-session match always wins over both.

## Verify one journey

1. Open your site in a private window, with `?utm_source=doctest&utm_campaign=doctest` appended.
2. Open **Live**. Confirm the visit appears within 30 seconds.
3. Complete a sign-up so your code calls `identify()`.
4. Open **Users**. Find the user. Confirm the touchpoint reads `doctest`.
5. Complete a purchase.
6. Open **Conversions**. Confirm the row's `attribution_type` is not `none`.

## When it does not work

| Symptom                                               | Cause                                                   | Check                                    | Fix                                                      |
| ----------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------- | -------------------------------------------------------- |
| The visit has no campaign                             | The landing URL lost its parameters                     | The URL after every redirect             | Keep the query string through each redirect hop          |
| Click ID present on the visit, absent on the purchase | The purchase came from a webhook with no linked visitor | The `user_id` on both rows in **Events** | Call `identify()` with the same ID on browser and server |
| `attribution_type: none` on every mobile conversion   | The app never carried a click ID                        | The app event payload in **Events**      | Set up deep links so the click ID reaches the app        |
| Snapchat conversions carry no click ID                | The landing page dropped `ScCid`                        | The landing URL of a real Snap ad        | Stop stripping unknown query parameters                  |
| OpenAI conversions carry no click ID                  | The web event carries no `oppref`                       | The event payload in **Events**          | Pass `oppref` as an event property                       |
| Attribution stops after a consent banner              | The visitor denied marketing consent                    | `consent.marketing` on the event         | Nothing. This is the correct behavior                    |
| Datalyr and the ad platform disagree                  | Different windows, models, and timezones                | The six rows below                       | Align each one before comparing                          |

## Before you compare totals

Align all six of these. Any one of them alone explains a large gap.

| Setting                      | Why it matters                                                                      |
| ---------------------------- | ----------------------------------------------------------------------------------- |
| Date range and timezone      | Datalyr reports in the workspace timezone                                           |
| Conversion definition        | One rule's trigger event against the platform's action                              |
| Gross against net revenue    | Superwall and RevenueCat report different bases                                     |
| Currency                     | Non-USD values are summed at face value, so compare a single currency on both sides |
| Attribution window and model | Google looks back 90 days, Meta 7                                                   |
| View-through inclusion       | Meta counts 1-day view. Datalyr counts clicks                                       |

## Next

* [Conversion delivery](/advanced/conversion-delivery): how the resolved click ID reaches the ad platform.
* [Conversions](/product/conversions): read `attribution_type` on one delivery row.
* [Integrations](/integrations/index): connect the platform whose clicks you want to match.
