Ruby SDK
Server-side ingest for Ruby. Matches the Node and Python shapes; zero runtime dependencies (uses Net::HTTP from stdlib).
Supports Ruby 3.1+.
Install
gem install getfluxly
Or in your Gemfile:
gem "getfluxly"
Init
require "getfluxly"
client = GetFluxly::Client.new(token: "gflux_secret_yourtoken")
Pass token: your server-side secret key. Never expose this in browser-facing code.
track()
track records a named event against an identified or anonymous user.
client.track("subscription_started",
external_id: "user_42",
properties: { plan: "pro", mrr: 49 })
| Argument | Required | Notes |
|---|---|---|
| event name | yes | String, e.g. "page_viewed" |
external_id: | yes (or anonymous_id:) | Your stable user identifier |
anonymous_id: | yes (or external_id:) | Browser-generated ID when no login exists |
properties: | no | Arbitrary Hash |
timestamp: | no | ISO 8601 string; defaults to server now |
Events are queued in memory and flushed as a batch. Call client.flush before your process exits (see Flushing below).
identify()
Experimental:
identify()currently sends the event name$identifybut the server expectsidentify, so end-to-end identity stitching does not yet work. Usetrack()with your own identify event as a workaround until the fix ships.
# workaround until identify() is fixed
client.track("identify",
external_id: "user_42",
properties: { email: "user@example.com", plan: "pro" })
alias()
Links an anonymous ID to a known external_id, enabling pre-login event attribution.
client.alias(user_id: "user_42",
anonymous_id: "anon_a8f3c2")
Flushing
Experimental: A background flush thread is not yet implemented. Manual flush is required: call
client.flushbefore your process exits, or register anat_exithook. Theflush_intervaloption is accepted but has no effect until the background flusher ships.
Call flush explicitly:
client.flush # drains the in-memory queue synchronously
client.shutdown # flush + teardown; also registered via at_exit
Or register the hook yourself for long-running processes:
at_exit { client.flush }
Each flushed batch carries a unique X-Idempotency-Key. Retries cover 408, 425, 429, and 5xx responses with exponential backoff and +/- 25% jitter. Retry-After is honored.
Configuration
| Option | Default | Notes |
|---|---|---|
flush_at | 20 | Events queued before a forced flush |
flush_interval | 5.0 | Reserved; background flusher not yet active |
max_retries | 2 | Per failed batch |
timeout | 5.0 | Per HTTP request, seconds |
max_queue_size | 1000 | Hard cap; raises queue_overflow when exceeded |
client = GetFluxly::Client.new(
token: ENV["GFLUX_SERVER_TOKEN"],
flush_at: 50,
max_retries: 3,
timeout: 10.0
)
Rails integration
Auto-loaded but opt-in via explicit require:
# config/initializers/getfluxly.rb
require "getfluxly/rails"
GetFluxly::Rails.configure do |c|
c.token = ENV["GFLUX_SERVER_TOKEN"]
end
Use the shared client anywhere in your app:
GetFluxly::Rails.client.track("invoice_paid", external_id: "user_42")
Rack middleware
GetFluxly::Rails::Middleware reads the gflux_anon cookie from the incoming Cookie header and attaches the value to request.env["gflux.anonymous_id"]. Controllers can then read it to resume an existing browser session for server-side tracking:
anonymous_id = request.env["gflux.anonymous_id"]
client.track("page_viewed",
anonymous_id: anonymous_id,
properties: { path: request.path })
Note: the anonymous ID is available via request.env["gflux.anonymous_id"], not request.gflux_anonymous_id.
Errors
begin
client.track("invoice_paid", external_id: "user_42")
rescue GetFluxly::Error => e
case e.code
when "queue_overflow"
# back-pressure; the queue is full, event was dropped
when "rate_limited"
# SDK already retried max_retries times
when "auth_failed"
# bad or missing token
end
end
See the full error code table for all codes and HTTP mappings.