> For the complete documentation index, see [llms.txt](https://docs.hackle.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hackle.io/en/event-management/properties/utm.md).

# Campaign Property (UTM)

## How UTM Campaign Information Is Managed

The Hackle Web SDK automatically collects and stores which marketing campaign a user arrived through, and links this acquisition information to events that occur afterward. This document explains **when UTM parameters are stored, when they are retained, and when they are reset**.

### Supported SDK Versions

| SDK              | Version  |
| ---------------- | -------- |
| `javascript-sdk` | 11.18.0+ |
| `react-sdk`      | 11.18.0+ |

### Collected Parameters

The SDK automatically reads the following parameters from the query string of the page URL.

| Category    | Parameter                                                                       |
| ----------- | ------------------------------------------------------------------------------- |
| UTM         | `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content`, `utm_id` |
| Ad Click ID | `gclid` (Google Ads), `fbclid` (Meta/Facebook)                                  |

* Parameters with an **empty string value are ignored**. (e.g., `?utm_source=` is not collected)
* Collected values are **stored as User Properties**, and an acquisition event is fired when a new campaign is detected.
* The attribution model is **Last-touch**. If the user arrives again with a new UTM, the previous value is overwritten.

### How It Is Stored

Collected UTM information is stored in a **first-party cookie**.

| Item             | Details                                                                        |
| ---------------- | ------------------------------------------------------------------------------ |
| Storage location | Browser cookie                                                                 |
| Domain scope     | Based on the root domain (e.g., `.example.com` — **shared across subdomains**) |

{% hint style="info" %}
Because it is stored in a cookie, **the stored value itself does not disappear** even across page refreshes, redirects, new tabs, or subdomain navigation. The value changes only when the SDK explicitly updates or resets it through the "re-evaluation" process described below.
{% endhint %}

### When UTM Information Is Updated (Re-evaluation)

The SDK re-checks the current URL to decide whether to update UTM information only at the following two moments.

1. **When the page is newly loaded** — any case where the SDK is re-initialized, such as initial entry, refresh, or a page transition involving a server round-trip.
2. **When a new session starts** — one of the following conditions:
   * The User Identifier (userId) changes (e.g., login/logout)
   * A new event occurs after a session timeout (default **30 minutes** of inactivity)

{% hint style="info" %}
Client-side routing alone in a SPA (Single Page Application) without a refresh does not trigger this re-evaluation. In other words, even if you navigate between pages during a session, **the UTM information stays fixed at the value from the initial entry** unless the SDK is reloaded or a new session starts.
{% endhint %}

### Rules for Retain / Update / Reset Decisions

When re-evaluation runs, the SDK looks at both the **UTM values in the current page URL** and the **previous page (referrer)** to decide as follows.

| Current URL state                          | Acquisition path                                                                   | Action                                                            |
| ------------------------------------------ | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| UTM **present**, differs from stored value | N/A                                                                                | **Update** (overwrite with new campaign + fire acquisition event) |
| UTM **present**, same as stored value      | N/A                                                                                | **Retain** (no change, no duplicate event)                        |
| UTM **absent**                             | **Navigation within the same domain** (previous page is our site)                  | **Retain**                                                        |
| UTM **absent**                             | **Arrival from an external site** or **no referrer** (direct URL entry / bookmark) | **Reset** (delete stored UTM)                                     |

Key summary:

* **There are only two cases where it is retained:** (1) navigating within the same domain without UTM, and (2) when the UTM in the current URL is exactly identical to the stored value.
* Otherwise, if **"no UTM + external/direct arrival"** is detected at a re-evaluation moment, the existing UTM is **reset**.
* The key axis for the decision is the **domain of the referrer (previous page)**.

### Behavior by Scenario

| Scenario                                                            | Result         | Description                                                                  |
| ------------------------------------------------------------------- | -------------- | ---------------------------------------------------------------------------- |
| **Initial arrival via a UTM link**                                  | Store          | Store campaign information + fire acquisition event                          |
| **Refreshing the same UTM URL**                                     | Retain         | Values are identical, so no change or duplicate event                        |
| **Re-arrival via a new UTM link**                                   | Update         | Overwrite with the last acquisition campaign (Last-touch)                    |
| **Page transition via an internal site link** (same domain, no UTM) | Retain         | Referrer is your own domain → existing UTM retained                          |
| **SPA routing** (page navigation without refresh)                   | Retain (fixed) | No re-evaluation. The UTM from entry is retained throughout the session      |
| **Direct URL entry / bookmark revisit** (no UTM)                    | Reset          | No referrer, so judged as "external/direct arrival" → stored value deleted   |
| **Return after external OAuth login** (no UTM in callback URL)      | Reset risk     | The return page's referrer is an external (auth provider) domain → reset     |
| **Return after external payment (PG)** (no UTM in callback URL)     | Reset risk     | Same as above. If the referrer is the payment provider's domain, it is reset |

#### Note on SPA Environments

In a SPA that routes without refreshing, the UTM captured at initial entry is retained throughout the session, making it stable. Conversely, however, **UTM parameters that appear only during routing after the initial entry may not be collected immediately.** For such a value to be collected, that UTM must still be present in the URL at the moment of the next page load or the start of a new session.

#### Caution with External Redirects (OAuth / Payment)

When you navigate to an external authentication/payment page and then return, the return page is handled as a **full page load**, triggering re-evaluation. If the return URL (callback URL) has no UTM and the referrer is an external domain (auth provider / payment provider), the rules cause **the stored UTM to be reset**. If the User Identifier changes during login, a new session also starts, leading to the same result.

### Recommendations

* **To retain UTM even after an external redirect**, configure the redirect so that the return (callback) URL carries the original UTM parameters back as-is. If the callback URL contains the UTM, it is retained as the same value or reapplied as-is during re-evaluation.
* To measure campaign performance accurately, **attach UTM parameters consistently to acquisition links (ads, emails, etc.)**.
* If you want to record a specific event together with the campaign right after arrival in a SPA, make sure the UTM is included in the URL at the moment of entry.

#### Carrying UTM Through After Visiting External Pages (Payment, Login, etc.)

**Situation.** After going through external payment (PG) or social login (OAuth), the address (URL) of the page you return to usually has no UTM, and the "previous page" is recorded as an external site (payment provider / login provider). The SDK may then judge this as a "new/direct arrival" and **reset the UTM it had stored**.

**Solution principle (in one sentence).** If you **reattach the original UTM to the return address (callback URL)** when coming back from an external site, the SDK recognizes it as the same campaign and carries the UTM through as-is. → This can be solved with configuration on the site (customer) side, without any SDK changes.

{% hint style="info" icon="lightbulb-on" %}
Just ask your development team to **keep the UTM attached to the return link address** after payment/login completes.
{% endhint %}

**Comparison of Methods**

| Method                                     | Difficulty | Recommendation | Description                                                                                    |
| ------------------------------------------ | ---------- | -------------- | ---------------------------------------------------------------------------------------------- |
| Reattach UTM to the return URL (returnUrl) | Low        | ★★★            | The most reliable method, working regardless of the type of payment or login                   |
| Process payment in a popup/window (iframe) | Medium     | ★★☆            | UTM is retained as-is because you do not leave the original page (may be restricted on mobile) |
| Return via a callback on your own domain   | Medium     | ★☆☆            | Unstable on its own → recommended to use together with "attaching UTM to the URL" above        |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.hackle.io/en/event-management/properties/utm.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
