Skip to content

CodeExamples

Ahmed Abbas edited this page Jun 8, 2026 · 1 revision

Code Examples

Complete, copy-pasteable examples for every public method of the Convert Ruby SDK. The public API is snake_case; only the wire payloads are camelCase (translated internally). All examples assume a single CONVERT_SDK client built once at boot (see Initialization).

Build the client

require "convert_sdk"

# Fetch mode.
CONVERT_SDK = ConvertSdk.create(
  sdk_key:        ENV.fetch("CONVERT_SDK_KEY"),
  sdk_key_secret: ENV["CONVERT_SDK_KEY_SECRET"],
  environment:    "prod"
)

# Direct-data mode (no network fetch).
CONVERT_SDK = ConvertSdk.create(data: load_pre_fetched_config)

Subscribe to lifecycle events

Client#on(event, &block) subscribes to a SystemEvents value (or its matching string) and returns self. Deferred one-shot events replay to late subscribers.

CONVERT_SDK.on("ready") do |_payload, _err|
  # decisions are available from here on
end

CONVERT_SDK.on(ConvertSdk::SystemEvents::BUCKETING) do |payload, _err|
  # payload => { visitor_id:, experience_key:, variation_key: }
end

CONVERT_SDK.on(ConvertSdk::SystemEvents::CONVERSION) do |payload, _err|
  # payload => { visitor_id:, goal_key: }
end

Create a visitor context

create_context(visitor_id = nil, attributes = nil) returns a fresh, independent Context (or nil for a blank visitor id). Attributes accept symbol or string keys.

# Visitor id only.
context = CONVERT_SDK.create_context("visitor-123")

# Visitor id + initial attributes.
context = CONVERT_SDK.create_context("visitor-123", { country: "US", plan: "premium" })

Run a single experience

run_experience(key, attributes = nil) returns a BucketedVariation on a hit or a Sentinel on a miss — never raises, never a bare nil.

variation = context.run_experience("homepage-test")
case variation&.key
when nil          then render_default     # sentinel miss (key is nil)
when "treatment"  then render_treatment
else                   render_variation(variation.key)
end

Per-call attributes are merged over the context's attributes (per-call wins):

variation = context.run_experience("homepage-test", { country: "DE" })

Run all experiences

run_experiences(attributes = nil) returns an Array<BucketedVariation>misses are filtered out, so the array contains only variations the visitor was actually bucketed into.

context.run_experiences.each do |variation|
  activate(variation.experience_key, variation.key)
end

Evaluate a single feature

run_feature(key, attributes = nil) returns a frozen BucketedFeature (or an Array when several bucketed variations carry the feature). A miss is a DISABLED BucketedFeature, never a sentinel — branch on #status.

feature = context.run_feature("new-checkout")
if feature.status == ConvertSdk::FeatureStatus::ENABLED
  render_new_checkout(feature.variables["headline"])
else
  render_legacy_checkout
end

Evaluate all features

run_features(attributes = nil) returns an Array<BucketedFeature> — the full roster, every declared feature evaluated for this visitor (enabled + disabled).

context.run_features.each do |feature|
  toggle(feature.key, on: feature.status == ConvertSdk::FeatureStatus::ENABLED)
end

Track a conversion

track_conversion(goal_key, goal_data: nil, force_multiple_transactions: false) records a conversion, deduplicated per visitor per goal. Returns self.

# Bare conversion.
context.track_conversion("signup")

# With revenue / transaction data (snake_case goal-data keys).
context.track_conversion(
  "purchase",
  goal_data: { amount: 49.99, products_count: 3, transaction_id: "tx-42" }
)

The eight accepted goal_data keys are listed in Return Types & Sentinels. Unknown keys are rejected and debug-logged.

Force a repeat transaction (bypass dedup)

By default a goal records once per visitor. For renewals or repeat purchases, bypass the dedup check:

context.track_conversion(
  "purchase",
  goal_data: { amount: 49.99, transaction_id: "tx-43" },
  force_multiple_transactions: true
)

force_multiple_transactions: true enqueues the repeat transaction without re-marking the goal.

Suppress tracking for a single call

Pass enable_tracking: false in the per-call attributes hash to evaluate but not report (e.g. a consent-denied flow). Bucketing, sticky persistence, and the bucketing lifecycle event still fire — only the outbound network enqueue is skipped.

variation = context.run_experience("homepage-test", { enable_tracking: false })
context.run_experiences({ enable_tracking: false })

The global tracking: false config switch always wins over a per-call true. See Tracking Control.

Set default report-segments

set_default_segments(segments) attaches default report-segments for the visitor (filtered to the platform report keys), merged into the visitor's stored segments. Returns self. Supply the wire keys (visitorType, customSegments, …).

context.set_default_segments({ "visitorType" => "new", "customSegments" => ["beta"] })

Run custom segments

run_custom_segments(segment_keys, attributes = nil) evaluates named custom segments against the visitor's properties and attaches matching ids under customSegments in StoreData. Returns a propagated RuleError sentinel, or nil.

context.run_custom_segments(["high-value", "returning"])

# With per-call rule data.
context.run_custom_segments(["high-value"], { ruleData: { lifetime_value: 1250 } })

See Segments.

Update visitor properties (sticky)

update_visitor_properties(properties) merges sticky properties into both the in-memory attributes (so a later decision on this context sees them immediately) and the store (so a later context for the same visitor sees them — stickiness). Returns self.

context.update_visitor_properties({ plan: "premium", account_age_days: 120 })

See Visitor Context.

Read persisted visitor data

get_visitor_data returns the visitor's stored, string-keyed StoreData, or the empty shape { "bucketing" => {}, "segments" => {}, "goals" => {} } when nothing is stored.

data = context.get_visitor_data
data["bucketing"] # sticky variation assignments
data["segments"]  # attached report-segments
data["goals"]     # converted goals (dedup state)

Look up a config entity

get_config_entity(key, entity_type) looks up a config entity by key. entity_type is one of :experience, :feature, :goal (symbol or string). Returns the frozen entity hash, or nil on a miss (debug-logged).

experience = context.get_config_entity("homepage-test", :experience)
feature    = context.get_config_entity("new-checkout", :feature)
goal       = context.get_config_entity("purchase", :goal)

Flush queued events

flush(reason = nil) (alias release_queues) delivers queued events synchronously and returns self. An empty queue is a no-op. Long-running servers also drain via the background flush timer; short-lived processes must flush explicitly before exit.

CONVERT_SDK.flush
CONVERT_SDK.flush("shutdown")   # optional human-readable reason (logged)
CONVERT_SDK.release_queues       # the frozen-name alias — same path

Re-arm after a fork

postfork explicitly re-arms the client after a fork — rarely needed (automatic Process._fork detection covers the common runtimes). Returns self. See Fork Safety & Runtime Recipes.

# e.g. after Process.daemon, or in a worker-boot hook for belt-and-braces
CONVERT_SDK.postfork

Next steps

Clone this wiki locally