getfluxly (Ruby)

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 })
ArgumentRequiredNotes
event nameyesString, 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:noArbitrary Hash
timestamp:noISO 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 $identify but the server expects identify, so end-to-end identity stitching does not yet work. Use track() 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.flush before your process exits, or register an at_exit hook. The flush_interval option 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

OptionDefaultNotes
flush_at20Events queued before a forced flush
flush_interval5.0Reserved; background flusher not yet active
max_retries2Per failed batch
timeout5.0Per HTTP request, seconds
max_queue_size1000Hard 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.