Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions docs/events/cross-navigation/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
title: "Cross-navigation tracking"
description: "Configure cross-domain tracking to maintain user identity between different domains in your ecosystem"
date: "2025-07-26"
sidebar_position: 5
---

When users navigate between different domains in your ecosystem, their user identity may get fragmented. Examples include navigation from your main website to a partner site, or to a mobile app. This creates gaps in your user journey data and makes it difficult to understand the complete customer experience across your digital properties.

:::info Web subdomains
This problem doesn't usually apply for navigation between web subdomains, as the web trackers have `discoverRootDomain` [enabled by default](/docs/sources/trackers/web-trackers/tracker-setup/initialization-options/index.md).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have an example to avoid being jargon?

(e.g. www.example.com and blog.example.com)

:::

Cross-navigation (also called cross-domain) tracking solves this problem by passing user identification data in URL parameters when users click links to other domains. This enables you to maintain user continuity across your applications.

To use cross-navigation tracking, configure the [web](/docs/sources/trackers/web-trackers/cross-domain-tracking/index.md) or [native mobile](/docs/sources/trackers/mobile-trackers/tracking-events/session-tracking/index.md#decorating-outgoing-links-using-cross-navigation-tracking) trackers to add an additional parameter, named `_sp`, to the querystring of outbound links. This process is called "link decoration".

Link decoration makes the added values visible in the `url` field of events on the destination page or URI. The querystring is added only to the events at the destination: it doesn't persist throughout the user's session.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this meant to be "at the destination URL" or "destination page" or similar? It doesn't seem unreasonable to think "the destination" is the entire site/app you're linking to.


## Querystring properties

The `_sp` querystring parameter has two different formats: extended or short. You can also configure exactly which properties you want to include.

Available properties:

| Property | Description | Extended | Short |
| ---------------- | ---------------------------------------------- | -------- | ----- |
| `domainUserId` | Current tracker-generated UUID user identifier |||
| `timestamp` | Current epoch timestamp, millisecond precision |||
| `sessionId` | Current session UUID identifier || |
| `subjectUserId` | Custom business user identifier || |
| `sourceId` | Application identifier || |
| `sourcePlatform` | Platform of the current device || |
| `reason` | Custom information or identifier || |

For example, the link `appSchema://path/to/page` would look like this after decoration with the full extended format:

```
appSchema://path/to/page?_sp=domainUserId.timestamp.sessionId.subjectUserId.sourceId.sourcePlatform.reason
```

## How are the querystring parameters processed?

By default, your pipeline will process only the short format querystring `_sp={domainUserId}.{timestamp}`, even if you've decorated the links with the extended format. To process the extra properties, you'll need to configure the [cross-navigation enrichment](/docs/pipeline/enrichments/available-enrichments/cross-navigation-enrichment/index.md).

Both default and extended formats will populate the [atomic](/docs/fundamentals/canonical-event/index.md) `refr_domain_userid` and `refr_dvce_tstamp` fields. The enrichment also adds a `cross_navigation` entity to the event.

| Feature | Default behavior | With cross-navigation enrichment |
| ------------------------------------------------------- | ---------------- | -------------------------------- |
| Processes short format `_sp={domainUserId}.{timestamp}` |||
| Processes extended format properties |||
| Populates `refr_domain_userid` field |||
| Populates `refr_dvce_tstamp` field |||
| Adds `cross_navigation` entity |||
2 changes: 1 addition & 1 deletion docs/events/timestamps/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Timestamps"
description: ""
date: "2025-05-15"
sidebar_position: 4
sidebar_position: 400
---

Snowplow events have multiple timestamps that are added as the payload moves through the pipeline. The set of timestamps is designed to account for devices with incorrectly set clocks, or delays in event sending due to network outages. All timestamps are converted to UTC for consistency across events.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
---
title: "Cross Navigation Enrichment"
title: "Cross-navigation enrichment"
sidebar_position: 5
sidebar_label: Cross Navigation
sidebar_label: Cross-navigation
---

This enrichment parses the extended cross navigation format in `_sp` querystring parameter and attaches the `cross_navigation` context to an event.
This enrichment parses the extended cross-navigation format in the `_sp` querystring parameter, and attaches a `cross_navigation` entity to an event.

The `_sp` parameter can be attached by our Web ([see cross-domain tracking](/docs/sources/trackers/web-trackers/cross-domain-tracking/index.md)) and [mobile trackers](/docs/sources/trackers/mobile-trackers/tracking-events/session-tracking/index.md#decorating-outgoing-links-using-cross-navigation-tracking) and contains user, session and app identifiers (e.g., domain user and session IDs, business user ID, source app ID). The information to include in the parameters is configurable in the trackers. This is useful for tracking the movement of users across different apps and platforms.
Check out the [cross-navigation](/docs/events/cross-navigation/index.md) page to learn why this can be useful.

The extended cross navigation format can be described by `_sp={domainUserId}.{timestamp}.{sessionId}.{subjectUserId}.{sourceId}.{platform}.{reason}`
The extended cross-navigation format is `_sp={domainUserId}.{timestamp}.{sessionId}.{subjectUserId}.{sourceId}.{sourcePlatform}.{reason}`. The `domainUserId` and `timestamp` fields will always be present, but some of the other fields may be null or empty. They're configured within the tracker.

If this enrichment isn't enabled, Enrich parses `_sp` querystring parameter according to the old format, `_sp={domainUserId}.{timestamp}`
If this enrichment isn't enabled, Enrich parses the `_sp` querystring parameter according to the short format, `_sp={domainUserId}.{timestamp}`

## Configuration

- [Schema](https://github.com/snowplow/iglu-central/blob/master/schemas/com.snowplowanalytics.snowplow.enrichments/cross_navigation_config/jsonschema/1-0-0)
- [Example](https://github.com/snowplow/enrich/blob/master/config/enrichments/cross_navigation_config.json)

```json reference
https://github.com/snowplow/enrich/blob/master/config/enrichments/cross_navigation_config.json
```

```mdx-code-block
import TestingWithMicro from "@site/docs/reusable/test-enrichment-with-micro/_index.md"

Expand All @@ -25,13 +29,10 @@ import TestingWithMicro from "@site/docs/reusable/test-enrichment-with-micro/_in

## Input

This enrichment extracts `_sp` querystring parameter from the following inputs:

- The `page_url` field from the Snowplow event
- The referer uri extracted from corresponding HTTP header in the raw event
This enrichment extracts the `_sp` querystring parameter from the `page_url` field from the Snowplow event.

## Output

This enrichment adds a new derived context to the enriched event with [this schema](https://github.com/snowplow/iglu-central/blob/master/schemas/com.snowplowanalytics.snowplow/cross_navigation/jsonschema/1-0-0).
This enrichment adds a new derived entity to the enriched event based on [this schema](https://github.com/snowplow/iglu-central/blob/master/schemas/com.snowplowanalytics.snowplow/cross_navigation/jsonschema/1-0-0).

Also, it continues to populate `refr_domain_userid` and `refr_dvce_tstamp` enriched event fields as before.
Also, it populates the `refr_domain_userid` and `refr_dvce_tstamp` enriched event fields.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth having the qualifier here; this page ranks highly for those two fields in search now and this implies this enrichment is required for them to populate, but they will populate even if it is disabled (even if it's super clear on the other page).

Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ For instance, with this configuration:
SessionConfiguration(
foregroundTimeout: Measurement(value: 360, unit: .seconds),
backgroundTimeout: Measurement(value: 15, unit: .seconds)
)
)
```

</TabItem>
Expand Down Expand Up @@ -212,30 +212,25 @@ Snowplow.createTracker(getApplicationContext(), namespace, networkConfig, sessio

## Decorating outgoing links using cross-navigation tracking

:::note Not available before v6
:::note
This feature was introduced in version 6.0.0 of the iOS and Android trackers.
:::

The tracker provides a `decorateLink` API to decorate outgoing links from the mobile app to another mobile app or to a website.
This API adds an `_sp` parameter to the links containing information about the user, app, and current session.
This is useful for tracking the movement of users across different apps and platforms.
It is part of our cross-navigation solution and is equivalent to [cross-domain tracking on the JavaScript tracker](/docs/sources/trackers/web-trackers/cross-domain-tracking/index.md).
The `decorateLink` function is part of Snowplow's [cross-navigation solution](/docs/events/cross-navigation/index.md) for tracking the movement of users across different apps and platforms.

For example, calling `decorateLink` on `appSchema://path/to/page` will produce the following result:
Choose which parameters to include using a `CrossDeviceParameterConfiguration` object. The `domainUserId` and `timestamp` are always included automatically. Use booleans to select which properties to include in the link decoration. The tracker will derive the required values from its configuration.

```
appSchema://path/to/page?_sp=domainUserId.timestamp.sessionId.subjectUserId.sourceId.platform.reason
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of like the example since it makes it obvious that your deep link handler needs to not break if it receives this parameter. But I don't think that's very common, nor do I think generating deep links within the app itself is very common, more likely it will be app -> web links so it's probably a moot point.

Oh, it moved to the general page, nevermind!

```
This table shows the options:

The `decorateLink` function adds the following information to the link (configurable using the `CrossDeviceParameterConfiguration` object passed to the method):
| Property | Description | Type | Included by default? | Value used |
| ---------------- | -------------------------------- | ------- | -------------------- | ---------------------------------- |
| `sessionId` | Current session UUID identifier | Boolean | ✅ | `SessionController.sessionId` |
| `subjectUserId` | Custom business user identifier | Boolean | ❌ | `SubjectController.userId` |
| `sourceId` | Application identifier | Boolean | ✅ | `TrackerConfiguration.appId` |
| `sourcePlatform` | Platform of the current device | Boolean | ❌ | `TrackerController.devicePlatform` |
| `reason` | Custom information or identifier | String | ❌ | Custom string provided by you |

- `domainUserId` – The current tracker generated user identifier (value of `SessionController.userId`) – required.
- `timestamp` – The current ms precision epoch timestamp – required.
- `sessionId` - The current session identifier (value of `SessionController.sessionId`) – optional.
- `subjectUserId` - The custom business user identifier (value of `SubjectController.userId`) – optional.
- `sourceId` – The `appId` (value of `TrackerConfiguration.appId`) – optional.
- `platform` - The platform of the current device (value of `TrackerController.devicePlatform` – optional.
- `reason` – Identifier/information for cross-navigation – optional.
The `subjectUserId` property is not included by default, in case it contains personal data.

<Tabs groupId="platform" queryString>
<TabItem value="ios" label="iOS" default>
Expand All @@ -245,7 +240,7 @@ let link = URL(string: "https://example.com")!
let decoratedLink = Snowplow.defaultTracker()?.decorateLink(
link,
// optional configuration for which information to be added to the link
extendedParameters: CrossDeviceParameterConfiguration(sessionId: true, subjectUserId: true)
extendedParameters: CrossDeviceParameterConfiguration(sessionId: false, subjectUserId: true)
)
```

Expand All @@ -257,7 +252,7 @@ val link = Uri.parse("http://example.com")
val decoratedLink = Snowplow.defaultTracker.decorateLink(
link,
// optional configuration for which information to be added to the link
CrossDeviceParameterConfiguration(sessionId = true, subjectUserId = true)
CrossDeviceParameterConfiguration(sessionId = false, subjectUserId = true)
)
```

Expand All @@ -267,7 +262,7 @@ val decoratedLink = Snowplow.defaultTracker.decorateLink(
```java
Uri link = Uri.parse("http://example.com");
Uri decoratedLink = Snowplow.getDefaultTracker().decorateLink(link, new CrossDeviceParameterConfiguration(
true, // sessionId
false, // sessionId
true, // subjectUserId
false, // sourceId
false, // sourcePlatform
Expand Down
Loading