Skip to content

TrackingControl

Joseph Samir edited this page Jun 21, 2026 · 3 revisions

Tracking Control

The iOS SDK has three independent layers that control whether outbound tracking events are sent. Use them to honor consent without losing your experiment logic — bucketing, rule evaluation, sticky persistence, and goal dedup keep working regardless of the tracking state. Only the network side is silenced.

Layer 1 — Static init-time flag (ConvertConfiguration.networkTracking)

Set at construction time and immutable for the SDK's lifetime:

import ConvertSwiftSDK

let config = ConvertConfiguration(sdkKey: "YOUR_SDK_KEY", networkTracking: false)
let sdk = ConvertSwiftSDK(configuration: config)

When networkTracking is false, no events are ever enqueued for the lifetime of that ConvertSwiftSDK instance. This is the reliable kill-switch for all tracking — experiences, features, and conversions. The SDK still buckets visitors and returns decisions; only the send is suppressed.

This flag seeds the runtime toggle (Layer 3): await sdk.isTrackingEnabled() returns this value until setTrackingEnabled(_:) changes it.

Layer 2 — Per-call enableTracking on experience methods

Suppress the exposure event for a single decision call:

// bucket without emitting the exposure event for this one call
let variation = await context.runExperience("homepage-redesign", enableTracking: false)
await context.runExperiences(enableTracking: false)

When enableTracking: false, bucketing, sticky persistence, audience rules, and the .bucketing event bus signal still fire — only the outbound exposure event to Convert is skipped.

This parameter exists only on runExperience and runExperiences. The feature methods (runFeature, runFeatures) take no enableTracking parameter (Android SDK parity). Likewise, trackConversion has no per-call tracking flag (FR23). To suppress those paths selectively, use the static networkTracking: false or the runtime toggle.

Layer 3 — Runtime toggle (setTrackingEnabled / isTrackingEnabled)

An actor-backed flag you can flip at any point after initialization, for mid-session consent withdrawal:

// suppress all subsequent events (e.g. on GDPR consent withdrawal)
await sdk.setTrackingEnabled(false)

// re-enable after consent re-grant
await sdk.setTrackingEnabled(true)

// read the current state
let isOn = await sdk.isTrackingEnabled()

Completion-handler overloads are available for UIKit / Objective-C callers:

sdk.setTrackingEnabled(false) {
    // called on MainActor once the actor flag is closed
}
sdk.isTrackingEnabled { isOn in print("tracking:", isOn) }

When false:

  • Every enqueue on the event sink is dropped — events are not buffered and do not replay on re-enable.
  • runExperience / runExperiences suppress the bucketing enqueue (decisioning is unaffected).
  • trackConversion suppresses both the conversion and transaction enqueues. The per-visitor dedup mark is still written before the gate, so a suppressed conversion is still counted as "triggered" — a re-enabled later call will not re-fire the conversion event.
  • The local SystemEvent.conversion bus signal still fires on first trigger regardless of the network gate (JS parity — only delivery to Convert is suppressed).

When re-enabled: the gate re-opens for new events only. Events generated while disabled were never buffered; they are not recovered. Previously persisted events (from before the disable) continue draining normally through the queue.

The ConvertSwiftSDK handle stays an all-let Sendable final class — the mutable bit lives inside the actor TrackingState held by let.

How the three layers combine

Layers 1 and 3 are an AND gate for delivery. An event is delivered only when networkTracking == true (Layer 1) and setTrackingEnabled is true (Layer 3) and, for experience calls, the per-call enableTracking is true (Layer 2).

networkTracking (init) Runtime setTrackingEnabled Per-call enableTracking Experience event shipped?
true true (default) true (default) Yes
true true false No
true false any No
false any any No

Consent scenarios

Scenario What to do
Consent unknown at launch ConvertConfiguration(sdkKey:, networkTracking: false) — start silent; call await sdk.setTrackingEnabled(true) once consent resolves.
Consent withdrawn mid-session await sdk.setTrackingEnabled(false). In-flight queue continues draining; new events stay silent.
Do not initialize at all If the user has not consented, simply do not construct ConvertSwiftSDK. No identifier is generated, no bucketing runs, no event is sent.
Suppress per-feature There is no per-call flag on runFeature/runFeatures; use networkTracking: false or the runtime toggle for the whole SDK.
Suppress a single experience Keep the SDK-level toggles true and pass enableTracking: false on the specific runExperience call.

Relationship to the offline queue

Disabling tracking (via Layer 1 or 3) stops events from being enqueued. It does not flush or clear events already persisted to the on-disk queue from a previous session — those continue through the normal background delivery path. See Offline Behavior.

Related pages

Clone this wiki locally