Tracking Control
Consent: static networkTracking, per-call enableTracking, and runtime setTrackingEnabled
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)
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
enableTracking on experience methodsSuppress 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)
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/runExperiencessuppress the bucketing enqueue (decisioning is unaffected).trackConversionsuppresses 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.conversionbus 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
- Configuration Options — the
networkTrackingparameter onConvertConfiguration - App Privacy & Data Collection — what data the SDK collects when tracking is on
- Objective-C / Completion-Handler Interop — callback overloads of the async toggle API