-
Notifications
You must be signed in to change notification settings - Fork 0
Initialization
ConvertSdk.create is THE public entry point. It builds the validated configuration, wires the SDK's managers, drives the config lifecycle, and returns a ready-to-use ConvertSdk::Client. Build exactly one client per process and reuse it for the process lifetime — the client owns the shared config, store, event, and delivery surfaces.
create is the SDK's only raising surface: it raises ArgumentError on misconfiguration (missing sdk_key/data, bad types, an unknown option key). Every other public method degrades to a documented return value and a log line instead of raising.
ConvertSdk.create(sdk_key: nil, data: nil, store: nil, clock: nil, sink: nil, **options) #=> ClientThe keyword arguments fall into two groups: the wiring seams (store:, clock:, sink:) extracted before config validation, and **options — any config option (sdk_key_secret:, environment:, log_level:, timeouts, …).
The client supports two mutually-exclusive config sources. At least one of sdk_key: / data: is required (otherwise ArgumentError).
Pass an sdk_key: and the client fetches config synchronously at construction via GET {config_endpoint}/config/{sdk_key} (with ?environment=... appended when environment: is set). When sdk_key_secret: is configured, an Authorization: Bearer {secret} header is attached (the secret is redacted from every log line).
CONVERT_SDK = ConvertSdk.create(
sdk_key: ENV.fetch("CONVERT_SDK_KEY"),
sdk_key_secret: ENV["CONVERT_SDK_KEY_SECRET"] # optional bearer secret
)A failed fetch never raises — it is logged at warn and the client is constructed without config (degrade-gracefully). It may fall back to a non-stale cached entry from the store (meaningful across processes with a shared RedisStore).
Pass a pre-fetched config object and no network fetch happens — the inline object is normalised to string keys and installed straight away. This is the single network-free path, ideal for tests and advanced setups:
config = load_pre_fetched_config # your own loader / fixture
CONVERT_SDK = ConvertSdk.create(data: config)Symbol-keyed inputs are accepted — they are deep-stringified at the public boundary so the installed snapshot matches the string-keyed wire shape exactly.
The first successful config install (fetched or direct) fires ready exactly once for the client's lifetime. Subsequent installs (the background refresh) fire config.updated, never ready again.
Because fetch mode installs config synchronously inside create, a client returned from create in fetch mode is typically already ready. To observe readiness explicitly — and to catch late subscribers — subscribe with Client#on; the SDK replays deferred one-shot events to subscribers that register after the event fired:
CONVERT_SDK.on("ready") do |_payload, _err|
# decisions are available from here on
endClient#on accepts a SystemEvents value or its matching string: ready (SystemEvents::READY), config.updated (CONFIG_UPDATED), bucketing (BUCKETING), and conversion (CONVERSION). It returns self, so it chains. See Event System.
These three keyword arguments are extracted before config validation — they are not config options.
-
sink:— an initial log sink (anything responding todebug/info/warn/error, e.g. the stdlibLogger). Passing it atcreatetime — rather than attaching one afterward — makes the full lifecycle observable, including the construction-time config fetch. Without this seam you could only attach a sink aftercreateand would miss every init-time line.require "logger" CONVERT_SDK = ConvertSdk.create( sdk_key: ENV.fetch("CONVERT_SDK_KEY"), log_level: ConvertSdk::LogLevel::TRACE, sink: Logger.new($stdout) )
-
store:— an optional data store for sticky bucketing and goal deduplication. Defaults to an in-processMemoryStore. Pass aConvertSdk::Stores::RedisStore(or any object that duck-typesget/set) for cross-process state. See Configuration Options and Persistent DataStore. -
clock:— an optional monotonic time source (#call→ seconds) for the config-cache TTL math. Defaults to the SDK's monotonic clock. Injectable so tests control staleness without real waits.
create starts no background threads (NFR4 lazy start). The background config-refresh timer is wired at construction but only started on the first create_context call. This is core to the SDK's zero-config fork safety — a client built in a preloading master carries no thread state across a fork. See Fork Safety & Runtime Recipes.
A Context binds one visitor to the client. create_context returns a new, independent context — call it once per request/job:
# Visitor id only.
context = CONVERT_SDK.create_context("visitor-123")
# Visitor id + initial attributes (symbol OR string keys both work).
context = CONVERT_SDK.create_context("visitor-123", { country: "US", plan: "premium" })A blank or nil visitor id logs an error and returns nil (never an ArgumentError — per-request validation respects the never-crash contract). Attributes are deep-stringified at the boundary, so symbol-keyed Ruby hashes and string-keyed Rails params behave identically. See Visitor Context.
- Configuration Options — every config option and its default
- Return Types & Sentinels — what the decision methods return
- Code Examples — end-to-end snippets
Copyrights © 2026 All Rights Reserved by Convert Insights, Inc.
Getting Started
Ruby SDK
- Quickstart
- Installation
- Initialization
- Configuration
- Return Types & Sentinels
- Code Examples
- Fork Safety & Runtime Recipes
- Tracking Control
Core Concepts
- Experiences & Variations
- Feature Flags
- Bucketing Algorithm
- Rule Evaluation
- Segments
- Data Management
- Event System
- API Communication
How-To Guides
- Running Experiences
- Running Features
- Tracking Conversions
- Visitor Context
- Persistent DataStore
- Troubleshooting
Contributing