trevosdk runs experiments and records conversions from your Ruby backend. Zero
dependencies, Ruby 3.2+, and assignment is byte-identical to every other Trevo SDK — the
same user gets the same variant in the browser and on the backend.
gem "trevosdk".
Create a client
You need a server key:tsk_secret_…, from Settings → SDK keys with platform Server.
It is shown once. Never put it in client code.
Trevosdk.init sets up a process-wide singleton reachable as Trevosdk.client — the common
one-client-per-app setup. Config refresh (60-second poll) and event delivery run on
background threads; events flush at process exit, or deterministically via flush / close.
For multiple clients, use Trevosdk::Client.new(secret_key, **options) directly.
Assignment needs config, so wait for the first fetch once at boot:
Read a variant
get_variant reads an immutable in-memory config snapshot — no network call, nothing that
blocks — so it is safe anywhere: Rails controllers, Sidekiq jobs, rake tasks. The singleton
is safe across Puma threads.
Each call records an exposure (deduplicated per identity and variant within a 10-minute
window). To read without recording one, pass track_exposure: false.
Identity is passed per call
A server holds no ambient user state, so every call takes the identity explicitly:user_id: wins for bucketing when present; an
event carrying both is what links a user’s anonymous browsing to their conversions. With no
identity at all, get_variant returns "control" and records nothing.
Bucket with the identity the browser is using at that moment — the user id when
identified, otherwise the trevo_id cookie. Anything else assigns the same person different
variants on the client and the server.
Track conversions
insert_id: derived from the thing that happened, and Trevo
records the event once no matter how many deliveries arrive:
Linking identities without a cookie
Webhooks and background jobs have no cookie to read. State the link directly:anonymous_id belongs to one user — pointing it at a
different user raises and changes nothing.
Runtime notes
- Rails — initialize in
config/initializers/trevosdk.rband callTrevosdk.clientfrom anywhere. - Forking servers (Puma workers, Sidekiq, Spring) — a client built before the fork keeps
working in the child. Background threads do not survive a fork, so the SDK detects the new
pid and restarts them on the first
get_variantortrack; an expliciton_worker_bootre-init is optional. - Short-lived scripts and jobs — call
Trevosdk.client.flushbefore exiting so the batch is delivered inside the run (anat_exitflush also runs).
Local development
Pin variants without touching Trevo:force_variants: {"checkout-cta" => "treatment"}. Forced reads never record
an exposure, so local testing never pollutes results. The SDK’s own spec suite deletes the
variable around every example, so exporting it cannot turn a conformance run red.
Experiment keys may be Strings or Symbols — get_variant(:"checkout-cta", ...) and
get_variant("checkout-cta", ...) resolve the same experiment.
Errors
Everything raised or passed toon_error: is typed, so you can branch on what happened:
Trevosdk::ConfigError, Trevosdk::DeliveryError (carries #status),
Trevosdk::SerializationError, Trevosdk::QueueFullError and
Trevosdk::EventRejectedError, all under Trevosdk::Error (itself a RuntimeError).