From 0ff1bacd12eb7b1b9ff1b325379860e152875a40 Mon Sep 17 00:00:00 2001 From: forstisabella <92472883+forstisabella@users.noreply.github.com> Date: Thu, 11 Sep 2025 16:03:01 -0400 Subject: [PATCH 01/55] Update group.md --- src/connections/spec/group.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/connections/spec/group.md b/src/connections/spec/group.md index 98f1ebd55b..369d683ea5 100644 --- a/src/connections/spec/group.md +++ b/src/connections/spec/group.md @@ -8,15 +8,14 @@ The Group call enables you to identify what account or organization your users a {% include components/reference-button.html href="https://university.segment.com/introduction-to-segment/324252?reg=1&referrer=docs" icon="media/academy.svg" title="Segment University: The Segment Methods" description="Check out our high-level overview of these APIs in Segment University. (Must be logged in to access.)" %} -In addition to the `groupId`, which is how you'd identify the specific group or company, the group method receives traits that are specific to the group, like industry or number of employees for example, that belong to that specific account. Like the traits of an identify call, you can update these when you call the same trait with a different value. +In addition to the `groupId`, which is how you'd identify the specific group or company, the group method receives traits that are specific to the group, for example the industry or number of employees, that belong to that specific account. Like the traits of an Identify call, you can update these when you call the same trait with a different value. When using the Group call, it's helpful if you have accounts with multiple users. - -> info "Segment doesn't have an ungroup call" -> If you're using a device-mode destination that has a method for ungrouping users, you can invoke it directly on the client side [using Segment's ready() method](/docs/connections/sources/catalog/libraries/website/javascript/#ready). +> info "Segment doesn't have a native solution for removing users from a group" +> If you're using a device-mode destination that has a method for removing users from a group, you can invoke it directly on the client side [using Segment's ready() method](/docs/connections/sources/catalog/libraries/website/javascript/#ready). > -> For cloud-mode destinations, you can [create a Destination Function](/docs/connections/functions/destination-functions/) to ungroup users. +> For cloud-mode destinations, you can [create a Destination Function](/docs/connections/functions/destination-functions/) to remove users from a group. Here's the payload of a typical Group call, with most [common fields](/docs/connections/spec/common/) removed: @@ -106,7 +105,7 @@ Use the following interactive code pen to see what your Group calls would look l ## Group ID -A Group ID is the unique identifier which you recognize a group by in your own database. For example, if you're using MongoDB it might look something like `507f191e810c19729de860ea`. +A Group ID is the unique identifier which you recognize a group by in your own database. For example, if you're using MongoDB, your Group ID might look something like `507f191e810c19729de860ea`. ## Traits @@ -132,10 +131,9 @@ The following are the reserved traits Segment has standardized: | `website` | String | Website of a group. | | `plan` | String | Plan that a group is in. | -**Note:** You might be used to some destinations recognizing special properties differently. For example, Mixpanel has a special `track_charges` method for accepting revenue. Luckily, you don't have to worry about those inconsistencies. Just pass along `revenue`. **Segment handles all of the destination-specific conversions for you automatically.** Same goes for the rest of the reserved properties. +**Note:** You might be used to some destinations recognizing special properties differently. For example, Mixpanel has a special `track_charges` method for accepting revenue. **Segment handles all of the destination-specific conversions for you automatically.** -If you pass these values, `on null` will throw a `NullPointerException`. +If you pass a reserved trait, `on null` will throw a `NullPointerException`. You may continue to set values inside the trait. If you do so, this would work the same as the rules do with NoSQL data. If you had set a value previously for a user and on the next request you sent the same value of that property as `on null`, it will be replaced by `null`, but if you do not send that property, the original value is persisted. -**Traits are case-insensitive**, so in JavaScript you can match the rest of your camel-case code by sending `createdAt`, and in Ruby you can match your snake-case code by sending `created_at`. That way the API never seems alien to your code base. - +**Traits are case-insensitive**. In JavaScript you can match the rest of your camel-case code by sending `createdAt`, and in Ruby you can match your snake-case code by sending `created_at`. That way, the API never seems alien to your code base. \ No newline at end of file From 86fefef309176b56e4f243bcbf3d78eb7da09ac5 Mon Sep 17 00:00:00 2001 From: forstisabella <92472883+forstisabella@users.noreply.github.com> Date: Fri, 31 Oct 2025 14:07:42 -0400 Subject: [PATCH 02/55] linked to snowflake delivery overview --- src/connections/delivery-overview.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/connections/delivery-overview.md b/src/connections/delivery-overview.md index cc64ab5474..4546dd2169 100644 --- a/src/connections/delivery-overview.md +++ b/src/connections/delivery-overview.md @@ -50,12 +50,22 @@ The pipeline view for storage destination includes the following steps: - **Filtered at destination**: Events that were discarded due to [Destination Filters](/docs/guides/filtering-data/#destination-filters), [filtering in the Integrations object](/docs/guides/filtering-data/#filtering-with-the-integrations-object), [Destination Insert functions](/docs/connections/functions/insert-functions/), or [per source schema integration filters](/docs/guides/filtering-data/#per-source-schema-integrations-filters). [Actions destinations](/docs/connections/destinations/actions/) also have a filtering capability: for example, if your Action is set to only send Identify events, all other event types will be filtered out. Actions destinations with incomplete triggers or disabled mappings are filtered out at this step. [Consent Management](/docs/privacy/consent-management/) users also see events discarded due to consent preferences. - **Events to warehouse rows**: A read-only box that shows the point in the delivery process where Segment converts events into warehouse rows. - **Failed to sync**: Syncs that either failed to sync or were partially successful. Selecting this step takes you to a table of all syncs with one or more failed collections. Select a sync from the table to view the discard reason, any collections that failed, the status, and the number of rows that synced for each collection. For information about common errors, see Ware -- **Successfully synced**: A record of all successful or partially successful syncs made with your destination. To view the reason a partially successfully sync was not fully successful, see the Failed to sync step. +- **Successfully synced**: A record of all successful or partially successful syncs made with your destination. To view the reason a partially successfully sync was not fully successful, see the Failed to sync step. The following image shows a storage destination with 23 partially successful syncs: ![A screenshot of the Delivery Overview tab for a Storage destination, with the Failed to sync step selected and a table of partially successful syncs.](images/delivery-overview-storage-destinations.png) +##### Linked Audiences to Snowflake destination + +You can send Linked Audiences downstream to the Snowflake destination with the following steps: +- **Events from audience***: Events that Segment created for your activation. The number of events for each compute depends on the changes detected in your audience membership. +- **Filtered at source**: Events discarded by Protocols: either by the [schema settings](/docs/protocols/enforce/schema-configuration/) or [Tracking Plans](/docs/protocols/tracking-plan/create/). +- **Filtered at destination**: Events that were discarded due to [Destination Filters](/docs/guides/filtering-data/#destination-filters), [filtering in the Integrations object](/docs/guides/filtering-data/#filtering-with-the-integrations-object), [Destination Insert functions](/docs/connections/functions/insert-functions/), or [per source schema integration filters](/docs/guides/filtering-data/#per-source-schema-integrations-filters). [Actions destinations](/docs/connections/destinations/actions/) also have a filtering capability: for example, if your Action is set to only send Identify events, all other event types will be filtered out. Actions destinations with incomplete triggers or disabled mappings are filtered out at this step. [Consent Management](/docs/privacy/consent-management/) users also see events discarded due to consent preferences. +- **Events to warehouse rows**: A read-only box that shows the point in the delivery process where Segment converts events into Snowflake warehouse rows. +- **Failed to sync**: Syncs that either failed to sync or were partially successful. Selecting this step takes you to a table of all syncs with one or more failed collections. Select a sync from the table to view the discard reason, any collections that failed, the status, and the number of rows that synced for each collection. For information about common errors, see Ware +- **Successfully synced**: A record of all successful or partially successful syncs made with your destination. To view the reason a partially successfully sync was not fully successful, see the Failed to sync step. + #### Destinations connected to Engage Destinations > info "Delivery Overview for Engage Destinations is in Public Beta" From 2b55ed1384bd5a1a61d396a1ab20a01781152c75 Mon Sep 17 00:00:00 2001 From: alon-getrise Date: Mon, 3 Nov 2025 19:38:45 +0200 Subject: [PATCH 03/55] Update index.md Updated event names based on requirements for Proper Case --- src/connections/sources/catalog/cloud-apps/rise-ai/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/connections/sources/catalog/cloud-apps/rise-ai/index.md b/src/connections/sources/catalog/cloud-apps/rise-ai/index.md index e2375e3b60..ba9a901bd7 100644 --- a/src/connections/sources/catalog/cloud-apps/rise-ai/index.md +++ b/src/connections/sources/catalog/cloud-apps/rise-ai/index.md @@ -32,8 +32,8 @@ The table below lists events that Rise AI sends to Segment. These events appear | Event name | Description | | ------------------- | ------------------------------------------------------------------ | -| walkthrough-progress | User progress through AI-guided walkthroughs and onboarding flows | -| chats | AI chat session creation and interactions | +| Walkthrough Progress | User progress through AI-guided walkthroughs and onboarding flows | +| Chats | AI chat session creation and interactions | ## Event properties From 0498ebee5920c2c1738b8c24a58c83af79b10aa0 Mon Sep 17 00:00:00 2001 From: Vanessa Sun Date: Tue, 4 Nov 2025 16:08:54 -0500 Subject: [PATCH 04/55] add notes for profile updates --- .../catalog/actions-stackadapt-audiences/index.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/connections/destinations/catalog/actions-stackadapt-audiences/index.md b/src/connections/destinations/catalog/actions-stackadapt-audiences/index.md index 32e805c715..9c84bb6a48 100644 --- a/src/connections/destinations/catalog/actions-stackadapt-audiences/index.md +++ b/src/connections/destinations/catalog/actions-stackadapt-audiences/index.md @@ -9,7 +9,7 @@ redirect_from: "/connections/destinations/catalog/actions-stackadapt/" {% include content/plan-grid.md name="actions" %} -[StackAdapt](https://www.stackadapt.com/){:target="_blank"} is a leading programmatic advertising platform designed to maximize audience engagement. It enables marketers to run high-performing, cross-channel campaigns through real-time bidding, advanced audience targeting, and powerful data-driven insights. +[StackAdapt](https://www.stackadapt.com/){:target="\_blank"} is a leading programmatic advertising platform designed to maximize audience engagement. It enables marketers to run high-performing, cross-channel campaigns through real-time bidding, advanced audience targeting, and powerful data-driven insights. With the [Engage](/docs/engage/) integration, you can seamlessly sync your Engage Audiences and user data with StackAdapt to refine targeting precision and drive stronger campaign performance. @@ -60,6 +60,9 @@ Each Engage audience should only contain profiles that have a valid email addres - Select the source field for `Standard User Properties`. Ensure the source field matches the profile traits selected in step 4. You can learn more about the field format by hovering over the info icon of the field. - Follow the Destinations Actions documentation to [customize mappings](/docs/connections/destinations/actions/#customize-mappings). +> note "Trait synchronization" +> Both Custom, Computed, and Consent Traits are mapped and included in the initial data synchronization. However, for ongoing updates, please be aware that only Computed Traits will be updated within StackAdapt's Data Hub. + To verify that your audience syncs with StackAdapt, open StackAdapt and navigate to **Audience & Attribution > Customer Data > Profiles**. On the Profiles tab, you should be able to see a list of profiles being synced to the StackAdapt platform. > info "Syncs can take up to 4 hours" From d68392d2a9bff5163eebfb3e88c7ab6c75d43393 Mon Sep 17 00:00:00 2001 From: forstisabella <92472883+forstisabella@users.noreply.github.com> Date: Wed, 5 Nov 2025 09:52:02 -0500 Subject: [PATCH 05/55] Update src/connections/delivery-overview.md Co-authored-by: Sharon Adewusi --- src/connections/delivery-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connections/delivery-overview.md b/src/connections/delivery-overview.md index 4546dd2169..d9f31fda63 100644 --- a/src/connections/delivery-overview.md +++ b/src/connections/delivery-overview.md @@ -63,7 +63,7 @@ You can send Linked Audiences downstream to the Snowflake destination with the f - **Filtered at source**: Events discarded by Protocols: either by the [schema settings](/docs/protocols/enforce/schema-configuration/) or [Tracking Plans](/docs/protocols/tracking-plan/create/). - **Filtered at destination**: Events that were discarded due to [Destination Filters](/docs/guides/filtering-data/#destination-filters), [filtering in the Integrations object](/docs/guides/filtering-data/#filtering-with-the-integrations-object), [Destination Insert functions](/docs/connections/functions/insert-functions/), or [per source schema integration filters](/docs/guides/filtering-data/#per-source-schema-integrations-filters). [Actions destinations](/docs/connections/destinations/actions/) also have a filtering capability: for example, if your Action is set to only send Identify events, all other event types will be filtered out. Actions destinations with incomplete triggers or disabled mappings are filtered out at this step. [Consent Management](/docs/privacy/consent-management/) users also see events discarded due to consent preferences. - **Events to warehouse rows**: A read-only box that shows the point in the delivery process where Segment converts events into Snowflake warehouse rows. -- **Failed to sync**: Syncs that either failed to sync or were partially successful. Selecting this step takes you to a table of all syncs with one or more failed collections. Select a sync from the table to view the discard reason, any collections that failed, the status, and the number of rows that synced for each collection. For information about common errors, see Ware +- **Failed to sync**: Syncs that either failed to sync or were partially successful. Selecting this step takes you to a table of all syncs with one or more failed collections. Select a sync from the table to view the discard reason, any collections that failed, the status, and the number of rows that synced for each collection. For information about common errors, see [Warehouse Errors](docs/connections/storage/warehouses/warehouse-errors). - **Successfully synced**: A record of all successful or partially successful syncs made with your destination. To view the reason a partially successfully sync was not fully successful, see the Failed to sync step. #### Destinations connected to Engage Destinations From 0be55ea69a8a2c982b27d8b9d6fdfe1c3730e841 Mon Sep 17 00:00:00 2001 From: Carolina Lopez Date: Thu, 6 Nov 2025 15:09:03 -0500 Subject: [PATCH 06/55] Remove `>` - They are not shown --- .../destinations/catalog/actions-ms-bing-capi/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/connections/destinations/catalog/actions-ms-bing-capi/index.md b/src/connections/destinations/catalog/actions-ms-bing-capi/index.md index 758f4c835e..1fc8dc4670 100644 --- a/src/connections/destinations/catalog/actions-ms-bing-capi/index.md +++ b/src/connections/destinations/catalog/actions-ms-bing-capi/index.md @@ -16,8 +16,8 @@ redirect_from: "/connections/destinations/catalog/microsoft-bing-capi/" 3. Select an existing source to connect to the destination. 4. Give the destination a name and click **Create destination**. 5. In **Basic Settings**, enter the Bing **UetTag** and **ApiToken**. - > * To find the UET tag, see Microsoft's steps on [how to create a UET tag](https://help.ads.microsoft.com/#apex/3/en/56682/2-500){:target="_blank"}. - > * To generate the API token, contact [Microsoft support](https://about.ads.microsoft.com/en/support){:target="_blank"} or fill out a [request form](https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbRwMZAe0PcMxHmZ0AjDaNRmxUM0o5UURRVktCRkxHNEFLTVNYQjI3NDNBUS4u){:target="_blank"}. + * To find the UET tag, see Microsoft's steps on [how to create a UET tag](https://help.ads.microsoft.com/#apex/3/en/56682/2-500){:target="_blank"}. + * To generate the API token, contact [Microsoft support](https://about.ads.microsoft.com/en/support){:target="_blank"} or fill out a [request form](https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbRwMZAe0PcMxHmZ0AjDaNRmxUM0o5UURRVktCRkxHNEFLTVNYQjI3NDNBUS4u){:target="_blank"}. 6. Toggle **Enable Destination** on to start sending data to Microsoft Bing CAPI from Segment. {% include components/actions-fields.html %} From feb4c313add84b5fea1a110c112a04e9899a9bec Mon Sep 17 00:00:00 2001 From: Wenxi Zeng Date: Thu, 6 Nov 2025 15:09:07 -0600 Subject: [PATCH 07/55] update kotlin setup guide --- .../auto-instrumentation/kotlin-setup.md | 264 ++++++++++-------- 1 file changed, 142 insertions(+), 122 deletions(-) diff --git a/src/connections/auto-instrumentation/kotlin-setup.md b/src/connections/auto-instrumentation/kotlin-setup.md index b7fa63241a..90e0fb81c7 100644 --- a/src/connections/auto-instrumentation/kotlin-setup.md +++ b/src/connections/auto-instrumentation/kotlin-setup.md @@ -25,159 +25,173 @@ Signals supports [Jetpack Compose](https://developer.android.com/compose){:targe Segment recommends testing in a development environment before deploying Signals in production. For more information, see [Debug mode](#step-4-enable-debug-mode). -## Step 1: Install dependencies +## Prerequisites -To install Signals, add the following dependencies to your app-level Gradle build file. +Auto-Instrumentation (aka Signals) works on top of Analytics and Live Plugins. Make sure to add the following dependencies to your module's Gradle file if you don't have them already. ```groovy -dependencies { - // Core Analytics Kotlin library - implementation("com.segment.analytics.kotlin:android:1.19.1") - - // Live plugin for real-time analytics - implementation("com.segment.analytics.kotlin:analytics-kotlin-live:1.1.0") - - // Signals core library - implementation("com.segment.analytics.kotlin.signals:core:0.5.0") - - // Optional: Jetpack Compose UI tracking - implementation("com.segment.analytics.kotlin.signals:compose:0.5.0") - - // Optional: OkHttp3 network request tracking - implementation("com.segment.analytics.kotlin.signals:okhttp3:0.5.0") - - // Optional: Screen and route tracking for Navigation components - implementation("com.segment.analytics.kotlin.signals:navigation:0.5.0") - - // Optional: HttpURLConnection tracking - implementation("com.segment.analytics.kotlin.signals:java-net:0.5.0") -} +// analytics kotlin +implementation ("com.segment.analytics.kotlin:android:1.22.0") +// live plugin +implementation("com.segment.analytics.kotlin:analytics-kotlin-live:1.3.0") ``` -The core libraries are required to enable Signals and real-time analytics. Use the following optional plugins to track additional activity based on your app's architecture: - -- **Compose**: Tracks user interface events in Jetpack Compose. -- **OkHttp3**: Captures requests sent through OkHttp3 or Retrofit. -- **Navigation**: Tracks route changes when using Jetpack Navigation. -- **JavaNet**: Tracks network activity sent through `HttpURLConnection`. - -Only add the plugins you plan to use. You can add or remove them later without reinitializing your source. - -## Step 2: Initialize the SDK - -After you add dependencies, you need to initialize the Analytics client and configure the Signals plugin. - -Start by creating the `Analytics` instance using your source's write key. Then add the Signals plugin and configure its settings separately. - -```kotlin -// Create the Analytics instance with your configuration -val analytics = Analytics(Configuration(writeKey = "")) - -// Add the live plugin for real-time event handling -analytics.add(LivePlugins()) +## Step 1: Getting started -// Add the Signals plugin -analytics.add(Signals) - -// Configure Signals settings -Signals.configuration = Configuration( - maximumBufferSize = 1000, // Number of signals to keep in memory - broadcastInterval = 60, // Send signals every 60 seconds - broadcasters = listOf(WebhookBroadcaster("YOUR_WEBHOOK")), // Optional - debugMode = true // For development use only -) - -// Optional: Add the Compose plugin to track UI events and interactions -analytics.add(SignalsComposeTrackingPlugin()) +Instrumentation becomes as simple as adding dependencies to your module's Gradle file: +1. Add Signals Core + ```groovy + // signal core + implementation ("com.segment.analytics.kotlin.signals:core:1.0.0") + ``` +2. Initialize Signals + ```kotlin + //... .... + analytics.add(LivePlugins()) // Make sure LivePlugins is added + analytics.add(Signals) // Add the signals plugin + + Signals.configuration = Configuration( + // sendDebugSignalsToSegment will relay events to Segment server. Should only be true for development purposes. + sendDebugSignalsToSegment = true + // obfuscateDebugSignals will obfuscate sensitive data + obfuscateDebugSignals = true + // .. other options + ) + ``` +3. Add proper dependency and plugin as needed to: + * [Capture Interactions](#capture-interactions) + * [Capture Navigation](#capture-navigation) + * [Capture Network](#capture-network) -// Optional: Track screen transitions using Navigation -analytics.add(SignalsActivityTrackingPlugin()) -navController.turnOnScreenTracking() -``` +## Step 2: Additional setup -When you run this code, keep the following in mind: +### Capture Interactions -- You need to replace `` with the key from your Android Source in Segment. -- `debugMode` sends signals to Segment for use in the Event Builder. Only enable it in development environments. -- If your app doesn't use Jetpack Compose or Navigation, you can skip those plugin lines. +#### Kotlin Compose -For more options, see [Configuration options reference](#configuration-options). +1. Add the dependency to your module’s Gradle build file. + ```groovy + implementation ("com.segment.analytics.kotlin.signals:compose:1.0.0") + ``` -## Step 3: Track network requests +2. Add `SignalsComposeTrackingPlugin` to analytics + ```kotlin + analytics.add(SignalsComposeTrackingPlugin()) + ``` -Signals supports automatic tracking of network activity for apps that use OkHttp3, Retrofit, or `HttpURLConnection`. +#### Legacy XML UI -Add the relevant plugin based on your network stack. +1. Add uitoolkit Gradle Plugin dependency to project level `build.gradle` + ```groovy + buildscript { + dependencies { + classpath 'com.segment.analytics.kotlin.signals:uitoolkit-gradle-plugin:1.0.0' + } + } + ``` +2. Apply the plugin in your app level `build.gradle` and add the dependency + ```groovy + plugins { + // ...other plugins + id 'com.segment.analytics.kotlin.signals.uitoolkit-tracking' + } + + dependencies { + // ..other dependencies + implementation ("com.segment.analytics.kotlin.signals:uitoolkit:1.0.0") + } + ``` -### OkHttp3 -1. Add the dependency to your Gradle file: +### Capture Navigation +1. Add navigation Gradle Plugin dependency to project level `build.gradle` ```groovy - implementation("com.segment.analytics.kotlin.signals:okhttp3:0.5.0") + buildscript { + dependencies { + classpath 'com.segment.analytics.kotlin.signals:navigation-gradle-plugin:1.0.0' + } + } ``` - -2. Add the tracking plugin to your `OkHttpClient`: - +2. Apply the plugin in your app level `build.gradle` and add the dependency + ```groovy + plugins { + // ...other plugins + id 'com.segment.analytics.kotlin.signals.navigation-tracking' + } + + dependencies { + // ..other dependencies + implementation ("com.segment.analytics.kotlin.signals:navigation:1.0.0") + } + ``` +3. (Optional) Add `SignalsActivityTrackingPlugin` to analytics to track Activity/Fragment navigation. **Not required for Compose Navigation** ```kotlin - val okHttpClient = OkHttpClient.Builder() - .addInterceptor(SignalsOkHttp3TrackingPlugin()) - .build() + analytics.add(SignalsActivityTrackingPlugin()) ``` -### Retrofit - -Retrofit is built on top of OkHttp, so the setup is similar. - -1. Add the same OkHttp3 plugin shown in the previous sectiion: +### Capture Network +#### OkHttp + +1. add dependency: ```groovy - implementation("com.segment.analytics.kotlin.signals:okhttp3:0.5.0") + implementation ("com.segment.analytics.kotlin.signals:okhttp3:1.0.0") ``` -2. Attach the plugin through your Retrofit client configuration: - +2. add `SignalsOkHttp3TrackingPlugin` as an interceptor to your OkHttpClient: ```kotlin - val okHttpClient = OkHttpClient.Builder() - .addInterceptor(SignalsOkHttp3TrackingPlugin()) - .build() - - val retrofit = Retrofit.Builder() - .client(okHttpClient) - .baseUrl("https://your.api.endpoint") - .build() + private val okHttpClient = OkHttpClient.Builder() + .addInterceptor(SignalsOkHttp3TrackingPlugin()) + .build() ``` -### HttpURLConnection - -1. Add the JavaNet plugin dependency: +#### Retrofit +1. add dependency: ```groovy - implementation("com.segment.analytics.kotlin.signals:java-net:0.5.0") + implementation ("com.segment.analytics.kotlin.signals:okhttp3:1.0.0") ``` -2. Install the plugin at runtime: - +2. add `SignalsOkHttp3TrackingPlugin` as an interceptor to your Retrofit client: ```kotlin - JavaNetTrackingPlugin.install() + private val okHttpClient = OkHttpClient.Builder() + .addInterceptor(SignalsOkHttp3TrackingPlugin()) + .build() + + val retrofit = Retrofit.Builder() + .client(okHttpClient) + .build() ``` -Depending on your app’s network stack, you may only need one plugin. If your app uses multiple clients, you can install more than one plugin. +#### java.net.HttpURLConnection + 1. add dependency: + ```groovy + implementation ("com.segment.analytics.kotlin.signals:java-net:1.0.0") + ``` + + 2. install the `JavaNetTrackingPlugin` on where you initialize analytics: + ```kotlin + JavaNetTrackingPlugin.install() + ``` -## Step 4: Enable debug mode + +## Step 3: Enable debug mode By default, Signals stores captured data on the device and doesn't forward it to Segment. This process prevents unnecessary bandwidth use and helps support privacy compliance requirements. -To view captured signals in the Event Builder and create event generation rules, you need to enable `debugMode`. This setting temporarily lets the SDK send signal data to Segment while you're testing. +To view captured signals in the Event Builder and create event generation rules, you need to enable `sendDebugSignalsToSegment`. This setting temporarily lets the SDK send signal data to Segment while you're testing. + +In addition, the SDK obfuscates signals sent to Segment by default. To view the completed data, you need to turn off `obfuscateDebugSignals`. > warning "" -> Only enable `debugMode` in development environments. Avoid using `debugMode` in production apps. +> Only enable `sendDebugSignalsToSegment` in development environments. Avoid using `sendDebugSignalsToSegment` in production apps. -You can enable `debugMode` in one of two ways. +You can enable `sendDebugSignalsToSegment` and turn off `obfuscateDebugSignals` in one of two ways. ### Option 1: Use build flavors -Configure `debugMode` at build time using [Android product flavors](https://developer.android.com/build/build-variants#product-flavors){:target="_blank"}. +Configure `sendDebugSignalsToSegment` and `obfuscateDebugSignals` at build time using [Android product flavors](https://developer.android.com/build/build-variants#product-flavors){:target="_blank"}. 1. In your `build.gradle` file, define two flavors: @@ -186,10 +200,12 @@ Configure `debugMode` at build time using [Android product flavors](https://deve ... productFlavors { prod { - buildConfigField "boolean", "DEBUG_MODE", "false" + buildConfigField "boolean", "SEND_DEBUG_SIGNALS_TO_SEGMENT", "false" + buildConfigField "boolean", "OBFUSCATE_DEBUG_SIGNALS", "true" } dev { - buildConfigField "boolean", "DEBUG_MODE", "true" + buildConfigField "boolean", "SEND_DEBUG_SIGNALS_TO_SEGMENT", "true" + buildConfigField "boolean", "OBFUSCATE_DEBUG_SIGNALS", "false" } } } @@ -199,19 +215,21 @@ Configure `debugMode` at build time using [Android product flavors](https://deve ```kotlin Signals.configuration = Configuration( - ... - debugMode = BuildConfig.DEBUG_MODE + // ... other config options + sendDebugSignalsToSegment = BuildConfig.SEND_DEBUG_SIGNALS_TO_SEGMENT + obfuscateDebugSignals = BuildConfig.OBFUSCATE_DEBUG_SIGNALS ) ``` ### Option 2: Use a feature flag -If your app uses [Firebase Remote Config](https://firebase.google.com/docs/remote-config){:target="_blank"} or a similar system, you can control `debugMode` remotely. +If your app uses [Firebase Remote Config](https://firebase.google.com/docs/remote-config){:target="_blank"} or a similar system, you can control `sendDebugSignalsToSegment` and `obfuscateDebugSignals` remotely. ```kotlin Signals.configuration = Configuration( ... - debugMode = remoteConfig.getBoolean("debug_mode") + sendDebugSignalsToSegment = remoteConfig.getBoolean("sendDebugSignalsToSegment") + obfuscateDebugSignals = remoteConfig.getBoolean("obfuscateDebugSignals") ) ``` @@ -226,13 +244,13 @@ After you build and run your app, use the [Event Builder](/docs/connections/auto - Tap buttons and UI elements. - Trigger network requests. -If `debugMode` is enabled, Signals appear in real time as you interact with the app. +If `sendDebugSignalsToSegment` is enabled, Signals appear in real time as you interact with the app. 4. In the Event Builder, select a signal and click **Configure event** to define a new event. 5. After you add any event mappings, click **Publish event rules** to save them. > info "What if I don't see the Event Builder tab?" -> If you don't see the Event Builder tab, confirm that the SDK is installed correctly and make sure `debugMode` is enabled. Verify that Auto-Instrumentation is enabled in **Settings > Advanced**. If you still don't see it, reach out to your CSM. +> If you don't see the Event Builder tab, confirm that the SDK is installed correctly and make sure `sendDebugSignalsToSegment` is enabled. Verify that Auto-Instrumentation is enabled in **Settings > Advanced**. If you still don't see it, reach out to your CSM. ## Configuration options @@ -240,12 +258,14 @@ Use the `Signals.configuration` object to control how captured signals are store The following table lists the available options: -| Option | Required | Type | Default | Description | -| ------------------- | -------- | ------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `maximumBufferSize` | No | `Int` | `1000` | The number of captured signals to keep in memory before relaying them. Signals get stored in a first-in, first-out buffer. | -| `broadcastInterval` | No | `Int` (seconds) | `60` | The interval, in seconds, at which buffered signals are sent to broadcasters. | -| `broadcasters` | No | `List` | N/A | A list of broadcasters that forward signal data to external destinations. `SegmentBroadcaster` is included by default, and you can add others like `WebhookBroadcaster` or a custom implementation. | -| `debugMode` | No | `Boolean` | `false` | When `true`, relays signals to Segment so they appear in the Event Builder. Only enable this in development environments. | +| OPTION | REQUIRED | VALUE | DESCRIPTION | +|------------------|----------|---------------------------|-------------| +| **maximumBufferSize** | No | Integer | The number of signals to be kept for JavaScript inspection. This buffer is first-in, first-out. Default is **1000**. | +| **relayCount** | No | Integer | Relays every X signals to Segment. Default is **20**. | +| **relayInterval** | No | Integer | Relays signals to Segment every X seconds. Default is **60**. | +| **broadcasters** | No | List | An array of broadcasters. These objects forward signal data to their destinations, like **WebhookBroadcaster**, or you could write your own **DebugBroadcaster** that writes logs to the developer console. **SegmentBroadcaster** is always added by the SDK. | +| **sendDebugSignalsToSegment** | No | Boolean | Turns on debug mode and allows the SDK to relay Signals to Segment server. Default is **false**. It should only be set to true for development purposes. | +| **obfuscateDebugSignals** | No | Boolean | Obfuscates signals being relayed to Segment. Default is **true**. | ## Next steps From 252f27b008dbaec8fad50dd9296828365a51930c Mon Sep 17 00:00:00 2001 From: Wenxi Zeng Date: Thu, 6 Nov 2025 15:28:45 -0600 Subject: [PATCH 08/55] update swift setup guide --- .../auto-instrumentation/swift-setup.md | 307 +++++++++++++++--- 1 file changed, 258 insertions(+), 49 deletions(-) diff --git a/src/connections/auto-instrumentation/swift-setup.md b/src/connections/auto-instrumentation/swift-setup.md index 7133f052d8..cbc4691e8f 100644 --- a/src/connections/auto-instrumentation/swift-setup.md +++ b/src/connections/auto-instrumentation/swift-setup.md @@ -12,7 +12,7 @@ Learn how to connect an existing source, integrate dependencies, turn on Auto-In > info "Regional availability" > Auto-Instrumentation isn't supported in EU workspaces. -## Step 1: Get your source write key +## Before you start You need the `writeKey` from an existing Segment source. To find it: @@ -21,60 +21,265 @@ You need the `writeKey` from an existing Segment source. To find it: 3. From the source's overview tab, go to **Settings > API Keys**. 4. Copy the `writeKey` shown in the code block. -## Step 2: Add dependencies and initialization code -Next, add the Signals SDKs to your Swift applicatiion. +## Prerequisites -1. Use Swift Package Manager to add the Signals SDK from the following repository: +Auto-Instrumentation (aka Signals) works on top of Analytics. Make sure to add the following dependency to your project if you don't have analytics-swift already. - ```zsh - https://github.com/segment-integrations/analytics-swift-live.git - ``` +```swift +dependencies: [ + .package(url: "https://github.com/segmentio/analytics-swift.git", from: "1.9.1") +] +``` -2. Add the initialization code and configuration options: +## Step 1: Getting started + +1. Add AnalyticsLive to your Swift Package dependencies: + ```swift + dependencies: [ + .package(url: "https://github.com/segmentio/analytics-live-swift.git", from: "3.2.1") + ] + ``` +2. Import and initialize with your Analytics instance: + > success "" > See [configuration options](#configuration-options) for a complete list. +> + ```swift + import Segment + import AnalyticsLive + + let analytics = Analytics(configuration: Configuration(writeKey: "YOUR_WRITE_KEY")) + + // Add LivePlugins first + analytics.add(plugin: LivePlugins()) + + // Add Signals + analytics.add(plugin: Signals.shared) + + // Configure Signals + Signals.shared.useConfiguration(SignalsConfiguration( + writeKey: "YOUR_WRITE_KEY", // Same writeKey as Analytics + useUIKitAutoSignal: true, + useSwiftUIAutoSignal: true, + useNetworkAutoSignal: true, + #if DEBUG + // NOTE: See section below on using these flags appropriately. + sendDebugSignalsToSegment: true, // Only true for development + obfuscateDebugSignals: false // Only false for development + #endif + // ... other options + )) + ``` + +3. Set up capture for the UI framework(s) you're using: + * [Capture SwiftUI Interactions](#swiftui) + * [Capture UIKit Interactions](#uikit) + * [Capture Network Activity](#capture-network) + +## Step 2: Additional setup + +### Capture Interactions + +#### SwiftUI + +SwiftUI automatic signal capture requires adding typealiases to your code. This is necessary because SwiftUI doesn't provide hooks for automatic instrumentation. + +1. Enable SwiftUI auto-signals in your configuration: ```swift - // Configure Analytics with your settings - {... ....} + Signals.shared.useConfiguration(SignalsConfiguration( + writeKey: "YOUR_WRITE_KEY", + useSwiftUIAutoSignal: true + // ... other options + )) + ``` - // Set up the Signals SDK configuration - let config = Signals.Configuration( - writeKey: "", // Replace with the write key you previously copied - maximumBufferSize: 100, - useSwiftUIAutoSignal: true, - useNetworkAutoSignal: true - ) +2. Add the following typealiases to your SwiftUI views or in a shared file: + ```swift + import SwiftUI + import AnalyticsLive + + // Navigation + typealias NavigationLink = SignalNavigationLink + typealias NavigationStack = SignalNavigationStack // iOS 16+ + + // Selection & Input Controls + typealias Button = SignalButton + typealias TextField = SignalTextField + typealias SecureField = SignalSecureField + typealias Picker = SignalPicker + typealias Toggle = SignalToggle + typealias Slider = SignalSlider // Not available on tvOS + typealias Stepper = SignalStepper // Not available on tvOS + + // List & Collection Views + typealias List = SignalList + ``` - // Locate and set the fallback JavaScript file for edge functions - let fallbackURL = Bundle.main.url(forResource: "MyEdgeFunctions", withExtension: "js") +3. Use the controls normally in your SwiftUI code: + ```swift + struct ContentView: View { + var body: some View { + NavigationStack { + VStack { + Button("Click Me") { + // Button tap will automatically generate a signal + } + + TextField("Enter text", text: $text) + // Text changes will automatically generate signals + } + } + } + } + ``` + +> **Note:** The typealiases replace SwiftUI's native controls with signal-generating versions. Your code remains unchanged, but interactions are now automatically captured. + +#### UIKit + +UIKit automatic signal capture uses method swizzling and requires no code changes. - // Apply the configuration and add the Signals plugin - Signals.shared.useConfiguration(config) - Analytics.main.add(plugin: LivePlugins(fallbackFileURL: fallbackURL)) - Analytics.main.add(plugin: Signals.shared) +1. Enable UIKit auto-signals in your configuration: + ```swift + Signals.shared.useConfiguration(SignalsConfiguration( + writeKey: "YOUR_WRITE_KEY", + useUIKitAutoSignal: true + // ... other options + )) ``` -Verify that you replaced `` with the actual write key you copied in [Step 1](#step-1-get-your-source-write-key). +2. That's it! The following UIKit interactions and navigation events are automatically captured via method swizzling: + + **Interactions:** + - `UIButton` taps + - `UISlider` value changes + - `UIStepper` value changes + - `UISwitch` toggle events + - `UITextField` text changes + - `UITableViewCell` selections + + **Navigation:** + - `UINavigationController` push/pop operations + - `UIViewController` modal presentations and dismissals + - `UITabBarController` tab switches + +### Capture Navigation + +Navigation capture is handled automatically when you enable SwiftUI or UIKit auto-signals: + +- **SwiftUI**: Captured through `SignalNavigationLink` and `SignalNavigationStack` when you add the typealiases +- **UIKit**: Captured automatically via `UINavigationController`, `UIViewController`, and `UITabBarController` swizzling -#### SwiftUI projects +No additional setup required beyond enabling the appropriate auto-signal flags. -If your app is written in SwiftUI, you need to add a `TypeAlias.swift` file to your project that captures interaction and navigation Signals, like in this example: +### Capture Network + +Network capture automatically tracks URLSession requests and responses. + +1. Enable network auto-signals in your configuration: + ```swift + Signals.shared.useConfiguration(SignalsConfiguration( + writeKey: "YOUR_WRITE_KEY", + useNetworkAutoSignal: true, + allowedNetworkHosts: ["*"], // Allow all hosts (default) + blockedNetworkHosts: [] // Block specific hosts (optional) + // ... other options + )) + ``` + +2. Network requests made via URLSession are automatically captured, including: + - Request URL, method, headers, and body + - Response status, headers, and body + - Request/response correlation via request ID + +> **Note:** Third-party networking libraries that use URLSession underneath (like Alamofire) should work automatically. Segment API endpoints are automatically blocked to prevent recursive tracking. + +#### Configuring Network Hosts + +You can control which network requests are tracked: ```swift -import Foundation -import Signals - -typealias Button = SignalButton -typealias NavigationStack = SignalNavigationStack -typealias NavigationLink = SignalNavigationLink -typealias TextField = SignalTextField -typealias SecureField = SignalSecureField +SignalsConfiguration( + writeKey: "YOUR_WRITE_KEY", + useNetworkAutoSignal: true, + allowedNetworkHosts: ["api.myapp.com", "*.example.com"], // Only track these hosts + blockedNetworkHosts: ["analytics.google.com"] // Exclude these hosts +) ``` -## Step 3: Turn on Auto-Instrumentation in your source +- `allowedNetworkHosts`: Array of host patterns to track. Use `"*"` to allow all hosts (default). +- `blockedNetworkHosts`: Array of host patterns to exclude from tracking. + +The following hosts are automatically blocked to prevent recursive tracking: +- `api.segment.com` +- `cdn-settings.segment.com` +- `signals.segment.com` +- `api.segment.build` +- `cdn.segment.build` +- `signals.segment.build` + +## Step 3: Enable debug mode + +By default, Signals stores captured data on the device and doesn't forward it to Segment. This process prevents unnecessary bandwidth use and helps support privacy compliance requirements. + +To view captured signals in the Event Builder and create event generation rules, you need to enable `sendDebugSignalsToSegment`. This setting temporarily lets the SDK send signal data to Segment while you're testing. + +In addition, the SDK obfuscates signals sent to Segment by default. To view the completed data, you need to turn off `obfuscateDebugSignals`. + +> warning "" +> Only enable `sendDebugSignalsToSegment` in development environments. Avoid using `sendDebugSignalsToSegment` in production apps. + +You can enable `sendDebugSignalsToSegment` and turn off `obfuscateDebugSignals` in one of three ways. + +### Option 1: Use Build Configurations to Toggle Debug Mode + + 1. Define different configurations in your project settings (Debug, Release, etc.) + + 2. Use compiler flags to control the setting: + ```swift + Signals.shared.useConfiguration(SignalsConfiguration( + writeKey: "YOUR_WRITE_KEY", + // ... other config options + #if DEBUG + sendDebugSignalsToSegment: true, + obfuscateDebugSignals: false + #else + sendDebugSignalsToSegment: false, + obfuscateDebugSignals: true + #endif + )) + ``` + +### Option 2: Use a Feature Flag System + If you're using Firebase Remote Config or a similar feature flag system, you can dynamically control `sendDebugSignalsToSegment` and `obfuscateDebugSignals` without requiring a new app build: + ```swift + let remoteConfig = RemoteConfig.remoteConfig() + + Signals.shared.useConfiguration(SignalsConfiguration( + writeKey: "YOUR_WRITE_KEY", + // ... other config options + sendDebugSignalsToSegment: remoteConfig["sendDebugSignalsToSegment"].boolValue, + obfuscateDebugSignals: remoteConfig["obfuscateDebugSignals"].boolValue + )) + ``` + +### Option 3: Use Environment Variables (for debugging/testing) + You can check for environment variables or launch arguments during development: + ```swift + let isDebugEnabled = ProcessInfo.processInfo.environment["SIGNALS_DEBUG"] != nil + + Signals.shared.useConfiguration(SignalsConfiguration( + writeKey: "YOUR_WRITE_KEY", + // ... other config options + sendDebugSignalsToSegment: isDebugEnabled, + obfuscateDebugSignals: !isDebugEnabled + )) + ``` + +## Step 4: Turn on Auto-Instrumentation in your source Next, return to the source settings to turn on Auto-Instrumentation: @@ -83,7 +288,7 @@ Next, return to the source settings to turn on Auto-Instrumentation: 3. From the source's overview tab, go to **Settings > Advanced**. 4. Toggle Auto-Instrumention on. -## Step 4: Verify and deploy events +## Step 5: Verify and deploy events After integrating the SDK and running your app, verify that Segment is collecting signals: @@ -91,7 +296,7 @@ After integrating the SDK and running your app, verify that Segment is collectin 2. In the source overview, look for the **Event Builder** tab. If the tab doesn’t appear: - Make sure you've installed the SDK correctly. - Reach out to your Segment CSM to confirm that your workspace has the necessary feature flags enabled. -3. Launch your app [in debug mode](https://github.com/segmentio/analytics-next/tree/master/packages/signals/signals#sending-and-viewing-signals-on-segmentcom-debug-mode){:target="_blank"}. This enables signal collection so you can see activity in the Event Builder. +3. If `sendDebugSignalsToSegment` is enabled, Signals appear in real time in the Event Builder as you interact with the app. 4. Use the app as a user would: navigate between screens, tap buttons, trigger network requests. Signals appear in real time as you interact with the app. 5. In the Event Builder, find a signal and click **Configure event** to define a new event. After configuring the event, click **Publish event rules**. @@ -99,18 +304,22 @@ After integrating the SDK and running your app, verify that Segment is collectin Using the Signals Configuration object, you can control the destination, frequency, and types of signals that Segment automatically tracks within your application. The following table details the configuration options for Signals-Swift. -| `Option` | Required | Value | Description | -| ---------------------- | -------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `writeKey` | Yes | String | Source write key | -| `maximumBufferSize` | No | Integer | The number of signals to be kept for JavaScript inspection. This buffer is first-in, first-out. Default is `1000`. | -| `relayCount` | No | Integer | Relays signals to Segment every Xth event. Default is `20`. | -| `relayInterval` | No | TimeInterval | Relays signals to segment every X seconds. Default is `60`. | -| `broadcasters` | No | `SignalBroadcaster` | An array of broadcasters. These objects forward signal data to their destinations, like `WebhookBroadcaster` or `DebugBroadcaster` writing to the developer console. Default is `SegmentBroadcaster`. | -| `useUIKitAutoSignal` | No | Bool | Tracks UIKit component interactions automatically. Default is `false`. | -| `useSwiftUIAutoSignal` | No | Bool | Tracks SwiftUI component interactions automatically. Default is `false`. | -| `useNetworkAutoSignal` | No | Bool | Tracks network events automatically. Default is `false`. | -| `allowedNetworkHosts` | No | Array | An array of allowed network hosts. | -| `blockedNetworkHosts` | No | Array | An array of blocked network hosts. + +| OPTION | REQUIRED | VALUE | DESCRIPTION | +|------------------|----------|---------------------------|-------------| +| **writeKey** | Yes | String | Your Segment write key. Should match your Analytics instance writeKey. | +| **maximumBufferSize** | No | Int | The number of signals to be kept for JavaScript inspection. This buffer is first-in, first-out. Default is **1000**. | +| **relayCount** | No | Int | Relays every X signals to Segment. Default is **20**. | +| **relayInterval** | No | TimeInterval | Relays signals to Segment every X seconds. Default is **60**. | +| **broadcasters** | No | [SignalBroadcaster] | An array of broadcasters. These objects forward signal data to their destinations, like **WebhookBroadcaster**, or you could write your own **DebugBroadcaster** that writes logs to the developer console. **SegmentBroadcaster** is always added by the SDK when `sendDebugSignalsToSegment` is true. | +| **sendDebugSignalsToSegment** | No | Bool | Turns on debug mode and allows the SDK to relay Signals to Segment server. Default is **false**. It should only be set to true for development purposes. | +| **obfuscateDebugSignals** | No | Bool | Obfuscates signals being relayed to Segment. Default is **true**. | +| **apiHost** | No | String | API host for signal relay. Default is **"signals.segment.io/v1"**. | +| **useUIKitAutoSignal** | No | Bool | Enables automatic UIKit signal capture via method swizzling. Default is **false**. | +| **useSwiftUIAutoSignal** | No | Bool | Enables automatic SwiftUI signal capture (requires typealiases). Default is **false**. | +| **useNetworkAutoSignal** | No | Bool | Enables automatic network signal capture for URLSession. Default is **false**. | +| **allowedNetworkHosts** | No | [String] | Array of host patterns to track. Use `["*"]` for all hosts. Default is **["*"]**. | +| **blockedNetworkHosts** | No | [String] | Array of host patterns to exclude from tracking. Default is **[]**. | ## Next steps From 1f3da0ed9cd117ad886680500491567c1ddfc4c0 Mon Sep 17 00:00:00 2001 From: Wenxi Zeng Date: Thu, 6 Nov 2025 15:28:58 -0600 Subject: [PATCH 09/55] minor fix --- .../auto-instrumentation/kotlin-setup.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/connections/auto-instrumentation/kotlin-setup.md b/src/connections/auto-instrumentation/kotlin-setup.md index 90e0fb81c7..baff94dca4 100644 --- a/src/connections/auto-instrumentation/kotlin-setup.md +++ b/src/connections/auto-instrumentation/kotlin-setup.md @@ -45,6 +45,10 @@ Instrumentation becomes as simple as adding dependencies to your module's Gradle implementation ("com.segment.analytics.kotlin.signals:core:1.0.0") ``` 2. Initialize Signals + +> success "" +> See [configuration options](#configuration-options) for a complete list. +> ```kotlin //... .... analytics.add(LivePlugins()) // Make sure LivePlugins is added @@ -233,6 +237,15 @@ Signals.configuration = Configuration( ) ``` +## Step 4: Turn on Auto-Instrumentation in your source + +Next, return to the source settings to turn on Auto-Instrumentation: + +1. Go to **Connections > Sources**. +2. Select the source you used in Step 1. +3. From the source's overview tab, go to **Settings > Advanced**. +4. Toggle Auto-Instrumention on. + ## Step 5: Verify event collection After you build and run your app, use the [Event Builder](/docs/connections/auto-instrumentation/event-builder/) to confirm that Signals are being collected correctly. From 5108f0c7edcd1b35b5c6bc5c741c0bff856f8f79 Mon Sep 17 00:00:00 2001 From: Wenxi Zeng Date: Thu, 6 Nov 2025 16:06:55 -0600 Subject: [PATCH 10/55] link fix --- src/connections/auto-instrumentation/kotlin-setup.md | 3 +-- src/connections/auto-instrumentation/swift-setup.md | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/connections/auto-instrumentation/kotlin-setup.md b/src/connections/auto-instrumentation/kotlin-setup.md index baff94dca4..95025d4cd1 100644 --- a/src/connections/auto-instrumentation/kotlin-setup.md +++ b/src/connections/auto-instrumentation/kotlin-setup.md @@ -17,13 +17,12 @@ This guide shows how to install and configure the library, as well as how to ena To use Signals with Android, you need: - An active Segment workspace with Auto-Instrumentation enabled. -- A Kotlin-based Android project. - Android Gradle Plugin version 7.0 or later. - A minimum compile SDK version of 21. Signals supports [Jetpack Compose](https://developer.android.com/compose){:target="_blank"} and traditional Android UI frameworks. It also includes optional plugins for network tracking using [OkHttp3](https://square.github.io/okhttp/){:target="_blank"}, [Retrofit](https://square.github.io/retrofit/){:target="_blank"}, or [HttpURLConnection](https://developer.android.com/reference/java/net/HttpURLConnection){:target="_blank"}. -Segment recommends testing in a development environment before deploying Signals in production. For more information, see [Debug mode](#step-4-enable-debug-mode). +Segment recommends testing in a development environment before deploying Signals in production. For more information, see [Debug mode](#step-3-enable-debug-mode). ## Prerequisites diff --git a/src/connections/auto-instrumentation/swift-setup.md b/src/connections/auto-instrumentation/swift-setup.md index cbc4691e8f..785e002a06 100644 --- a/src/connections/auto-instrumentation/swift-setup.md +++ b/src/connections/auto-instrumentation/swift-setup.md @@ -21,6 +21,7 @@ You need the `writeKey` from an existing Segment source. To find it: 3. From the source's overview tab, go to **Settings > API Keys**. 4. Copy the `writeKey` shown in the code block. +Segment recommends testing in a development environment before deploying Signals in production. For more information, see [Debug mode](#step-3-enable-debug-mode). ## Prerequisites From 6197c51601c0afe5e86f4d105ea7aebf8c475034 Mon Sep 17 00:00:00 2001 From: pwseg Date: Thu, 6 Nov 2025 20:53:55 -0600 Subject: [PATCH 11/55] init --- .../identity-resolution/delete-profile-identifier-api.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/unify/identity-resolution/delete-profile-identifier-api.md diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md new file mode 100644 index 0000000000..936208c252 --- /dev/null +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -0,0 +1,5 @@ +--- +title: Delete Profile Identifier API +plan: unify +hidden: true +--- \ No newline at end of file From 68ebf29eeb2bd9e14e912191bd97acbed599bd91 Mon Sep 17 00:00:00 2001 From: pwseg Date: Thu, 6 Nov 2025 21:01:36 -0600 Subject: [PATCH 12/55] add prerequisites section --- .../delete-profile-identifier-api.md | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index 936208c252..428112f396 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -2,4 +2,40 @@ title: Delete Profile Identifier API plan: unify hidden: true ---- \ No newline at end of file +--- + +The Delete Profile Identifier API removes identifiers from a profile while preserving the profile's history, including traits, events, and merge history. + +Use this API to clean up outdated or incorrectly added identifiers without deleting entire profiles and replaying events. + +## Use cases + +Remove identifiers that shouldn't be associated with a profile: + +- Remove mistakenly imported identifiers, like incorrect email addresses, to prevent inaccurate targeting in downstream tools. +- Clean up obsolete identifiers after database migrations or system changes. +- Transfer identifiers with a short lifespan between profiles. For example, when a user changes phone numbers or when a prepaid service expires, you can remove the phone number from one profile and add it to another. +- Fix profiles that violate [ID Resolution limits](). Remove old identifiers to bring profiles into compliance with your configured limits. +- Revert misconfigured identity resolution settings. For example, if you reduced the `user_id` limit from 3 to 1, remove extra `user_id` values to resolve discrepancies between Segment and downstream tools like Braze or Amplitude. + +## Before you begin + +During private beta, the Delete Profile Identifier API is available to Unify and Engage. + +You must have one of the following role permissions to delete identifiers: + +- Workspace Owner +- Identity Admin +- Unify and Engage Admin + +For more information, see [the Roles documentation](/docs/segment-app/iam/roles/). + +### Profiles Sync configuration + +If you use [Profiles Sync](/docs/unify/profiles-sync/overview/), complete these steps before using the Delete Profile Identifier API: + +1. Add the `__operation` column to the `external_id_mapping_updates` table schema in your data warehouse: + - Default value: `CREATED` + - Deleted value: `REMOVED` +2. Verify that your analytics workloads (BI tools, data pipelines, ML models) can handle deleted identifiers. Make sure these systems remain operational and account for the `REMOVED` flag. + From 0f32c0b775dd0eca39d1d4a28e49bee72c4f02a4 Mon Sep 17 00:00:00 2001 From: pwseg Date: Thu, 6 Nov 2025 21:04:13 -0600 Subject: [PATCH 13/55] explain deletion process --- .../delete-profile-identifier-api.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index 428112f396..322569fbf4 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -39,3 +39,16 @@ If you use [Profiles Sync](/docs/unify/profiles-sync/overview/), complete these - Deleted value: `REMOVED` 2. Verify that your analytics workloads (BI tools, data pipelines, ML models) can handle deleted identifiers. Make sure these systems remain operational and account for the `REMOVED` flag. + + +## How deletion works + +When you delete an identifier, Segment removes it from [Identity Resolution](/docs/unify/identity-resolution/) and propagates the change through connected systems. + +The Delete Profile Identifier API confirms that Segment deleted the identifier from the Real-Time Identity Graph. Deletion then propagates to other systems: + +1. Real-time Profile storage**: The Profile API and Profile explorer delete the identifier in near real time. +2. Batch Profile Data lakehouse: Segment soft-deletes the identifier (flags it as deleted) in the append-only table within minutes. The identifier filters out from the materialized view within 24 hours. +3. Customer data warehouse: Profile Sync sends a deletion notification to your warehouse. The `external_id_mapping_updates` table shows the identifier with `__operation` set to `REMOVED`. The `user_identifiers` materialized view filters out removed identifiers. + + \ No newline at end of file From 140762ddaae440e35d79ee958f3d6b9acfe58124 Mon Sep 17 00:00:00 2001 From: pwseg Date: Thu, 6 Nov 2025 21:07:55 -0600 Subject: [PATCH 14/55] add responses --- .../delete-profile-identifier-api.md | 83 ++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index 322569fbf4..44bf9a867a 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -51,4 +51,85 @@ The Delete Profile Identifier API confirms that Segment deleted the identifier f 2. Batch Profile Data lakehouse: Segment soft-deletes the identifier (flags it as deleted) in the append-only table within minutes. The identifier filters out from the materialized view within 24 hours. 3. Customer data warehouse: Profile Sync sends a deletion notification to your warehouse. The `external_id_mapping_updates` table shows the identifier with `__operation` set to `REMOVED`. The `user_identifiers` materialized view filters out removed identifiers. - \ No newline at end of file + + +## Delete an identifier + +You can only delete identifiers from known profiles. The API requires a valid `user_id` to locate the profile. + +The API returns an error if you try to delete: + +- All `user_id` values from a profile. Profiles must have at least one `user_id`. +- A `group_id` identifier. The API only supports individual profiles. + +### API request format + +The API accepts one identifier per request. + +**Endpoint**: +``` +POST https://{HOST_NAME}/v1/spaces/{SPACE_ID}/collections/users/profiles/user_id:{USER_ID_VALUE}/external_ids/delete +``` + +**Parameters**: + +| Parameter | Description | +| ----------------- | ---------------------------------------------------------------------------------------------------- | +| **HOST_NAME** | `profiles.segment.com` for North America workspaces or `profiles.euw1.segment.com` for EU workspaces | +| **SPACE_ID** | Your space ID. Find this in **Unify > Settings > API access** | +| **USER_ID_VALUE** | The `user_id` value that identifies the profile | +| **AUTH_TOKEN** | Your access token. Generate this in **Unify > Settings > API access** | + +**Request body**: + +| Field | Description | +| ----------------------- | ------------------------------------------------------------------------------ | +| **delete_external_ids** | Array containing the identifier to delete. Limit: 1 identifier per request | +| **id** | Value of the identifier to delete (for example, `hello@gmail.com`) | +| **type** | Type of identifier to delete (for example, `email`, `anonymous_id`, `user_id`) | + + + +### Example request + +First, base64-encode your access token with a trailing colon: + +```bash +echo -n 'your_token:' | base64 +``` + +Then send the delete request: + +```bash +curl --location --request POST 'https://profiles.segment.com/v1/spaces/spa_abc123/collections/users/profiles/user_id:user_001/external_ids/delete' \ +--header 'Authorization: Basic ' \ +--header 'Content-Type: application/json' \ +--data '{ + "delete_external_ids": [ + { + "id": "example@gmail.com", + "type": "email" + } + ] +}' +``` +## Responses and error codes + +## HTTP responses + +| HTTP Code | Code | Message | +| --------- | -------------------- | --------------------------------------------------------------------- | +| 200 | success | external identifier has been deleted | +| 400 | unsupported_eid_type | unsupported external id type | +| 400 | bad_request | missing required parameters in URL | +| 400 | bad_request | invalid URL: valid `user_id` is required. unsupported `` | +| 400 | bad_request | only one external_id can be deleted at a time | +| 400 | bad_request | invalid collection: `` | +| 400 | bad_request | external id specification must differ from lookup id | +| 401 | unauthorized | the specified token is invalid | +| 403 | forbidden | Deleted identifier not activated for space_id `` | +| 404 | not_found | the resource was not found | +| 404 | eid_not_found | external identifier not found | +| 404 | source_id_not_found | no source attached to space_id `` | +| 429 | rate_limit_error | Attempted to delete more than 100 IDs per second for a single profile | + From 4cfa6429b77281f7b341240b8af373a103fbf38d Mon Sep 17 00:00:00 2001 From: pwseg Date: Thu, 6 Nov 2025 21:08:29 -0600 Subject: [PATCH 15/55] change header [netlify-build] --- src/unify/identity-resolution/delete-profile-identifier-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index 44bf9a867a..acf909bb75 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -115,7 +115,7 @@ curl --location --request POST 'https://profiles.segment.com/v1/spaces/spa_abc12 ``` ## Responses and error codes -## HTTP responses + | HTTP Code | Code | Message | | --------- | -------------------- | --------------------------------------------------------------------- | From e9086b8bd51650083a807defc916c6204f68c072 Mon Sep 17 00:00:00 2001 From: pwseg Date: Thu, 6 Nov 2025 21:23:29 -0600 Subject: [PATCH 16/55] some cleanup --- .../delete-profile-identifier-api.md | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index acf909bb75..2a2f5a8d80 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -45,7 +45,7 @@ If you use [Profiles Sync](/docs/unify/profiles-sync/overview/), complete these When you delete an identifier, Segment removes it from [Identity Resolution](/docs/unify/identity-resolution/) and propagates the change through connected systems. -The Delete Profile Identifier API confirms that Segment deleted the identifier from the Real-Time Identity Graph. Deletion then propagates to other systems: +After you send the request, the Delete Profile Identifier API confirms that Segment deleted the identifier from the Real-Time Identity Graph. Deletion then propagates to other systems: 1. Real-time Profile storage**: The Profile API and Profile explorer delete the identifier in near real time. 2. Batch Profile Data lakehouse: Segment soft-deletes the identifier (flags it as deleted) in the append-only table within minutes. The identifier filters out from the materialized view within 24 hours. @@ -53,7 +53,7 @@ The Delete Profile Identifier API confirms that Segment deleted the identifier f -## Delete an identifier +## Delete an identifier You can only delete identifiers from known profiles. The API requires a valid `user_id` to locate the profile. @@ -133,3 +133,39 @@ curl --location --request POST 'https://profiles.segment.com/v1/spaces/spa_abc12 | 404 | source_id_not_found | no source attached to space_id `` | | 429 | rate_limit_error | Attempted to delete more than 100 IDs per second for a single profile | +## Limitations and considerations + + + +### Deletion scope + +The Delete Profile Identifier API removes identifiers from Unify systems, including Identity Resolution, Profile Storage, and Profile Sync to your data warehouse. However, deletion doesn't extend to all Segment systems. Identifiers remain in the Event Archive and are soft-deleted in the Batch Profile Data Lakehouse. + +Segment doesn't delete identifiers from downstream destinations like Braze, Amplitude, Facebook, Engage Audiences, Journeys, Linked Audiences, or Consent settings. You must update these systems separately. + +### Rate limits + +Segment allows up to 100 deletion requests per second per space and 100 deletions per second for identifiers on a single profile. + +### Response time + +Most deletion requests complete in under 3 seconds. Deletions on profiles with more than 15 merges or 50 identifier mappings may take longer. + +Deletion propagates to connected systems at different speeds: +- **Real-Time Profile Storage**: seconds to 5 minutes +- **Profile Sync**: depends on your sync schedule + +### Space rebuilds and replays + +If you rebuild a space from Segment Archives, deletions don't replay automatically. You must rerun deletions after the replay completes. + +### Identifier reintroduction + +Segment may reintroduce deleted identifiers in the following cases: + +1. **Event replays**: Replaying events from the Event Archive that reference deleted identifiers adds them back to the profile. +2. **Engage or Journey sync timing**: Deleting an identifier within 5 minutes of sending an event that references it may result in the identifier being reintroduced through Engage-generated events. + +### Profile API source + +When you first use the Delete Profile Identifier API, Segment creates a `profile-api-source` for internal tracking. This source may appear in your workspace. From 01e4399249e33e8bae04fb1dd28607ef8f7ba493 Mon Sep 17 00:00:00 2001 From: pwseg Date: Thu, 6 Nov 2025 21:28:27 -0600 Subject: [PATCH 17/55] some more cleanup --- src/unify/identity-resolution/delete-profile-identifier-api.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index 2a2f5a8d80..b040053bee 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -76,7 +76,7 @@ POST https://{HOST_NAME}/v1/spaces/{SPACE_ID}/collections/users/profiles/user_id | Parameter | Description | | ----------------- | ---------------------------------------------------------------------------------------------------- | | **HOST_NAME** | `profiles.segment.com` for North America workspaces or `profiles.euw1.segment.com` for EU workspaces | -| **SPACE_ID** | Your space ID. Find this in **Unify > Settings > API access** | +| **SPACE_ID** | Your space ID. Find this in **Unify > Unify settings > API access** | | **USER_ID_VALUE** | The `user_id` value that identifies the profile | | **AUTH_TOKEN** | Your access token. Generate this in **Unify > Settings > API access** | @@ -152,6 +152,7 @@ Segment allows up to 100 deletion requests per second per space and 100 deletion Most deletion requests complete in under 3 seconds. Deletions on profiles with more than 15 merges or 50 identifier mappings may take longer. Deletion propagates to connected systems at different speeds: + - **Real-Time Profile Storage**: seconds to 5 minutes - **Profile Sync**: depends on your sync schedule From a06a3f60c1bdb8ae813c28f86c35b42a8f4b7481 Mon Sep 17 00:00:00 2001 From: Carolina Lopez Date: Thu, 6 Nov 2025 22:32:55 -0500 Subject: [PATCH 18/55] Fix some links --- .../destinations/catalog/actions-braze-cloud/index.md | 4 ++-- src/connections/destinations/catalog/wishpond/index.md | 2 +- .../mobile/react-native/destination-plugins/index.md | 4 ++-- .../sources/catalog/libraries/server/net/quickstart.md | 2 +- .../sources/catalog/libraries/server/node/migration.md | 2 +- src/guides/how-to-guides/forecast-with-sql.md | 2 +- src/guides/what-is-replay.md | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/connections/destinations/catalog/actions-braze-cloud/index.md b/src/connections/destinations/catalog/actions-braze-cloud/index.md index ca025d7370..5c731999a2 100644 --- a/src/connections/destinations/catalog/actions-braze-cloud/index.md +++ b/src/connections/destinations/catalog/actions-braze-cloud/index.md @@ -16,7 +16,7 @@ versions: [Braze](https://www.braze.com/){:target="_blank"}, formerly Appboy, is an engagement platform that empowers growth by helping marketing teams to build customer loyalty through mobile, omni-channel customer experiences. > success "" -> **Good to know**: This page is about the [Actions-framework](/docs/connections/destinations/actions/) Braze Segment destination. There's also a page about the [non-Actions Braze destination](/docs/connections/destinations/catalog/braze/). Both of these destinations receives data _from_ Segment. There's also the [Braze source](/docs/connections/sources/catalog/cloud-apps/braze//), which sends data _to_ Segment! +> **Good to know**: This page is about the [Actions-framework](/docs/connections/destinations/actions/) Braze Segment destination. There's also a page about the [non-Actions Braze destination](/docs/connections/destinations/catalog/braze/). Both of these destinations receives data _from_ Segment. There's also the [Braze source](/docs/connections/sources/catalog/cloud-apps/braze/), which sends data _to_ Segment! ## Benefits of Braze Cloud-Mode (Actions) vs Braze (Classic) @@ -77,4 +77,4 @@ Braze requires one of either `external_id`, `user_alias`, or `braze_id` to be pr #### Missing events When an event is sent under an alias, it might appear to be missing if the alias cannot be found in Braze. This might be due to an incorrect search for the alias in Braze. -To search for an alias in Braze, use the format `Alias Label:Alias Name`. For example, if the "Alias Label" field is set as email and "Alias Name" field is set as email address, for example: "test@email.com", you should search for the alias using "email:test@email.com". \ No newline at end of file +To search for an alias in Braze, use the format `Alias Label:Alias Name`. For example, if the "Alias Label" field is set as email and "Alias Name" field is set as email address, for example: "test@email.com", you should search for the alias using "email:test@email.com". diff --git a/src/connections/destinations/catalog/wishpond/index.md b/src/connections/destinations/catalog/wishpond/index.md index 8ec5082834..427ac22492 100644 --- a/src/connections/destinations/catalog/wishpond/index.md +++ b/src/connections/destinations/catalog/wishpond/index.md @@ -75,6 +75,6 @@ To more details how Wishpond's identify works visit [Wishpond API Docs: #track] Make sure you have copied the right keys from Wishpond's ["API Keys" dialog](https://www.wishpond.com/central/welcome?api_keys=true){:target="_blank"}, this destination will need `Merchant ID` and `Tracking Key`. -[Analytics.js]: https://segment.com//docs/connections/sources/catalog/libraries/website/javascript/ +[Analytics.js]: https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/ [ci-link]: https://circleci.com/gh/segment-integrations/analytics.js-integration-wishpond [ci-badge]: https://circleci.com/gh/segment-integrations/analytics.js-integration-wishpond.svg?style=svg diff --git a/src/connections/sources/catalog/libraries/mobile/react-native/destination-plugins/index.md b/src/connections/sources/catalog/libraries/mobile/react-native/destination-plugins/index.md index ec31175aeb..ca542e31cc 100644 --- a/src/connections/sources/catalog/libraries/mobile/react-native/destination-plugins/index.md +++ b/src/connections/sources/catalog/libraries/mobile/react-native/destination-plugins/index.md @@ -51,13 +51,13 @@ plugins: mark: url: https://cdn.filepicker.io/api/file/k1fi9InSu6eint2IHilP - name: Firebase - url: connections/sources/catalog/libraries/mobile/react-native//destination-plugins/firebase-react-native/ + url: connections/sources/catalog/libraries/mobile/react-native/destination-plugins/firebase-react-native/ logo: url: https://cdn.filepicker.io/api/file/W6teayYkRmKgb8SMqxIn mark: url: https://cdn.filepicker.io/api/file/ztKtaLBUT7GUZKius5sa - name: FullStory - url: connections/sources/catalog/libraries/mobile/react-native//destination-plugins/fullstory-react-native/ + url: connections/sources/catalog/libraries/mobile/react-native/destination-plugins/fullstory-react-native/ logo: url: https://cdn.filepicker.io/api/file/0ET4vgkqTGNMRtZcFWCA mark: diff --git a/src/connections/sources/catalog/libraries/server/net/quickstart.md b/src/connections/sources/catalog/libraries/server/net/quickstart.md index 937f737bb9..23980d31ad 100644 --- a/src/connections/sources/catalog/libraries/server/net/quickstart.md +++ b/src/connections/sources/catalog/libraries/server/net/quickstart.md @@ -106,6 +106,6 @@ Congratulations! You can now track any event from the browser and the backend. H ## What's Next? -We just walked through the quickest way to get started with Segment using Analytics.js and the .NET library. You might also want to check out our full [Analytics.js reference](//docs/connections/sources/catalog/libraries/website/javascript/) to see what else is possible, or read about the [Tracking API methods](/docs/connections/spec/) to get a sense for the bigger picture. +We just walked through the quickest way to get started with Segment using Analytics.js and the .NET library. You might also want to check out our full [Analytics.js reference](/docs/connections/sources/catalog/libraries/website/javascript/) to see what else is possible, or read about the [Tracking API methods](/docs/connections/spec/) to get a sense for the bigger picture. If you're running an **Ecommerce** site or app you should also check out our [Ecommerce API reference](/docs/connections/spec/ecommerce/v2/) to make sure your products and checkout experience is instrumented properly! diff --git a/src/connections/sources/catalog/libraries/server/node/migration.md b/src/connections/sources/catalog/libraries/server/node/migration.md index b250ad9a93..3774eb04b4 100644 --- a/src/connections/sources/catalog/libraries/server/node/migration.md +++ b/src/connections/sources/catalog/libraries/server/node/migration.md @@ -60,7 +60,7 @@ If you're using the [classic version of Analytics Node.js](/docs/connections/sou #### Removals The updated Analytics Node.js removed these configuration options: -- `errorHandler` (see the docs on [error handling](/docs/connections/sources/catalog/libraries/server/node//#error-handling) for more information) +- `errorHandler` (see the docs on [error handling](/docs/connections/sources/catalog/libraries/server/node/#error-handling) for more information) The updated Analytics Node.js library removed undocumented behavior around `track` properties diff --git a/src/guides/how-to-guides/forecast-with-sql.md b/src/guides/how-to-guides/forecast-with-sql.md index 3d376f2708..227f198900 100644 --- a/src/guides/how-to-guides/forecast-with-sql.md +++ b/src/guides/how-to-guides/forecast-with-sql.md @@ -190,7 +190,7 @@ At Toastmates, most of the highest forward-looking expected LTV customers share With that in mind, you can define a behavioral cohort in our email tool, Customer.io, as well as create a trigger workflow so we can send an email offer to these customers. -[Learn how to use email tools to target this cohort of high value customers.](https://segment.com/docs/guides/how-to-guides/forecast-with-sql//) +[Learn how to use email tools to target this cohort of high value customers.](https://segment.com/docs/guides/how-to-guides/forecast-with-sql/) ## Reward your best customers diff --git a/src/guides/what-is-replay.md b/src/guides/what-is-replay.md index 7db26b3e31..75442342ee 100644 --- a/src/guides/what-is-replay.md +++ b/src/guides/what-is-replay.md @@ -68,7 +68,7 @@ There are two types of replays with Engage. #### Nuances to Consider for Engage Replays **1. Replay a Profile Source's data into Engage Space** -- When a new Profile Source is connected to an Engage Space, the default option to replay the source's data seen over the past 30 days can be selected. To request a source's additional historical data be replayed to the Engage Space, contact Segment Support at friends@segment.com or [create a ticket](https://segment.com/docs/engage/[url](https://app.segment.com/goto-my-workspace/home?period=last-24-hours&v2=enabled&help=create-ticket)). Please see [this documentation](https://segment.com/docs/engage/quickstart/#step-3-connect-production-sources:~:text=Step%203%3A%20Connect,production%20sources.) on further details of this process and what to include in your support request. +- When a new Profile Source is connected to an Engage Space, the default option to replay the source's data seen over the past 30 days can be selected. To request a source's additional historical data be replayed to the Engage Space, contact Segment Support at friends@segment.com or [create a ticket](https://app.segment.com/goto-my-workspace/home?period=last-24-hours&v2=enabled&help=create-ticket). Please see [this documentation](https://segment.com/docs/engage/quickstart/#step-3-connect-production-sources:~:text=Step%203%3A%20Connect,production%20sources.) on further details of this process and what to include in your support request. **2. Replay from an Engage Space to its connected destination** - Since each instance of a destination is connected to its own Engage "Output" source, that source contains events for all of the computations that destination is connected to received data from, _the list of output sources can be found under Unify > Unify Settings > Debugger_. Because of this, it's not possible to replay only a specific computation's data to the destination, you should instead consider reaching out to [Segment support](https://segment.com/help/contact/) to request a resync of that computation to its destination instead. However, if you would like to replay all failed events seen by that destination, which will encompass all connected computations, that can be achieved with a replay. From f4818968fa9217d22208f398691bd89223084141 Mon Sep 17 00:00:00 2001 From: pwseg Date: Thu, 6 Nov 2025 21:38:49 -0600 Subject: [PATCH 19/55] reword use cases --- .../delete-profile-identifier-api.md | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index b040053bee..c092a7e206 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -10,13 +10,13 @@ Use this API to clean up outdated or incorrectly added identifiers without delet ## Use cases -Remove identifiers that shouldn't be associated with a profile: +The Delete Profile Identifier API helps you clean up identifiers that shouldn't be associated with a profile, including: -- Remove mistakenly imported identifiers, like incorrect email addresses, to prevent inaccurate targeting in downstream tools. -- Clean up obsolete identifiers after database migrations or system changes. -- Transfer identifiers with a short lifespan between profiles. For example, when a user changes phone numbers or when a prepaid service expires, you can remove the phone number from one profile and add it to another. -- Fix profiles that violate [ID Resolution limits](). Remove old identifiers to bring profiles into compliance with your configured limits. -- Revert misconfigured identity resolution settings. For example, if you reduced the `user_id` limit from 3 to 1, remove extra `user_id` values to resolve discrepancies between Segment and downstream tools like Braze or Amplitude. +- Mistakenly imported identifiers, like incorrect email addresses, that prevent accurate targeting in downstream tools +- Obsolete identifiers left over from database migrations or system changes +- Identifiers with a short lifespan that need to transfer between profiles. For example, when a user changes phone numbers or when a prepaid service expires, you can remove the phone number from one profile and add it to another. +- Old identifiers that cause profiles to violate [ID Resolution limits]() +- Extra identifiers from misconfigured identity resolution settings. For example, if you reduced the `user_id` limit from 3 to 1, remove extra `user_id` values to resolve discrepancies between Segment and downstream tools like Braze or Amplitude. ## Before you begin @@ -67,10 +67,16 @@ The API returns an error if you try to delete: The API accepts one identifier per request. **Endpoint**: -``` +```sh POST https://{HOST_NAME}/v1/spaces/{SPACE_ID}/collections/users/profiles/user_id:{USER_ID_VALUE}/external_ids/delete ``` +```sh +https://{HOST_NAME}/v1/spaces/{SPACE_ID}/collections/users/profiles/user_id:{USER_ID_VALUE}/external_ids/delete +``` + +`POST https://{HOST_NAME}/v1/spaces/{SPACE_ID}/collections/users/profiles/user_id:{USER_ID_VALUE}/external_ids/delete` + **Parameters**: | Parameter | Description | From c79fb27db992e337bee0ed71d58cbd612182d82d Mon Sep 17 00:00:00 2001 From: pwseg Date: Thu, 6 Nov 2025 21:41:58 -0600 Subject: [PATCH 20/55] reword before you begin section --- .../delete-profile-identifier-api.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index c092a7e206..f74d8b850d 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -20,26 +20,22 @@ The Delete Profile Identifier API helps you clean up identifiers that shouldn't ## Before you begin -During private beta, the Delete Profile Identifier API is available to Unify and Engage. +The Delete Profile Identifier API is available to Unify and Engage customers during private beta. -You must have one of the following role permissions to delete identifiers: +You need one of these roles to delete identifiers: - Workspace Owner - Identity Admin - Unify and Engage Admin -For more information, see [the Roles documentation](/docs/segment-app/iam/roles/). +See [the Roles documentation](/docs/segment-app/iam/roles/) for more details. -### Profiles Sync configuration - -If you use [Profiles Sync](/docs/unify/profiles-sync/overview/), complete these steps before using the Delete Profile Identifier API: +If you use [Profiles Sync](/docs/unify/profiles-sync/overview/), you must also: 1. Add the `__operation` column to the `external_id_mapping_updates` table schema in your data warehouse: - Default value: `CREATED` - Deleted value: `REMOVED` -2. Verify that your analytics workloads (BI tools, data pipelines, ML models) can handle deleted identifiers. Make sure these systems remain operational and account for the `REMOVED` flag. - - +2. Verify that your analytics workloads (BI tools, data pipelines, ML models) can handle deleted identifiers. Make sure these systems stay operational and account for the `REMOVED` flag. ## How deletion works From a6957324dc31eb9d3e87f81ab63f0beecaa5331a Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 00:02:26 -0600 Subject: [PATCH 21/55] explain request better --- .../delete-profile-identifier-api.md | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index f74d8b850d..d9867cc15f 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -39,17 +39,18 @@ If you use [Profiles Sync](/docs/unify/profiles-sync/overview/), you must also: ## How deletion works -When you delete an identifier, Segment removes it from [Identity Resolution](/docs/unify/identity-resolution/) and propagates the change through connected systems. +When you delete an identifier, Segment removes it from [Identity Resolution](/docs/unify/identity-resolution/) and syncs the change to connected systems. -After you send the request, the Delete Profile Identifier API confirms that Segment deleted the identifier from the Real-Time Identity Graph. Deletion then propagates to other systems: +The API confirms that Segment deleted the identifier from the Real-Time Identity Graph. The deletion then flows through these systems: -1. Real-time Profile storage**: The Profile API and Profile explorer delete the identifier in near real time. -2. Batch Profile Data lakehouse: Segment soft-deletes the identifier (flags it as deleted) in the append-only table within minutes. The identifier filters out from the materialized view within 24 hours. -3. Customer data warehouse: Profile Sync sends a deletion notification to your warehouse. The `external_id_mapping_updates` table shows the identifier with `__operation` set to `REMOVED`. The `user_identifiers` materialized view filters out removed identifiers. +| System | What happens | +| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Real-time Profile storage | The Profile API and Profile explorer delete the identifier in near real time | +| Batch Profile Data lakehouse | Segment soft-deletes the identifier in the append-only table within minutes and filters it from the materialized view within 24 hours | +| Customer data warehouse | Profiles Sync adds a row to `external_id_mapping_updates` with `__operation` set to `REMOVED`. The `user_identifiers` view filters out removed identifiers | - -## Delete an identifier +## Send a deletion request You can only delete identifiers from known profiles. The API requires a valid `user_id` to locate the profile. @@ -62,35 +63,28 @@ The API returns an error if you try to delete: The API accepts one identifier per request. -**Endpoint**: -```sh -POST https://{HOST_NAME}/v1/spaces/{SPACE_ID}/collections/users/profiles/user_id:{USER_ID_VALUE}/external_ids/delete -``` +Send requests to this endpoint: -```sh -https://{HOST_NAME}/v1/spaces/{SPACE_ID}/collections/users/profiles/user_id:{USER_ID_VALUE}/external_ids/delete +``` +POST https://{HOST_NAME}/v1/spaces/{SPACE_ID}/collections/users/profiles/user_id:{USER_ID_VALUE}/external_ids/delete ``` -`POST https://{HOST_NAME}/v1/spaces/{SPACE_ID}/collections/users/profiles/user_id:{USER_ID_VALUE}/external_ids/delete` - -**Parameters**: - -| Parameter | Description | -| ----------------- | ---------------------------------------------------------------------------------------------------- | -| **HOST_NAME** | `profiles.segment.com` for North America workspaces or `profiles.euw1.segment.com` for EU workspaces | -| **SPACE_ID** | Your space ID. Find this in **Unify > Unify settings > API access** | -| **USER_ID_VALUE** | The `user_id` value that identifies the profile | -| **AUTH_TOKEN** | Your access token. Generate this in **Unify > Settings > API access** | +Replace the following parameters in the URL: -**Request body**: +| Parameter | Description | +| --------------- | ---------------------------------------------------------------------------------------------------- | +| `HOST_NAME` | `profiles.segment.com` for North America workspaces or `profiles.euw1.segment.com` for EU workspaces | +| `SPACE_ID` | Your space ID. Find this in **Unify > Unify settings > API access**. | +| `USER_ID_VALUE` | The `user_id` value that identifies the profile. | +| `AUTH_TOKEN` | Your access token. Generate this in **Unify > Unify settings > API access**. | -| Field | Description | -| ----------------------- | ------------------------------------------------------------------------------ | -| **delete_external_ids** | Array containing the identifier to delete. Limit: 1 identifier per request | -| **id** | Value of the identifier to delete (for example, `hello@gmail.com`) | -| **type** | Type of identifier to delete (for example, `email`, `anonymous_id`, `user_id`) | +Include these fields in the request body: - +| Field | Description | +| --------------------- | ------------------------------------------------------------------------------ | +| `delete_external_ids` | Array containing the identifier to delete. Limit: 1 identifier per request | +| `id` | Value of the identifier to delete (for example, `hello@gmail.com`) | +| `type` | Type of identifier to delete (for example, `email`, `anonymous_id`, `user_id`) | ### Example request From 43d6e37fed7966bcea771a9039b64147b2b76732 Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 11:48:45 +0000 Subject: [PATCH 22/55] edits [netlify-build] --- .../auto-instrumentation/kotlin-setup.md | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/src/connections/auto-instrumentation/kotlin-setup.md b/src/connections/auto-instrumentation/kotlin-setup.md index 95025d4cd1..ad8672c1ba 100644 --- a/src/connections/auto-instrumentation/kotlin-setup.md +++ b/src/connections/auto-instrumentation/kotlin-setup.md @@ -26,7 +26,7 @@ Segment recommends testing in a development environment before deploying Signals ## Prerequisites -Auto-Instrumentation (aka Signals) works on top of Analytics and Live Plugins. Make sure to add the following dependencies to your module's Gradle file if you don't have them already. +Auto-Instrumentation (also known as Signals) works on top of Analytics and Live Plugins. Make sure to add the following dependencies to your module's Gradle file if you don't have them already. ```groovy // analytics kotlin @@ -37,7 +37,7 @@ implementation("com.segment.analytics.kotlin:analytics-kotlin-live:1.3.0") ## Step 1: Getting started -Instrumentation becomes as simple as adding dependencies to your module's Gradle file: +To get started: 1. Add Signals Core ```groovy // signal core @@ -62,13 +62,13 @@ Instrumentation becomes as simple as adding dependencies to your module's Gradle ) ``` 3. Add proper dependency and plugin as needed to: - * [Capture Interactions](#capture-interactions) - * [Capture Navigation](#capture-navigation) - * [Capture Network](#capture-network) + * [Capture interactions](#capture-interactions). + * [Capture navigation](#capture-navigation). + * [Capture network](#capture-network). ## Step 2: Additional setup -### Capture Interactions +### Capture interactions #### Kotlin Compose @@ -84,7 +84,7 @@ Instrumentation becomes as simple as adding dependencies to your module's Gradle #### Legacy XML UI -1. Add uitoolkit Gradle Plugin dependency to project level `build.gradle` +1. Add the uitoolkit Gradle Plugin dependency to project-level `build.gradle`: ```groovy buildscript { dependencies { @@ -92,7 +92,7 @@ Instrumentation becomes as simple as adding dependencies to your module's Gradle } } ``` -2. Apply the plugin in your app level `build.gradle` and add the dependency +2. Apply the plugin in your app-level `build.gradle` and add the dependency: ```groovy plugins { // ...other plugins @@ -106,9 +106,9 @@ Instrumentation becomes as simple as adding dependencies to your module's Gradle ``` -### Capture Navigation +### Capture navigation -1. Add navigation Gradle Plugin dependency to project level `build.gradle` +1. Add the navigation Gradle Plugin dependency to project-level `build.gradle`: ```groovy buildscript { dependencies { @@ -116,7 +116,7 @@ Instrumentation becomes as simple as adding dependencies to your module's Gradle } } ``` -2. Apply the plugin in your app level `build.gradle` and add the dependency +2. Apply the plugin in your app-level `build.gradle` and add the dependency: ```groovy plugins { // ...other plugins @@ -128,21 +128,21 @@ Instrumentation becomes as simple as adding dependencies to your module's Gradle implementation ("com.segment.analytics.kotlin.signals:navigation:1.0.0") } ``` -3. (Optional) Add `SignalsActivityTrackingPlugin` to analytics to track Activity/Fragment navigation. **Not required for Compose Navigation** +3. (Optional) Add `SignalsActivityTrackingPlugin` to analytics to track Activity/Fragment navigation. **This is not required for Compose Navigation**. ```kotlin analytics.add(SignalsActivityTrackingPlugin()) ``` -### Capture Network +### Capture network #### OkHttp -1. add dependency: +1. Add the dependency: ```groovy implementation ("com.segment.analytics.kotlin.signals:okhttp3:1.0.0") ``` -2. add `SignalsOkHttp3TrackingPlugin` as an interceptor to your OkHttpClient: +2. Add `SignalsOkHttp3TrackingPlugin` as an interceptor to your OkHttpClient: ```kotlin private val okHttpClient = OkHttpClient.Builder() .addInterceptor(SignalsOkHttp3TrackingPlugin()) @@ -151,12 +151,12 @@ Instrumentation becomes as simple as adding dependencies to your module's Gradle #### Retrofit -1. add dependency: +1. Add the dependency: ```groovy implementation ("com.segment.analytics.kotlin.signals:okhttp3:1.0.0") ``` -2. add `SignalsOkHttp3TrackingPlugin` as an interceptor to your Retrofit client: +2. Add `SignalsOkHttp3TrackingPlugin` as an interceptor to your Retrofit client: ```kotlin private val okHttpClient = OkHttpClient.Builder() .addInterceptor(SignalsOkHttp3TrackingPlugin()) @@ -168,12 +168,12 @@ Instrumentation becomes as simple as adding dependencies to your module's Gradle ``` #### java.net.HttpURLConnection - 1. add dependency: + 1. Add the dependency: ```groovy implementation ("com.segment.analytics.kotlin.signals:java-net:1.0.0") ``` - 2. install the `JavaNetTrackingPlugin` on where you initialize analytics: + 2. Install the `JavaNetTrackingPlugin` on where you initialize analytics: ```kotlin JavaNetTrackingPlugin.install() ``` @@ -183,7 +183,7 @@ Instrumentation becomes as simple as adding dependencies to your module's Gradle By default, Signals stores captured data on the device and doesn't forward it to Segment. This process prevents unnecessary bandwidth use and helps support privacy compliance requirements. -To view captured signals in the Event Builder and create event generation rules, you need to enable `sendDebugSignalsToSegment`. This setting temporarily lets the SDK send signal data to Segment while you're testing. +To view captured signals in the Event Builder and create event generation rules, enable `sendDebugSignalsToSegment`. This setting temporarily lets the SDK send signal data to Segment while you're testing. In addition, the SDK obfuscates signals sent to Segment by default. To view the completed data, you need to turn off `obfuscateDebugSignals`. @@ -241,7 +241,7 @@ Signals.configuration = Configuration( Next, return to the source settings to turn on Auto-Instrumentation: 1. Go to **Connections > Sources**. -2. Select the source you used in Step 1. +2. Select the source you used in [Step 1](#Step-1-Getting-started). 3. From the source's overview tab, go to **Settings > Advanced**. 4. Toggle Auto-Instrumention on. @@ -251,13 +251,11 @@ After you build and run your app, use the [Event Builder](/docs/connections/auto 1. In your Segment workspace, go to **Connections > Sources** and select the Android Source you configured. 2. Open the **Event Builder** tab. -3. Interact with your app on a simulator or test device: - - Navigate between screens. - - Tap buttons and UI elements. - - Trigger network requests. - -If `sendDebugSignalsToSegment` is enabled, Signals appear in real time as you interact with the app. - +3. Interact with your app on a simulator or test device: + > - Navigate between screens. + > - Tap buttons and UI elements. + > - Trigger network requests. + > If `sendDebugSignalsToSegment` is enabled, Signals appear in real time as you interact with the app. 4. In the Event Builder, select a signal and click **Configure event** to define a new event. 5. After you add any event mappings, click **Publish event rules** to save them. From a4d51b3ee1194e5eae401b7df83755c9d663009a Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 12:02:34 +0000 Subject: [PATCH 23/55] fixes + edits --- .../auto-instrumentation/swift-setup.md | 69 +++++++++---------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/connections/auto-instrumentation/swift-setup.md b/src/connections/auto-instrumentation/swift-setup.md index 785e002a06..8bc6f71684 100644 --- a/src/connections/auto-instrumentation/swift-setup.md +++ b/src/connections/auto-instrumentation/swift-setup.md @@ -25,7 +25,7 @@ Segment recommends testing in a development environment before deploying Signals ## Prerequisites -Auto-Instrumentation (aka Signals) works on top of Analytics. Make sure to add the following dependency to your project if you don't have analytics-swift already. +Auto-Instrumentation (also known as Signals) works on top of Analytics. Make sure to add the following dependency to your project if you don't have analytics-swift already. ```swift dependencies: [ @@ -42,11 +42,10 @@ dependencies: [ ] ``` -2. Import and initialize with your Analytics instance: - -> success "" -> See [configuration options](#configuration-options) for a complete list. -> +2. Import and initialize with your Analytics instance: + > success "" + > See [configuration options](#configuration-options) for a complete list. + > ```swift import Segment import AnalyticsLive @@ -75,14 +74,14 @@ dependencies: [ ``` 3. Set up capture for the UI framework(s) you're using: - * [Capture SwiftUI Interactions](#swiftui) - * [Capture UIKit Interactions](#uikit) - * [Capture Network Activity](#capture-network) + * [Capture SwiftUI interactions](#swiftui). + * [Capture UIKit interactions](#uikit). + * [Capture network activity](#capture-network). ## Step 2: Additional setup -### Capture Interactions +### Capture interactions #### SwiftUI @@ -119,25 +118,25 @@ SwiftUI automatic signal capture requires adding typealiases to your code. This typealias List = SignalList ``` -3. Use the controls normally in your SwiftUI code: +3. Use the controls in your SwiftUI code: ```swift struct ContentView: View { var body: some View { NavigationStack { VStack { Button("Click Me") { - // Button tap will automatically generate a signal + // Button tap automatically generates a signal } TextField("Enter text", text: $text) - // Text changes will automatically generate signals + // Text changes automatically generates signals } } } } ``` -> **Note:** The typealiases replace SwiftUI's native controls with signal-generating versions. Your code remains unchanged, but interactions are now automatically captured. +The typealiases replace SwiftUI's native controls with signal-generating versions. Your code remains unchanged, but interactions are now automatically captured. #### UIKit @@ -152,7 +151,7 @@ UIKit automatic signal capture uses method swizzling and requires no code change )) ``` -2. That's it! The following UIKit interactions and navigation events are automatically captured via method swizzling: +2. The following UIKit interactions and navigation events are automatically captured via method swizzling: **Interactions:** - `UIButton` taps @@ -167,16 +166,16 @@ UIKit automatic signal capture uses method swizzling and requires no code change - `UIViewController` modal presentations and dismissals - `UITabBarController` tab switches -### Capture Navigation +### Capture navigation Navigation capture is handled automatically when you enable SwiftUI or UIKit auto-signals: -- **SwiftUI**: Captured through `SignalNavigationLink` and `SignalNavigationStack` when you add the typealiases -- **UIKit**: Captured automatically via `UINavigationController`, `UIViewController`, and `UITabBarController` swizzling +- **SwiftUI**: Captured through `SignalNavigationLink` and `SignalNavigationStack` when you add the typealiases. +- **UIKit**: Captured automatically via `UINavigationController`, `UIViewController`, and `UITabBarController` swizzling. -No additional setup required beyond enabling the appropriate auto-signal flags. +No additional setup is required beyond enabling the appropriate auto-signal flags. -### Capture Network +### Capture network Network capture automatically tracks URLSession requests and responses. @@ -192,13 +191,13 @@ Network capture automatically tracks URLSession requests and responses. ``` 2. Network requests made via URLSession are automatically captured, including: - - Request URL, method, headers, and body - - Response status, headers, and body - - Request/response correlation via request ID + - Request URL, method, headers, and body. + - Response status, headers, and body. + - Request or response correlation via request ID. -> **Note:** Third-party networking libraries that use URLSession underneath (like Alamofire) should work automatically. Segment API endpoints are automatically blocked to prevent recursive tracking. +Third-party networking libraries that use URLSession underneath (like Alamofire) should work automatically. Segment API endpoints are automatically blocked to prevent recursive tracking. -#### Configuring Network Hosts +#### Configuring network hosts You can control which network requests are tracked: @@ -226,7 +225,7 @@ The following hosts are automatically blocked to prevent recursive tracking: By default, Signals stores captured data on the device and doesn't forward it to Segment. This process prevents unnecessary bandwidth use and helps support privacy compliance requirements. -To view captured signals in the Event Builder and create event generation rules, you need to enable `sendDebugSignalsToSegment`. This setting temporarily lets the SDK send signal data to Segment while you're testing. +To view captured signals in the Event Builder and create event generation rules, enable `sendDebugSignalsToSegment`. This setting temporarily lets the SDK send signal data to Segment while you're testing. In addition, the SDK obfuscates signals sent to Segment by default. To view the completed data, you need to turn off `obfuscateDebugSignals`. @@ -235,9 +234,9 @@ In addition, the SDK obfuscates signals sent to Segment by default. To view the You can enable `sendDebugSignalsToSegment` and turn off `obfuscateDebugSignals` in one of three ways. -### Option 1: Use Build Configurations to Toggle Debug Mode +### Option 1: Use build configurations to toggle debug mode - 1. Define different configurations in your project settings (Debug, Release, etc.) + 1. Define different configurations in your project settings (for example, Debug or Release). 2. Use compiler flags to control the setting: ```swift @@ -254,7 +253,7 @@ You can enable `sendDebugSignalsToSegment` and turn off `obfuscateDebugSignals` )) ``` -### Option 2: Use a Feature Flag System +### Option 2: Use a Feature Flag system If you're using Firebase Remote Config or a similar feature flag system, you can dynamically control `sendDebugSignalsToSegment` and `obfuscateDebugSignals` without requiring a new app build: ```swift let remoteConfig = RemoteConfig.remoteConfig() @@ -267,7 +266,7 @@ You can enable `sendDebugSignalsToSegment` and turn off `obfuscateDebugSignals` )) ``` -### Option 3: Use Environment Variables (for debugging/testing) +### Option 3: Use environment variables (for debugging or testing) You can check for environment variables or launch arguments during development: ```swift let isDebugEnabled = ProcessInfo.processInfo.environment["SIGNALS_DEBUG"] != nil @@ -285,7 +284,7 @@ You can enable `sendDebugSignalsToSegment` and turn off `obfuscateDebugSignals` Next, return to the source settings to turn on Auto-Instrumentation: 1. Go to **Connections > Sources**. -2. Select the source you used in Step 1. +2. Select the source you used in [Step 1](#Step-1-Getting-started). 3. From the source's overview tab, go to **Settings > Advanced**. 4. Toggle Auto-Instrumention on. @@ -303,7 +302,7 @@ After integrating the SDK and running your app, verify that Segment is collectin ## Configuration options -Using the Signals Configuration object, you can control the destination, frequency, and types of signals that Segment automatically tracks within your application. The following table details the configuration options for Signals-Swift. +Using the Signals Configuration object, you can control the destination, frequency, and types of signals that Segment automatically tracks within your application. The following table details the configuration options for Signals-Swift: | OPTION | REQUIRED | VALUE | DESCRIPTION | @@ -312,15 +311,15 @@ Using the Signals Configuration object, you can control the destination, frequen | **maximumBufferSize** | No | Int | The number of signals to be kept for JavaScript inspection. This buffer is first-in, first-out. Default is **1000**. | | **relayCount** | No | Int | Relays every X signals to Segment. Default is **20**. | | **relayInterval** | No | TimeInterval | Relays signals to Segment every X seconds. Default is **60**. | -| **broadcasters** | No | [SignalBroadcaster] | An array of broadcasters. These objects forward signal data to their destinations, like **WebhookBroadcaster**, or you could write your own **DebugBroadcaster** that writes logs to the developer console. **SegmentBroadcaster** is always added by the SDK when `sendDebugSignalsToSegment` is true. | +| **broadcasters** | No | SignalBroadcaster | An array of broadcasters. These objects forward signal data to their destinations, like **WebhookBroadcaster**, or you could write your own **DebugBroadcaster** that writes logs to the developer console. **SegmentBroadcaster** is always added by the SDK when `sendDebugSignalsToSegment` is true. | | **sendDebugSignalsToSegment** | No | Bool | Turns on debug mode and allows the SDK to relay Signals to Segment server. Default is **false**. It should only be set to true for development purposes. | | **obfuscateDebugSignals** | No | Bool | Obfuscates signals being relayed to Segment. Default is **true**. | | **apiHost** | No | String | API host for signal relay. Default is **"signals.segment.io/v1"**. | | **useUIKitAutoSignal** | No | Bool | Enables automatic UIKit signal capture via method swizzling. Default is **false**. | | **useSwiftUIAutoSignal** | No | Bool | Enables automatic SwiftUI signal capture (requires typealiases). Default is **false**. | | **useNetworkAutoSignal** | No | Bool | Enables automatic network signal capture for URLSession. Default is **false**. | -| **allowedNetworkHosts** | No | [String] | Array of host patterns to track. Use `["*"]` for all hosts. Default is **["*"]**. | -| **blockedNetworkHosts** | No | [String] | Array of host patterns to exclude from tracking. Default is **[]**. | +| **allowedNetworkHosts** | No | String | Array of host patterns to track. Use `["*"]` for all hosts. Default is **["*"]**. | +| **blockedNetworkHosts** | No | String | Array of host patterns to exclude from tracking. Default is **[]**. | ## Next steps From ac84b7e56cce80b677b23036b776c752563551c7 Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 12:05:33 +0000 Subject: [PATCH 24/55] fixes [netlify-build] --- .../auto-instrumentation/kotlin-setup.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/connections/auto-instrumentation/kotlin-setup.md b/src/connections/auto-instrumentation/kotlin-setup.md index ad8672c1ba..1625c32c9a 100644 --- a/src/connections/auto-instrumentation/kotlin-setup.md +++ b/src/connections/auto-instrumentation/kotlin-setup.md @@ -38,12 +38,12 @@ implementation("com.segment.analytics.kotlin:analytics-kotlin-live:1.3.0") ## Step 1: Getting started To get started: -1. Add Signals Core +1. Add Signals Core: ```groovy // signal core implementation ("com.segment.analytics.kotlin.signals:core:1.0.0") ``` -2. Initialize Signals +2. Initialize Signals: > success "" > See [configuration options](#configuration-options) for a complete list. @@ -72,12 +72,12 @@ To get started: #### Kotlin Compose -1. Add the dependency to your module’s Gradle build file. +1. Add the dependency to your module’s Gradle build file: ```groovy implementation ("com.segment.analytics.kotlin.signals:compose:1.0.0") ``` -2. Add `SignalsComposeTrackingPlugin` to analytics +2. Add `SignalsComposeTrackingPlugin` to analytics: ```kotlin analytics.add(SignalsComposeTrackingPlugin()) ``` @@ -128,7 +128,7 @@ To get started: implementation ("com.segment.analytics.kotlin.signals:navigation:1.0.0") } ``` -3. (Optional) Add `SignalsActivityTrackingPlugin` to analytics to track Activity/Fragment navigation. **This is not required for Compose Navigation**. +3. (**Optional**): Add `SignalsActivityTrackingPlugin` to analytics to track Activity/Fragment navigation. **This is not required for Compose Navigation**. ```kotlin analytics.add(SignalsActivityTrackingPlugin()) ``` @@ -254,8 +254,9 @@ After you build and run your app, use the [Event Builder](/docs/connections/auto 3. Interact with your app on a simulator or test device: > - Navigate between screens. > - Tap buttons and UI elements. - > - Trigger network requests. - > If `sendDebugSignalsToSegment` is enabled, Signals appear in real time as you interact with the app. + > - Trigger network requests. + > + > If `sendDebugSignalsToSegment` is enabled, Signals appear in real time as you interact with the app. 4. In the Event Builder, select a signal and click **Configure event** to define a new event. 5. After you add any event mappings, click **Publish event rules** to save them. From 66a18242243f2caabf8ca3d189bbdd1c4c5ad58a Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 12:24:59 +0000 Subject: [PATCH 25/55] fixing numbering [netlify-build] --- src/connections/auto-instrumentation/swift-setup.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/connections/auto-instrumentation/swift-setup.md b/src/connections/auto-instrumentation/swift-setup.md index 8bc6f71684..1e99cc39e8 100644 --- a/src/connections/auto-instrumentation/swift-setup.md +++ b/src/connections/auto-instrumentation/swift-setup.md @@ -43,9 +43,8 @@ dependencies: [ ``` 2. Import and initialize with your Analytics instance: - > success "" - > See [configuration options](#configuration-options) for a complete list. - > +> success "" +> See [configuration options](#configuration-options) for a complete list. ```swift import Segment import AnalyticsLive @@ -72,7 +71,6 @@ dependencies: [ // ... other options )) ``` - 3. Set up capture for the UI framework(s) you're using: * [Capture SwiftUI interactions](#swiftui). * [Capture UIKit interactions](#uikit). From 30816686c12597e1d79117fec72df2893bbcba77 Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 12:31:12 +0000 Subject: [PATCH 26/55] trying again --- src/connections/auto-instrumentation/kotlin-setup.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/connections/auto-instrumentation/kotlin-setup.md b/src/connections/auto-instrumentation/kotlin-setup.md index 1625c32c9a..92b70c53ef 100644 --- a/src/connections/auto-instrumentation/kotlin-setup.md +++ b/src/connections/auto-instrumentation/kotlin-setup.md @@ -43,12 +43,11 @@ To get started: // signal core implementation ("com.segment.analytics.kotlin.signals:core:1.0.0") ``` -2. Initialize Signals: - +2. Initialize Signals: > success "" > See [configuration options](#configuration-options) for a complete list. -> - ```kotlin + +```kotlin //... .... analytics.add(LivePlugins()) // Make sure LivePlugins is added analytics.add(Signals) // Add the signals plugin @@ -60,7 +59,8 @@ To get started: obfuscateDebugSignals = true // .. other options ) - ``` +``` + 3. Add proper dependency and plugin as needed to: * [Capture interactions](#capture-interactions). * [Capture navigation](#capture-navigation). From 4bdeb7eb2a14b6860f262749fe7402d75d32b791 Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 12:31:32 +0000 Subject: [PATCH 27/55] please work [netlify-build] --- src/connections/auto-instrumentation/swift-setup.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/connections/auto-instrumentation/swift-setup.md b/src/connections/auto-instrumentation/swift-setup.md index 1e99cc39e8..a98a5841d5 100644 --- a/src/connections/auto-instrumentation/swift-setup.md +++ b/src/connections/auto-instrumentation/swift-setup.md @@ -45,7 +45,7 @@ dependencies: [ 2. Import and initialize with your Analytics instance: > success "" > See [configuration options](#configuration-options) for a complete list. - ```swift +```swift import Segment import AnalyticsLive @@ -70,7 +70,8 @@ dependencies: [ #endif // ... other options )) - ``` +``` + 3. Set up capture for the UI framework(s) you're using: * [Capture SwiftUI interactions](#swiftui). * [Capture UIKit interactions](#uikit). From 5661ef6725fe1e8021b08ff42d4e0cfa0085c04c Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 12:43:01 +0000 Subject: [PATCH 28/55] pleaseee Updated the initialization instructions for Signals and improved clarity in the documentation. --- src/connections/auto-instrumentation/kotlin-setup.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/connections/auto-instrumentation/kotlin-setup.md b/src/connections/auto-instrumentation/kotlin-setup.md index 92b70c53ef..9f36b8e51d 100644 --- a/src/connections/auto-instrumentation/kotlin-setup.md +++ b/src/connections/auto-instrumentation/kotlin-setup.md @@ -43,11 +43,8 @@ To get started: // signal core implementation ("com.segment.analytics.kotlin.signals:core:1.0.0") ``` -2. Initialize Signals: -> success "" -> See [configuration options](#configuration-options) for a complete list. - -```kotlin +2. Initialize Signals. For a complete list, see [configuration options](#configuration-options). + ```kotlin //... .... analytics.add(LivePlugins()) // Make sure LivePlugins is added analytics.add(Signals) // Add the signals plugin @@ -59,8 +56,7 @@ To get started: obfuscateDebugSignals = true // .. other options ) -``` - + ``` 3. Add proper dependency and plugin as needed to: * [Capture interactions](#capture-interactions). * [Capture navigation](#capture-navigation). From b81f9fdd79933f52bd147eaf1f92274a54867105 Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 12:43:59 +0000 Subject: [PATCH 29/55] praying this works [netlify-build] Reword instructions for importing and initializing Analytics instance for clarity. --- src/connections/auto-instrumentation/swift-setup.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/connections/auto-instrumentation/swift-setup.md b/src/connections/auto-instrumentation/swift-setup.md index a98a5841d5..723a857147 100644 --- a/src/connections/auto-instrumentation/swift-setup.md +++ b/src/connections/auto-instrumentation/swift-setup.md @@ -42,10 +42,8 @@ dependencies: [ ] ``` -2. Import and initialize with your Analytics instance: -> success "" -> See [configuration options](#configuration-options) for a complete list. -```swift +2. Import and initialize with your Analytics instance. For a complete list, see [configuration options](#configuration-options). + ```swift import Segment import AnalyticsLive @@ -70,8 +68,7 @@ dependencies: [ #endif // ... other options )) -``` - + ``` 3. Set up capture for the UI framework(s) you're using: * [Capture SwiftUI interactions](#swiftui). * [Capture UIKit interactions](#uikit). From 7c6f97181c36f9d6f103031d5c647e9ca27fcd00 Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 13:14:47 +0000 Subject: [PATCH 30/55] last fixes --- src/connections/auto-instrumentation/swift-setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/connections/auto-instrumentation/swift-setup.md b/src/connections/auto-instrumentation/swift-setup.md index 723a857147..5dc9db5af9 100644 --- a/src/connections/auto-instrumentation/swift-setup.md +++ b/src/connections/auto-instrumentation/swift-setup.md @@ -33,7 +33,7 @@ dependencies: [ ] ``` -## Step 1: Getting started +## Step 1: ing started 1. Add AnalyticsLive to your Swift Package dependencies: ```swift @@ -280,7 +280,7 @@ You can enable `sendDebugSignalsToSegment` and turn off `obfuscateDebugSignals` Next, return to the source settings to turn on Auto-Instrumentation: 1. Go to **Connections > Sources**. -2. Select the source you used in [Step 1](#Step-1-Getting-started). +2. Select the source you used in [Step 1](#step-1-getting-started). 3. From the source's overview tab, go to **Settings > Advanced**. 4. Toggle Auto-Instrumention on. From 33c50a6385bf7ffc6447ad6fe2032c000c6f378b Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 13:15:20 +0000 Subject: [PATCH 31/55] all done [netlify-build] --- src/connections/auto-instrumentation/kotlin-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connections/auto-instrumentation/kotlin-setup.md b/src/connections/auto-instrumentation/kotlin-setup.md index 9f36b8e51d..3c8ca07d9f 100644 --- a/src/connections/auto-instrumentation/kotlin-setup.md +++ b/src/connections/auto-instrumentation/kotlin-setup.md @@ -237,7 +237,7 @@ Signals.configuration = Configuration( Next, return to the source settings to turn on Auto-Instrumentation: 1. Go to **Connections > Sources**. -2. Select the source you used in [Step 1](#Step-1-Getting-started). +2. Select the source you used in [Step 1](#step-1-getting-started). 3. From the source's overview tab, go to **Settings > Advanced**. 4. Toggle Auto-Instrumention on. From 48efb817ca8ff49d67e0388da0442ee6d6086355 Mon Sep 17 00:00:00 2001 From: Sharon Adewusi Date: Fri, 7 Nov 2025 13:32:49 +0000 Subject: [PATCH 32/55] done done done --- src/connections/auto-instrumentation/swift-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connections/auto-instrumentation/swift-setup.md b/src/connections/auto-instrumentation/swift-setup.md index 5dc9db5af9..953efab2f6 100644 --- a/src/connections/auto-instrumentation/swift-setup.md +++ b/src/connections/auto-instrumentation/swift-setup.md @@ -33,7 +33,7 @@ dependencies: [ ] ``` -## Step 1: ing started +## Step 1: Getting started 1. Add AnalyticsLive to your Swift Package dependencies: ```swift From 4679e052057b9ca7144aa442167e8cf86523efc9 Mon Sep 17 00:00:00 2001 From: Carolina Lopez Date: Fri, 7 Nov 2025 09:05:55 -0500 Subject: [PATCH 33/55] Fix link --- .../destinations/catalog/criteo-app-web-events/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connections/destinations/catalog/criteo-app-web-events/index.md b/src/connections/destinations/catalog/criteo-app-web-events/index.md index 99da7bddaa..17c13a7c82 100644 --- a/src/connections/destinations/catalog/criteo-app-web-events/index.md +++ b/src/connections/destinations/catalog/criteo-app-web-events/index.md @@ -395,4 +395,4 @@ Criteo Events can receive dates in a specific format, in order for us to pass al ### Is the mobile integration bundled? -Even though we don't support integrating with Criteo Events using Segment from a server source, it's still not necessary for you to [bundle](/docs/connections/spec/mobile-packaging-sdks//) the Criteo Events SDK into the Segment SDK! This is because while our mobile integration with them is powered from our servers, the integration requires metadata that can only be supplied by the user's mobile device (which is collected and passed along automatically by the Segment mobile SDK). +Even though we don't support integrating with Criteo Events using Segment from a server source, it's still not necessary for you to [bundle](/docs/connections/spec/mobile-packaging-sdks/) the Criteo Events SDK into the Segment SDK! This is because while our mobile integration with them is powered from our servers, the integration requires metadata that can only be supplied by the user's mobile device (which is collected and passed along automatically by the Segment mobile SDK). From bf273d925d99e941ffa4b3c6d5312794866ae819 Mon Sep 17 00:00:00 2001 From: forstisabella <92472883+forstisabella@users.noreply.github.com> Date: Fri, 7 Nov 2025 09:37:16 -0500 Subject: [PATCH 34/55] update w eng feedback --- src/connections/delivery-overview.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/connections/delivery-overview.md b/src/connections/delivery-overview.md index d9f31fda63..51a596c6d2 100644 --- a/src/connections/delivery-overview.md +++ b/src/connections/delivery-overview.md @@ -58,13 +58,14 @@ The following image shows a storage destination with 23 partially successful syn ##### Linked Audiences to Snowflake destination -You can send Linked Audiences downstream to the Snowflake destination with the following steps: +You can view information about events sent from Linked Audiences downstream to the Snowflake destination with the following pipeline view: + - **Events from audience***: Events that Segment created for your activation. The number of events for each compute depends on the changes detected in your audience membership. - **Filtered at source**: Events discarded by Protocols: either by the [schema settings](/docs/protocols/enforce/schema-configuration/) or [Tracking Plans](/docs/protocols/tracking-plan/create/). - **Filtered at destination**: Events that were discarded due to [Destination Filters](/docs/guides/filtering-data/#destination-filters), [filtering in the Integrations object](/docs/guides/filtering-data/#filtering-with-the-integrations-object), [Destination Insert functions](/docs/connections/functions/insert-functions/), or [per source schema integration filters](/docs/guides/filtering-data/#per-source-schema-integrations-filters). [Actions destinations](/docs/connections/destinations/actions/) also have a filtering capability: for example, if your Action is set to only send Identify events, all other event types will be filtered out. Actions destinations with incomplete triggers or disabled mappings are filtered out at this step. [Consent Management](/docs/privacy/consent-management/) users also see events discarded due to consent preferences. - **Events to warehouse rows**: A read-only box that shows the point in the delivery process where Segment converts events into Snowflake warehouse rows. -- **Failed to sync**: Syncs that either failed to sync or were partially successful. Selecting this step takes you to a table of all syncs with one or more failed collections. Select a sync from the table to view the discard reason, any collections that failed, the status, and the number of rows that synced for each collection. For information about common errors, see [Warehouse Errors](docs/connections/storage/warehouses/warehouse-errors). -- **Successfully synced**: A record of all successful or partially successful syncs made with your destination. To view the reason a partially successfully sync was not fully successful, see the Failed to sync step. +- **Failed delivery**: Events that have been discarded due to errors or unmet destination requirements. Click into this step to view a table of all collections with one or more failed events. Select a collection from the table to view the discard reason, any events that failed, and the status. For information about common errors, see [Warehouse Errors](docs/connections/storage/warehouses/warehouse-errors). +- **Successful delivery**: Events that were successfully delivered to Snowflake. #### Destinations connected to Engage Destinations From 67f6d3067996d84c8e9e5a9c0f874e6894b9d783 Mon Sep 17 00:00:00 2001 From: forstisabella <92472883+forstisabella@users.noreply.github.com> Date: Fri, 7 Nov 2025 09:38:30 -0500 Subject: [PATCH 35/55] [netlify-build] --- src/connections/delivery-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connections/delivery-overview.md b/src/connections/delivery-overview.md index 51a596c6d2..bd65c6dacb 100644 --- a/src/connections/delivery-overview.md +++ b/src/connections/delivery-overview.md @@ -162,4 +162,4 @@ The Delivery Overview pipeline steps Failed on Ingest, Filtered at Source, Filte This table provides a list of all possible discard reasons available at each pipeline step. {% include content/delivery-overview-discards.html %} - + \ No newline at end of file From e9ac63f5515384d69bfcaed087589ed56d592892 Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 08:49:47 -0600 Subject: [PATCH 36/55] remove auth from parameters table --- .../delete-profile-identifier-api.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index d9867cc15f..63c70d5a0e 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -59,7 +59,17 @@ The API returns an error if you try to delete: - All `user_id` values from a profile. Profiles must have at least one `user_id`. - A `group_id` identifier. The API only supports individual profiles. -### API request format +### Authentication + +The API uses HTTP Basic Authentication. Base64-encode your access token with a trailing colon (the colon represents an empty password): + +```bash +echo -n 'your_token:' | base64 +``` + +Use the encoded value in the `Authorization` header of your requests. Generate your access token in **Unify > Unify settings > API access**. + +### Request format The API accepts one identifier per request. @@ -75,20 +85,19 @@ Replace the following parameters in the URL: | --------------- | ---------------------------------------------------------------------------------------------------- | | `HOST_NAME` | `profiles.segment.com` for North America workspaces or `profiles.euw1.segment.com` for EU workspaces | | `SPACE_ID` | Your space ID. Find this in **Unify > Unify settings > API access**. | -| `USER_ID_VALUE` | The `user_id` value that identifies the profile. | -| `AUTH_TOKEN` | Your access token. Generate this in **Unify > Unify settings > API access**. | +| `USER_ID_VALUE` | The `user_id` value that identifies the profile. | Include these fields in the request body: | Field | Description | | --------------------- | ------------------------------------------------------------------------------ | | `delete_external_ids` | Array containing the identifier to delete. Limit: 1 identifier per request | -| `id` | Value of the identifier to delete (for example, `hello@gmail.com`) | +| `id` | Value of the identifier to delete (for example, `hello@example.com`) | | `type` | Type of identifier to delete (for example, `email`, `anonymous_id`, `user_id`) | ### Example request -First, base64-encode your access token with a trailing colon: +The API uses HTTP Basic Authentication. Base64-encode your access token with a trailing colon (the colon represents an empty password): ```bash echo -n 'your_token:' | base64 From 792c936465b903e28d3aed54398950c4fd3261b2 Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 08:52:34 -0600 Subject: [PATCH 37/55] clean up status codes table --- .../delete-profile-identifier-api.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index 63c70d5a0e..ebe0862c41 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -75,7 +75,7 @@ The API accepts one identifier per request. Send requests to this endpoint: -``` +```bash POST https://{HOST_NAME}/v1/spaces/{SPACE_ID}/collections/users/profiles/user_id:{USER_ID_VALUE}/external_ids/delete ``` @@ -120,23 +120,23 @@ curl --location --request POST 'https://profiles.segment.com/v1/spaces/spa_abc12 ``` ## Responses and error codes - - -| HTTP Code | Code | Message | -| --------- | -------------------- | --------------------------------------------------------------------- | -| 200 | success | external identifier has been deleted | -| 400 | unsupported_eid_type | unsupported external id type | -| 400 | bad_request | missing required parameters in URL | -| 400 | bad_request | invalid URL: valid `user_id` is required. unsupported `` | -| 400 | bad_request | only one external_id can be deleted at a time | -| 400 | bad_request | invalid collection: `` | -| 400 | bad_request | external id specification must differ from lookup id | -| 401 | unauthorized | the specified token is invalid | -| 403 | forbidden | Deleted identifier not activated for space_id `` | -| 404 | not_found | the resource was not found | -| 404 | eid_not_found | external identifier not found | -| 404 | source_id_not_found | no source attached to space_id `` | -| 429 | rate_limit_error | Attempted to delete more than 100 IDs per second for a single profile | +The API returns the following HTTP status codes: + +| HTTP Code | Code | Message | +| --------- | ---------------------- | ----------------------------------------------------------------------- | +| `200` | `success` | External identifier has been deleted. | +| `400` | `unsupported_eid_type` | Unsupported external id type. | +| `400` | `bad_request` | Missing required parameters in URL. | +| `400` | `bad_request` | Invalid URL: valid `user_id` is required. Unsupported ``. | +| `400` | `bad_request` | Only one external_id can be deleted at a time. | +| `400` | `bad_request` | Invalid collection: ``. | +| `400` | `bad_request` | External id specification must differ from lookup id. | +| `401` | `unauthorized` | The specified token is invalid. | +| `403` | `forbidden` | Deleted identifier not activated for space_id ``. | +| `404` | `not_found` | The resource was not found. | +| `404` | `eid_not_found` | External identifier not found. | +| `404` | `source_id_not_found` | No source attached to space_id ``. | +| `429` | `rate_limit_error` | Attempted to delete more than 100 IDs per second for a single profile. | ## Limitations and considerations From 84d74dd1851b25d2d3aa4cb43b1ca17ae0d197ed Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 09:08:03 -0600 Subject: [PATCH 38/55] add private beta alert --- .../delete-profile-identifier-api.md | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index ebe0862c41..d36e4d2255 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -8,6 +8,11 @@ The Delete Profile Identifier API removes identifiers from a profile while prese Use this API to clean up outdated or incorrectly added identifiers without deleting entire profiles and replaying events. +This page explains how to use the API, including how deletions work across Segment systems and what to consider before you begin. + +> info "Delete Profile Identifier API Private Beta" +> The Delete Profile Identifier API is in Private Beta, and Segment is actively working on this feature. Some functionality may change before it becomes generally available. + ## Use cases The Delete Profile Identifier API helps you clean up identifiers that shouldn't be associated with a profile, including: @@ -20,7 +25,10 @@ The Delete Profile Identifier API helps you clean up identifiers that shouldn't ## Before you begin -The Delete Profile Identifier API is available to Unify and Engage customers during private beta. +> warning "Deletion scope" +> This API removes identifiers from Unify systems only. For complete user data deletion across all Segment systems (required for GDPR, CCPA, and other privacy regulations), see [Segment's user deletion and suppression guidance](/docs/privacy/user-deletion-and-suppression/). + +The Delete Profile Identifier API is available to Unify and Engage customers during private beta. You need one of these roles to delete identifiers: @@ -28,7 +36,7 @@ You need one of these roles to delete identifiers: - Identity Admin - Unify and Engage Admin -See [the Roles documentation](/docs/segment-app/iam/roles/) for more details. +See [the Roles documentation](/docs/segment-app/iam/roles/) for more detailss. If you use [Profiles Sync](/docs/unify/profiles-sync/overview/), you must also: @@ -138,9 +146,9 @@ The API returns the following HTTP status codes: | `404` | `source_id_not_found` | No source attached to space_id ``. | | `429` | `rate_limit_error` | Attempted to delete more than 100 IDs per second for a single profile. | -## Limitations and considerations +## Considerations and deletion behavior - +Keep the following information in mind as you use the Delete Profile Identifier API. ### Deletion scope @@ -156,10 +164,10 @@ Segment allows up to 100 deletion requests per second per space and 100 deletion Most deletion requests complete in under 3 seconds. Deletions on profiles with more than 15 merges or 50 identifier mappings may take longer. -Deletion propagates to connected systems at different speeds: +Deletion syncs to connected systems at different speeds: -- **Real-Time Profile Storage**: seconds to 5 minutes -- **Profile Sync**: depends on your sync schedule +- **Real-time Profile storage**: seconds to 5 minutes +- **Profiles Sync**: depends on your sync schedule ### Space rebuilds and replays @@ -167,10 +175,10 @@ If you rebuild a space from Segment Archives, deletions don't replay automatical ### Identifier reintroduction -Segment may reintroduce deleted identifiers in the following cases: +Segment may reintroduce deleted identifiers in these limited cases: -1. **Event replays**: Replaying events from the Event Archive that reference deleted identifiers adds them back to the profile. -2. **Engage or Journey sync timing**: Deleting an identifier within 5 minutes of sending an event that references it may result in the identifier being reintroduced through Engage-generated events. +- **Event replays**: Replaying events from the Event Archive that reference deleted identifiers adds them back to the profile. +- **Engage or Journey sync timing**: Deleting an identifier within 5 minutes of sending an event that references it may result in the identifier being reintroduced through Engage-generated events. ### Profile API source From c851481d58b7923fbb979420db9ab65d27f7e6aa Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 09:14:05 -0600 Subject: [PATCH 39/55] final touchups [netlify-build] --- .../delete-profile-identifier-api.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index d36e4d2255..9a5b1e1631 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -20,8 +20,8 @@ The Delete Profile Identifier API helps you clean up identifiers that shouldn't - Mistakenly imported identifiers, like incorrect email addresses, that prevent accurate targeting in downstream tools - Obsolete identifiers left over from database migrations or system changes - Identifiers with a short lifespan that need to transfer between profiles. For example, when a user changes phone numbers or when a prepaid service expires, you can remove the phone number from one profile and add it to another. -- Old identifiers that cause profiles to violate [ID Resolution limits]() -- Extra identifiers from misconfigured identity resolution settings. For example, if you reduced the `user_id` limit from 3 to 1, remove extra `user_id` values to resolve discrepancies between Segment and downstream tools like Braze or Amplitude. +- Old identifiers that cause profiles to violate [ID Resolution limits](/docs/unify/product-limits/#identity). +- Extra identifiers from misconfigured identity resolution settings. For example, if you reduced the `user_id` limit from 3 to 1, remove extra `user_id` values to resolve discrepancies between Segment and downstream tools like [Braze](/docs/connections/destinations/catalog/actions-braze-cloud/) or [Amplitude](/docs/connections/destinations/catalog/actions-amplitude/). ## Before you begin @@ -49,7 +49,7 @@ If you use [Profiles Sync](/docs/unify/profiles-sync/overview/), you must also: When you delete an identifier, Segment removes it from [Identity Resolution](/docs/unify/identity-resolution/) and syncs the change to connected systems. -The API confirms that Segment deleted the identifier from the Real-Time Identity Graph. The deletion then flows through these systems: +The API confirms that Segment deleted the identifier from the real-time Identity Graph. The deletion then flows through these systems: | System | What happens | | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -152,7 +152,7 @@ Keep the following information in mind as you use the Delete Profile Identifier ### Deletion scope -The Delete Profile Identifier API removes identifiers from Unify systems, including Identity Resolution, Profile Storage, and Profile Sync to your data warehouse. However, deletion doesn't extend to all Segment systems. Identifiers remain in the Event Archive and are soft-deleted in the Batch Profile Data Lakehouse. +The Delete Profile Identifier API removes identifiers from Unify systems, including Identity Resolution, Profile Storage, and Profile Sync to your data warehouse. However, deletion doesn't extend to all Segment systems. Identifiers remain in the event archive and are soft-deleted in the Batch Profile Data Lakehouse. Segment doesn't delete identifiers from downstream destinations like Braze, Amplitude, Facebook, Engage Audiences, Journeys, Linked Audiences, or Consent settings. You must update these systems separately. @@ -171,7 +171,7 @@ Deletion syncs to connected systems at different speeds: ### Space rebuilds and replays -If you rebuild a space from Segment Archives, deletions don't replay automatically. You must rerun deletions after the replay completes. +If you rebuild a space from Segment archives, deletions don't replay automatically. You must rerun deletions after the replay completes. ### Identifier reintroduction From 484ed20a0a9088ee0e363fee68312cc6073cdca0 Mon Sep 17 00:00:00 2001 From: CristhianMotoche Date: Fri, 7 Nov 2025 10:26:35 -0500 Subject: [PATCH 40/55] chore: Fix for recent change --- src/connections/auto-instrumentation/kotlin-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connections/auto-instrumentation/kotlin-setup.md b/src/connections/auto-instrumentation/kotlin-setup.md index 3c8ca07d9f..541cb52a7b 100644 --- a/src/connections/auto-instrumentation/kotlin-setup.md +++ b/src/connections/auto-instrumentation/kotlin-setup.md @@ -270,7 +270,7 @@ The following table lists the available options: | **maximumBufferSize** | No | Integer | The number of signals to be kept for JavaScript inspection. This buffer is first-in, first-out. Default is **1000**. | | **relayCount** | No | Integer | Relays every X signals to Segment. Default is **20**. | | **relayInterval** | No | Integer | Relays signals to Segment every X seconds. Default is **60**. | -| **broadcasters** | No | List | An array of broadcasters. These objects forward signal data to their destinations, like **WebhookBroadcaster**, or you could write your own **DebugBroadcaster** that writes logs to the developer console. **SegmentBroadcaster** is always added by the SDK. | +| **broadcasters** | No | List\ | An array of broadcasters. These objects forward signal data to their destinations, like **WebhookBroadcaster**, or you could write your own **DebugBroadcaster** that writes logs to the developer console. **SegmentBroadcaster** is always added by the SDK. | | **sendDebugSignalsToSegment** | No | Boolean | Turns on debug mode and allows the SDK to relay Signals to Segment server. Default is **false**. It should only be set to true for development purposes. | | **obfuscateDebugSignals** | No | Boolean | Obfuscates signals being relayed to Segment. Default is **true**. | From 53b3879a20fb36d538a55f481f839ac865fd4cd8 Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 09:56:07 -0600 Subject: [PATCH 41/55] quick fix --- src/unify/identity-resolution/delete-profile-identifier-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unify/identity-resolution/delete-profile-identifier-api.md b/src/unify/identity-resolution/delete-profile-identifier-api.md index 9a5b1e1631..d4008c4a39 100644 --- a/src/unify/identity-resolution/delete-profile-identifier-api.md +++ b/src/unify/identity-resolution/delete-profile-identifier-api.md @@ -36,7 +36,7 @@ You need one of these roles to delete identifiers: - Identity Admin - Unify and Engage Admin -See [the Roles documentation](/docs/segment-app/iam/roles/) for more detailss. +See [the Roles documentation](/docs/segment-app/iam/roles/) for more details. If you use [Profiles Sync](/docs/unify/profiles-sync/overview/), you must also: From 535c2e8dc885cc55f8ed769157771809231f8b59 Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 13:21:33 -0600 Subject: [PATCH 42/55] add journey context branch info --- .../v2/event-triggered-journeys-steps.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/engage/journeys/v2/event-triggered-journeys-steps.md b/src/engage/journeys/v2/event-triggered-journeys-steps.md index 0eb237231a..b097c55019 100644 --- a/src/engage/journeys/v2/event-triggered-journeys-steps.md +++ b/src/engage/journeys/v2/event-triggered-journeys-steps.md @@ -170,6 +170,22 @@ You can also give branches uniques name to differentiate them from each other on > info "Evaluation is sequential" > Segment evaluates branches in the order they appear in the configuration side sheet. If a profile qualifies for multiple branches, Segment sends it down the first one it matches. Profiles can't qualify for more than one branch, and Segment doesn't wait for audience membership to update after the profile enters the step. You can change the evaluation order by dragging branches up or down in the configuration side sheet. +### Branch on journey context + +Data split branches can evaluate conditions based on event properties stored in the journey context. This lets you route journey instances based on real-time event data instead of static profile information. + +When you configure a branch with journey context conditions: + +1. Select the event object from journey context. + - The triggering event is always available, and any events from Hold Until steps on the current path also show up. +2. Choose the specific property from that event. +3. Define the condition and value. + +Segment shows only event context available on the journey path leading to the Data split step. If an event was captured in a Hold Until step on a different branch, it won't appear as an option for conditions on the current branch. + +You can combine journey context conditions with trait-based and audience-based conditions in the same branch. Segment evaluates all conditions using `AND` logic, so the journey instance must satisfy every condition to follow that branch. + + ### Example: Target different customer types or event properties You can use a Data split to branch profiles based on event properties, traits, or audience membership that already exist on the profile when it reaches this step. For example: From 7c06c43e805c871127696d881259ccce9cd289d5 Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 13:25:10 -0600 Subject: [PATCH 43/55] clarify example use case --- src/engage/journeys/v2/event-triggered-journeys-steps.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/engage/journeys/v2/event-triggered-journeys-steps.md b/src/engage/journeys/v2/event-triggered-journeys-steps.md index b097c55019..e3b6e59af4 100644 --- a/src/engage/journeys/v2/event-triggered-journeys-steps.md +++ b/src/engage/journeys/v2/event-triggered-journeys-steps.md @@ -185,12 +185,11 @@ Segment shows only event context available on the journey path leading to the Da You can combine journey context conditions with trait-based and audience-based conditions in the same branch. Segment evaluates all conditions using `AND` logic, so the journey instance must satisfy every condition to follow that branch. - ### Example: Target different customer types or event properties -You can use a Data split to branch profiles based on event properties, traits, or audience membership that already exist on the profile when it reaches this step. For example: +You can use a Data split to branch journey instances based on event properties from journey context, profile traits, or audience membership. For example: -- Journey instances where the triggering event had a `transaction_total` > $100 are sent specific messaging about their high-ticket purchase. +- Journey instances where the triggering event's `transaction_total` property is greater than $100 receive high-value purchase messaging. - Profiles with a known `email_subscription_status` trait get treated as existing customers. - Profiles that belong to a `VIP` audience are routed down a separate path for high-value users. - Profiles with a specific set of traits (like favorite color and a known name) can receive personalized messaging. From c33c8fa1bb241d5a7106fe81e1b58babe8031d48 Mon Sep 17 00:00:00 2001 From: forstisabella <92472883+forstisabella@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:56:22 -0500 Subject: [PATCH 44/55] fixes [netlify-build] --- src/connections/delivery-overview.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/connections/delivery-overview.md b/src/connections/delivery-overview.md index bd65c6dacb..42eaf6470e 100644 --- a/src/connections/delivery-overview.md +++ b/src/connections/delivery-overview.md @@ -48,7 +48,7 @@ The pipeline view for storage destination includes the following steps: - **Failed on ingest**: Events that Segment received, but were dropped due to internal data validation rules. - **Filtered at source**: Events that were discarded due to schema settings or [Protocols](/docs/protocols/) Tracking Plans. - **Filtered at destination**: Events that were discarded due to [Destination Filters](/docs/guides/filtering-data/#destination-filters), [filtering in the Integrations object](/docs/guides/filtering-data/#filtering-with-the-integrations-object), [Destination Insert functions](/docs/connections/functions/insert-functions/), or [per source schema integration filters](/docs/guides/filtering-data/#per-source-schema-integrations-filters). [Actions destinations](/docs/connections/destinations/actions/) also have a filtering capability: for example, if your Action is set to only send Identify events, all other event types will be filtered out. Actions destinations with incomplete triggers or disabled mappings are filtered out at this step. [Consent Management](/docs/privacy/consent-management/) users also see events discarded due to consent preferences. -- **Events to warehouse rows**: A read-only box that shows the point in the delivery process where Segment converts events into warehouse rows. +- **Events pending retry**: A read-only box that shows the number of events that are awaiting retry. - **Failed to sync**: Syncs that either failed to sync or were partially successful. Selecting this step takes you to a table of all syncs with one or more failed collections. Select a sync from the table to view the discard reason, any collections that failed, the status, and the number of rows that synced for each collection. For information about common errors, see Ware - **Successfully synced**: A record of all successful or partially successful syncs made with your destination. To view the reason a partially successfully sync was not fully successful, see the Failed to sync step. @@ -60,11 +60,11 @@ The following image shows a storage destination with 23 partially successful syn You can view information about events sent from Linked Audiences downstream to the Snowflake destination with the following pipeline view: -- **Events from audience***: Events that Segment created for your activation. The number of events for each compute depends on the changes detected in your audience membership. +- **Events from audience**: Events that Segment created for your activation. The number of events for each compute depends on the changes detected in your audience membership. - **Filtered at source**: Events discarded by Protocols: either by the [schema settings](/docs/protocols/enforce/schema-configuration/) or [Tracking Plans](/docs/protocols/tracking-plan/create/). - **Filtered at destination**: Events that were discarded due to [Destination Filters](/docs/guides/filtering-data/#destination-filters), [filtering in the Integrations object](/docs/guides/filtering-data/#filtering-with-the-integrations-object), [Destination Insert functions](/docs/connections/functions/insert-functions/), or [per source schema integration filters](/docs/guides/filtering-data/#per-source-schema-integrations-filters). [Actions destinations](/docs/connections/destinations/actions/) also have a filtering capability: for example, if your Action is set to only send Identify events, all other event types will be filtered out. Actions destinations with incomplete triggers or disabled mappings are filtered out at this step. [Consent Management](/docs/privacy/consent-management/) users also see events discarded due to consent preferences. -- **Events to warehouse rows**: A read-only box that shows the point in the delivery process where Segment converts events into Snowflake warehouse rows. -- **Failed delivery**: Events that have been discarded due to errors or unmet destination requirements. Click into this step to view a table of all collections with one or more failed events. Select a collection from the table to view the discard reason, any events that failed, and the status. For information about common errors, see [Warehouse Errors](docs/connections/storage/warehouses/warehouse-errors). +- **Events pending retry**: A read-only box that shows the number of events that are awaiting retry. +- **Failed delivery**: Events that have been discarded due to errors or unmet destination requirements. Select a discard reason from the table to view all events that failed, sorted by collection. For information about common errors, see [Warehouse Errors](/docs/connections/storage/warehouses/warehouse-errors). - **Successful delivery**: Events that were successfully delivered to Snowflake. #### Destinations connected to Engage Destinations From 2d0cb599d703be4f8436550b8eb3f383e32bf532 Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 13:59:16 -0600 Subject: [PATCH 45/55] Add path join section --- .../v2/event-triggered-journeys-steps.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/engage/journeys/v2/event-triggered-journeys-steps.md b/src/engage/journeys/v2/event-triggered-journeys-steps.md index e3b6e59af4..85c9fcacc7 100644 --- a/src/engage/journeys/v2/event-triggered-journeys-steps.md +++ b/src/engage/journeys/v2/event-triggered-journeys-steps.md @@ -442,3 +442,30 @@ There may be cases where events sent to Segment are missing specific properties - Similarly, if a mapped trait is missing on the profile, the key is included in the payload with a value of `undefined`. Carefully configuring mappings and handling missing attributes can help you maintain data integrity and avoid errors in downstream systems. + +## Reconnect branches with path joins + +Path joins let you connect one branch of a journey to a step in another branch. This eliminates duplicate steps and saves journey step credits when multiple branches need to converge on the same downstream actions. + +Use path joins when different user segments need different initial treatments but should follow the same steps afterward. For example, high-value customers might receive multiple touchpoints through one branch while standard customers skip directly to a general follow-up step that both groups eventually reach. + +Path joins work well when: + +- Different user segments require unique messaging initially but share common downstream steps +- One branch needs fewer steps than another, and you want both to converge at a specific point +- Multiple branches lead to the same destination send or action step +- You want to reduce journey complexity and avoid duplicating identical steps across branches + +### When to use path joins + +### Create a path join + +To create a path join: + +1. Navigate to the last step in the branch you want to connect. +2. Click the **+** icon at the end of that branch. +3. Select **Connect path to existing step**. +4. Choose a step from another branch to connect to. Segment only shows the available steps you can connect to. +5. The connection appears as a line on the canvas, showing the path join between branches. + +You can only connect to child steps (steps that come after the split), not parent steps or steps earlier in the journey. Each branch endpoint supports one path join connection. From cbe8ba3707e7c73bc66ec22a34d2fbeb1c477fa1 Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 14:20:13 -0600 Subject: [PATCH 46/55] add path joins screenshot [netlify-build] --- src/engage/journeys/images/path_joins.png | Bin 0 -> 104041 bytes .../v2/event-triggered-journeys-steps.md | 42 +++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/engage/journeys/images/path_joins.png diff --git a/src/engage/journeys/images/path_joins.png b/src/engage/journeys/images/path_joins.png new file mode 100644 index 0000000000000000000000000000000000000000..5e98d61470f6b26f326ef5f90d433698912f71ff GIT binary patch literal 104041 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%0A_791p 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 z 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

qQpteHCZJDk_vSrw0ecwToV5*10*e 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 info "" +> You can only edit path join connections while the journey is in Draft state. Published journeys must be edited in a new version to modify path joins. + +### Journey context and path joins + +When branches reconnect through a path join, the journey context for profiles includes only the events from their specific path. Context from steps on other branches is not available. + +For example, if Branch A includes a Hold Until step that captures an event, and Branch B connects to a step after that Hold Until, profiles from Branch B won't have access to the event context from Branch A's Hold Until step. Only profiles that actually passed through Branch A will have that context available. + +When you configure Data split conditions after a path join, Segment dynamically shows only the context available for each possible path leading to that split. \ No newline at end of file From a11416df3b93d3e4638ac57267e0c8579fae4169 Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 14:22:49 -0600 Subject: [PATCH 47/55] fix directory issue [netlify-build] --- src/engage/journeys/v2/event-triggered-journeys-steps.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engage/journeys/v2/event-triggered-journeys-steps.md b/src/engage/journeys/v2/event-triggered-journeys-steps.md index a72d0a62ed..cc7d14f49b 100644 --- a/src/engage/journeys/v2/event-triggered-journeys-steps.md +++ b/src/engage/journeys/v2/event-triggered-journeys-steps.md @@ -460,13 +460,13 @@ Path joins work well when: To create a path join: -1. Navigate to the last step in the branch you want to connect. +1. Go to the last step in the branch you want to connect. 2. Click the **+** icon at the end of that branch. 3. Select **Connect path to existing step**. 4. Choose a step from another branch to connect to. Segment only shows the available steps you can connect to. 5. The connection appears as a line on the canvas, showing the path join between branches. -![Journey canvas showing the Connect path to existing step option in a dropdown menu. The menu appears when clicking a plus icon at the end of a journey branch, showing flow control options like Delay, Hold until, Data split, and Randomized split, along with the Connect path to existing step option at the top.](../images/application_started.png) +![Journey canvas showing the Connect path to existing step option in a dropdown menu. The menu appears when clicking a plus icon at the end of a journey branch, showing flow control options like Delay, Hold until, Data split, and Randomized split, along with the Connect path to existing step option at the top.](../images/path_joins.png) You can only connect to child steps (steps that come after the split), not parent steps or steps earlier in the journey. Each branch endpoint supports one path join connection. From c9907d844f4cc3037370f695077a3d97722b1eb0 Mon Sep 17 00:00:00 2001 From: pwseg <86626706+pwseg@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:32:39 -0600 Subject: [PATCH 48/55] Update src/engage/journeys/v2/event-triggered-journeys-steps.md Co-authored-by: rchinn1 <93161299+rchinn1@users.noreply.github.com> --- src/engage/journeys/v2/event-triggered-journeys-steps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engage/journeys/v2/event-triggered-journeys-steps.md b/src/engage/journeys/v2/event-triggered-journeys-steps.md index cc7d14f49b..e7def392dd 100644 --- a/src/engage/journeys/v2/event-triggered-journeys-steps.md +++ b/src/engage/journeys/v2/event-triggered-journeys-steps.md @@ -177,7 +177,7 @@ Data split branches can evaluate conditions based on event properties stored in When you configure a branch with journey context conditions: 1. Select the event object from journey context. - - The triggering event is always available, and any events from Hold Until steps on the current path also show up. + - The triggering event is always available, and any events from Hold until steps on the current path also show up. 2. Choose the specific property from that event. 3. Define the condition and value. From b3b20948a6d43be0471df82db6bf97b4ee013168 Mon Sep 17 00:00:00 2001 From: pwseg <86626706+pwseg@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:32:46 -0600 Subject: [PATCH 49/55] Update src/engage/journeys/v2/event-triggered-journeys-steps.md Co-authored-by: rchinn1 <93161299+rchinn1@users.noreply.github.com> --- src/engage/journeys/v2/event-triggered-journeys-steps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engage/journeys/v2/event-triggered-journeys-steps.md b/src/engage/journeys/v2/event-triggered-journeys-steps.md index e7def392dd..9ba4f9c84a 100644 --- a/src/engage/journeys/v2/event-triggered-journeys-steps.md +++ b/src/engage/journeys/v2/event-triggered-journeys-steps.md @@ -181,7 +181,7 @@ When you configure a branch with journey context conditions: 2. Choose the specific property from that event. 3. Define the condition and value. -Segment shows only event context available on the journey path leading to the Data split step. If an event was captured in a Hold Until step on a different branch, it won't appear as an option for conditions on the current branch. +Segment shows only event context available on the journey path leading to the Data split step. If an event was captured in a Hold until step on a different branch, it won't appear as an option for conditions on the current branch. You can combine journey context conditions with trait-based and audience-based conditions in the same branch. Segment evaluates all conditions using `AND` logic, so the journey instance must satisfy every condition to follow that branch. From e1c3e2dec37659f0a1a57626f19c29d3ccea088b Mon Sep 17 00:00:00 2001 From: pwseg <86626706+pwseg@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:32:52 -0600 Subject: [PATCH 50/55] Update src/engage/journeys/v2/event-triggered-journeys-steps.md Co-authored-by: rchinn1 <93161299+rchinn1@users.noreply.github.com> --- src/engage/journeys/v2/event-triggered-journeys-steps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engage/journeys/v2/event-triggered-journeys-steps.md b/src/engage/journeys/v2/event-triggered-journeys-steps.md index 9ba4f9c84a..3bdf62f543 100644 --- a/src/engage/journeys/v2/event-triggered-journeys-steps.md +++ b/src/engage/journeys/v2/event-triggered-journeys-steps.md @@ -445,7 +445,7 @@ Carefully configuring mappings and handling missing attributes can help you main ## Reconnect branches with path joins -Path joins let you connect one branch of a journey to a step in another branch. This eliminates duplicate steps and saves journey step credits when multiple branches need to converge on the same downstream actions. +Path joins connect a branch of a journey to a step in another branch. This eliminates duplicate steps and saves journey step credits when multiple branches need to converge on the same downstream actions. Use path joins when different user segments need different initial treatments but should follow the same steps afterward. For example, high-value customers might receive multiple touchpoints through one branch while standard customers skip directly to a general follow-up step that both groups eventually reach. From 8ed54519aee78698963fe63f2732308e7efa5c0d Mon Sep 17 00:00:00 2001 From: pwseg <86626706+pwseg@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:33:10 -0600 Subject: [PATCH 51/55] Update src/engage/journeys/v2/event-triggered-journeys-steps.md Co-authored-by: rchinn1 <93161299+rchinn1@users.noreply.github.com> --- src/engage/journeys/v2/event-triggered-journeys-steps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engage/journeys/v2/event-triggered-journeys-steps.md b/src/engage/journeys/v2/event-triggered-journeys-steps.md index 3bdf62f543..0f95bb68d4 100644 --- a/src/engage/journeys/v2/event-triggered-journeys-steps.md +++ b/src/engage/journeys/v2/event-triggered-journeys-steps.md @@ -504,6 +504,6 @@ From the target step: When branches reconnect through a path join, the journey context for profiles includes only the events from their specific path. Context from steps on other branches is not available. -For example, if Branch A includes a Hold Until step that captures an event, and Branch B connects to a step after that Hold Until, profiles from Branch B won't have access to the event context from Branch A's Hold Until step. Only profiles that actually passed through Branch A will have that context available. +For example, if Branch A includes a Hold until step that captures an event, and Branch B connects to a step after that Hold until, profiles from Branch B won't have access to the event context from Branch A's Hold until step. Only profiles that actually passed through Branch A will have that context available. When you configure Data split conditions after a path join, Segment dynamically shows only the context available for each possible path leading to that split. \ No newline at end of file From ad22723829bdcff4f7151f5baf657fc0e873fb0e Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 16:35:08 -0600 Subject: [PATCH 52/55] hide quick info box --- src/connections/destinations/catalog/satismeter/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/connections/destinations/catalog/satismeter/index.md b/src/connections/destinations/catalog/satismeter/index.md index a56505fe7e..82da8e3ce6 100644 --- a/src/connections/destinations/catalog/satismeter/index.md +++ b/src/connections/destinations/catalog/satismeter/index.md @@ -1,6 +1,7 @@ --- title: SatisMeter Destination id: 54c02a5adb31d978f14a7f6f +hide-dossier: true --- [Our SatisMeter destination code](https://github.com/segment-integrations/analytics.js-integration-satismeter){:target="_blank"} is all open-source on GitHub if you want to check it out. From 173dd092b0ca5e69e91d80864415d16cb38f758b Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 17:04:06 -0600 Subject: [PATCH 53/55] show destination info --- src/connections/destinations/catalog/actions-s3/index.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/connections/destinations/catalog/actions-s3/index.md b/src/connections/destinations/catalog/actions-s3/index.md index db3ab8a919..5eec08aa34 100644 --- a/src/connections/destinations/catalog/actions-s3/index.md +++ b/src/connections/destinations/catalog/actions-s3/index.md @@ -1,7 +1,5 @@ --- title: AWS S3 (Actions) Destination -hide-boilerplate: true -hide-dossier: false id: 66eaa166f650644f04389e2c private: true beta: true From 60c0314f5fcb76034c2a7d44485efa68611eed6c Mon Sep 17 00:00:00 2001 From: pwseg Date: Fri, 7 Nov 2025 17:23:55 -0600 Subject: [PATCH 54/55] add a couple of new limits --- src/engage/journeys/v2/limits.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/engage/journeys/v2/limits.md b/src/engage/journeys/v2/limits.md index 0b45249bca..b3b45c1726 100644 --- a/src/engage/journeys/v2/limits.md +++ b/src/engage/journeys/v2/limits.md @@ -7,15 +7,15 @@ This page outlines product limitations for Event-Triggered (V2) Journeys. ## General limits -| Name | Limit | Description | -| ------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| Steps | 50 | Maximum number of steps per journey. | -| Journey name | 73 characters | Maximum length for Journey names. Names must be unique. | -| Step name | 73 characters | Maximum length for step names. | -| Branch name | 73 characters | Maximum length for branch names within a split step. Branch names must be unique across the journey. | -| Additional branches | 5 | Maximum number of branches supported in a split or Hold Until step. | -| Delay duration | Minimum: 5 minutes
Maximum: 182 days | Allowed time range for Delay and Hold Until steps. | -| Unique identifier | 500 characters | For “Re-enter every time event occurs” rules, you must define a unique identifier. The value is limited to 500 characters. | +| Name | Limit | Description | +| ------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Steps | 50 | Maximum number of steps per journey. | +| Journey name | 73 characters | Maximum length for Journey names. Names must be unique. | +| Step name | 73 characters | Maximum length for step names. | +| Branch name | 73 characters | Maximum length for branch names within a split step. Branch names must be unique across the journey. | +| Additional branches | 5 | Maximum number of branches supported in a split or Hold Until step. | +| Delay duration | Minimum: 5 minutes
Maximum: 182 days | Allowed time range for Delay and Hold Until steps. | +| Unique identifier | Property name: 500 characters
Property value: 150 characters | For "Re-enter every time event occurs" rules, you must define a unique identifier. The property name is limited to 500 characters, and the property value is limited to 150 characters. | ## Journey Step Billing @@ -35,7 +35,7 @@ Plans with compute credits instead of journey steps consume 1 compute credit for | Name | Limit | Description | | ------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | Requests per second (RPS) | 25 events/sec/profile | Maximum events per second per Segment ID. Timer events are excluded. Excess events get dropped. | -| Instances per profile | 25 concurrent instances | Maximum concurrent Journey instances per profile. | +| Instances per profile | 25 concurrent instances | Maximum concurrent journey instances per profile across all journeys. | | Send profiles back branch | 100 instances | Maximum count a single journey instance can pass through a Wait Until Send profiles back to the beginning of this step' branch. | ## Journey context From f558dbced43393a1681e65523fc128db2dcd525d Mon Sep 17 00:00:00 2001 From: pwseg <86626706+pwseg@users.noreply.github.com> Date: Fri, 7 Nov 2025 17:34:17 -0600 Subject: [PATCH 55/55] nvm hide everything --- src/connections/destinations/catalog/actions-s3/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/connections/destinations/catalog/actions-s3/index.md b/src/connections/destinations/catalog/actions-s3/index.md index 5eec08aa34..e1de9ce71d 100644 --- a/src/connections/destinations/catalog/actions-s3/index.md +++ b/src/connections/destinations/catalog/actions-s3/index.md @@ -1,6 +1,8 @@ --- title: AWS S3 (Actions) Destination id: 66eaa166f650644f04389e2c +hide-boilerplate: true +hide-dossier: true private: true beta: true # versions: