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:

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_features etc. 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 bucketing event is enqueued for delivery, and a debug line 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 self

The per-call override — enable_tracking

Suppress 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.

Neither tracking switch touches the bucketing lifecycle event — 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. (An active preview is the one thing that does silence the lifecycle event — see below.)

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 trackingPer-call enable_trackingEvent enqueued?
truetrue (default)Yes
truefalseNo
falsetrueNo (global-off wins)
falsefalseNo

The third path — preview is zero-trace, not a switch

Context#set_preview is not a consent switch, but it is the strongest suppression in the SDK, so it belongs in the same mental model. While a preview is active on a context, that context records nothing — and unlike the tracking switches, this covers persistence and the lifecycle events too:

SurfaceUnder a tracking switch (global tracking: false or per-call enable_tracking: false)Under an active preview
Decisioning (bucketing, rules, features, segment matching)RunsRuns — only the previewed experience is forced
Sticky StoreData writePersistsSkipped
bucketing lifecycle eventFiresDoes not fire
Outbound event enqueueSuppressedSuppressed
track_conversionThe global switch suppresses the whole call before the dedup mark, so no conversion event fires either; there is no per-call switch on this methodFull no-op — nothing enqueued, no conversion event, no dedup mark
update_visitor_propertiesPersistsIn-memory merge only, store write skipped
set_default_segments / run_custom_segmentsPersistsMatching runs, store write skipped

This applies to every experience and feature evaluated on that context, not only the previewed one — so a page under preview still renders coherently while recording nothing. Preview state is per-Context: another context on the same client tracks normally.

See Code Examples for the wiring and QA & Preview for the preview-link workflow.

Consent scenarios

ScenarioWhat to do
Consent denied for the whole clientConvertSdk.create(..., tracking: false). Decisions and stickiness still work; nothing is delivered.
Consent denied for a specific call onlyKeep 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


Did this page help you?