Tracking Control
Consent: global tracking switch and per-call enable_tracking override
Two independent switches control whether the SDK sends outbound tracking events: a global config switch and a per-call override. Use them to honor consent without losing your experiment logic — bucketing, rule evaluation, and sticky persistence keep working regardless of the tracking state. Only the outbound network enqueue is silenced.
The global switch — tracking:
tracking:Set tracking: false at ConvertSdk.create to disable all outbound event tracking for the client:
CONVERT_SDK = ConvertSdk.create(
sdk_key: ENV.fetch("CONVERT_SDK_KEY"),
tracking: false # default is true
)When tracking is false:
- Decisioning still runs.
run_experience/run_featuresetc. still bucket the visitor and return real results. - Sticky StoreData still persists. Variation assignments and visitor properties are still written to the store.
- The outbound event enqueue is suppressed. No
bucketingevent is enqueued for delivery, and adebugline records each suppression (tracking disabled, event suppressed).
Conversions under the global switch
track_conversion checks the global switch before the dedup-and-mark step. So when tracking is false a conversion is neither enqueued nor marked as deduplicated — meaning a subsequent same-goal call stays unblocked once tracking is re-enabled. The return value is unchanged (self); no sentinel:
context.track_conversion("purchase")
# tracking: false -> nothing enqueued, goal NOT marked, debug line emitted, returns selfThe per-call override — enable_tracking
enable_trackingSuppress the event for a single decision call by putting enable_tracking: false in the per-call attributes hash (symbol or string key both work — the public boundary accepts both):
variation = context.run_experience("homepage-test", { enable_tracking: false })
context.run_experiences({ enable_tracking: false })When enable_tracking: false, bucketing, sticky persistence, audience rules, and the internal bucketing lifecycle event still fire — only the outbound enqueue is skipped (a debug line records the suppression: tracking suppressed for call). Absent or any non-false value leaves tracking on; only an explicit false suppresses.
The
bucketinglifecycle event always fires — it is decisioning observability, not tracking, so a host listener can react to the decision even under consent denial. Only the outbound enqueue is gated by the tracking switches.
How the two combine — global-off always wins
The verdict for whether an event is enqueued is the composition of both switches. The global switch is dominant: a global tracking: false suppresses delivery regardless of a per-call enable_tracking: true.
Global tracking | Per-call enable_tracking | Event enqueued? |
|---|---|---|
true | true (default) | Yes |
true | false | No |
false | true | No (global-off wins) |
false | false | No |
Consent scenarios
| Scenario | What to do |
|---|---|
| Consent denied for the whole client | ConvertSdk.create(..., tracking: false). Decisions and stickiness still work; nothing is delivered. |
| Consent denied for a specific call only | Keep the global tracking: true and pass enable_tracking: false on the calls you want silent. |
| Diagnosing "events vanish" | Confirm tracking is not disabled — a tracking disabled, event suppressed / tracking suppressed for call debug line is the signal. See the missing-events decision tree. |
Related pages
- Configuration Options — the
trackingconfig option - Code Examples — per-call suppression in context
- Tracking Conversions — the shared conversion concept doc