Skip to main content
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.
Or in your Gemfile: 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:
Without this, requests in the first moments after a deploy fall back to control.

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:
Send both ids whenever you have them. 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

Payment providers replay webhooks, and a conversion counted twice inflates whichever variant that user was in. Pass a stable insert_id: derived from the thing that happened, and Trevo records the event once no matter how many deliveries arrive:
Webhooks and background jobs have no cookie to read. State the link directly:
Idempotent and safe to retry. An anonymous_id belongs to one user — pointing it at a different user raises and changes nothing.

Runtime notes

  • Rails — initialize in config/initializers/trevosdk.rb and call Trevosdk.client from 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_variant or track; an explicit on_worker_boot re-init is optional.
  • Short-lived scripts and jobs — call Trevosdk.client.flush before exiting so the batch is delivered inside the run (an at_exit flush also runs).

Local development

Pin variants without touching Trevo:
Or in code with 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 to on_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).

Options

API summary