Configuration
Configure one client at process startup. Core Toggly::Config and Toggly::Rails::Configuration expose different option sets; merge the relevant settings into one startup path.
Core Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
app_key | String | - | Your Toggly app key (required unless offline) |
environment | String | "Production" | Environment name |
base_url | String | "https://definitions.toggly.io/" | Definitions API base URL |
definitions_url | String | nil | Base prefix override; endpoint path is appended |
refresh_interval | Integer | 300 | Refresh interval in seconds |
http_timeout | Integer | 10 | HTTP request timeout in seconds |
enable_undefined_in_dev | Boolean | false | Enable unknown features in development |
disable_background_refresh | Boolean | false | Disable polling and WebSocket startup; initial fetch still runs |
enable_live_updates | Boolean | true | WebSocket live updates (needs websocket-client-simple) |
use_signed_definitions | Boolean | false | Fetch from /definitions-signed/... |
allowed_key_ids | Array<String> | [] | Accepted but unused; no local signature verification |
defaults | Hash | {} | Default feature values for offline mode |
snapshot_provider | Object | nil | Persistence provider for caching |
logger | Logger | nil | Logger instance for debugging |
disable_entity_context_registration | Boolean | false | Skip startup schema upload; local entity mapping still works |
app_version / instance_name | String | nil | Application/instance metadata |
Client Configuration
Basic Configuration
client = Toggly::Client.new(
app_key: 'your-app-key',
environment: 'Production'
)
Full Configuration
require 'logger'
client = Toggly::Client.new(
app_key: ENV['TOGGLY_APP_KEY'],
environment: 'Production',
base_url: 'https://definitions.toggly.io/',
refresh_interval: 60,
http_timeout: 5,
enable_live_updates: true,
use_signed_definitions: true,
enable_undefined_in_dev: false,
defaults: {
'critical-feature' => true,
'experimental-feature' => false
},
logger: Logger.new($stdout)
)
Using Config Object
config = Toggly::Config.new(
app_key: 'your-app-key',
environment: 'Production',
refresh_interval: 120
)
client = Toggly::Client.new(config)
Signed definitions
See Signed definitions for the signed endpoint and Rails options.
Feature Variants
The Ruby SDK assigns variants locally from the definitions catalog
(variants + allocation). There is no enable_variants toggle and no
evaluated-variants-signed rail. Requires Ruby gem 1.1+ for
Config#identity / set_identity.
Prefer ambient identity: config, set_identity, or Rails feature_variant
(uses toggly_context). Per-call context: is an override.
require 'toggly'
client = Toggly::Client.new(
app_key: ENV['TOGGLY_APP_KEY'],
environment: 'Production',
identity: 'user-123' # optional default targeting userId
)
client.set_identity('user-123') # optional runtime update
client.enabled?('checkout-flow') # Local filter evaluation
variant = client.get_variant('checkout-flow')
if variant
puts variant.name # e.g. "treatment"
puts variant.configuration_value # Feature-specific payload, or nil
end
client.get_variant_value('checkout-flow')
# Override only when needed (e.g. impersonation):
client.get_variant(
'checkout-flow',
context: Toggly::Context.new(identity: 'other-user', groups: ['beta'])
)
client.close
In Rails, after the controller concern caches toggly_context:
variant = feature_variant(:checkout_flow)
value = feature_variant_value(:checkout_flow)
get_variant / feature_variant return nil when the feature key is
unknown, has no catalog variants, or no allocation match. They do not raise
for missing keys.
Do not confuse this with the variant: telemetry label. record_usage /
record_view accept a variant: keyword that is a free-form usage tag
(defaults to "enabled"/"disabled") — it does not assign a feature variant.
Live updates (WebSockets)
See Live updates. Shared protocol: WebSocket sync. Reliability notes: Server-side reliability.
Rails Configuration
Basic Setup
Toggly::Rails.configure do |config|
config.app_key = Rails.application.credentials.dig(:toggly, :app_key)
config.environment = Rails.env.production? ? 'Production' : 'Staging'
config.defaults = { 'ExpressCheckout' => false, 'new_dashboard' => false }
end
Rails-Specific Options
| Option | Type | Default | Description |
|---|---|---|---|
use_signed_definitions | Boolean | false | Fetch signed definitions endpoint |
allowed_key_ids | Array<String> | [] | Accepted but unused |
request_context_enabled | Boolean | true | Enable automatic request context |
identity_method | Symbol | :id | Method to call on current_user for identity |
groups_method | Symbol | nil | Method to call on current_user for groups |
context_builder | Proc | nil | Custom context builder |
use_rails_cache | Boolean | false | Use Rails.cache for snapshots |
cache_key_prefix | String | "toggly" | Cache key prefix |
Full Rails Configuration
Toggly::Rails.configure do |config|
# Core settings
config.app_key = Rails.application.credentials.dig(:toggly, :app_key)
config.environment = Rails.env.production? ? 'Production' : 'Staging'
config.refresh_interval = 60
config.use_signed_definitions = true
# User context
config.identity_method = :id
config.groups_method = :role_names
# Custom traits
config.add_trait(:plan) { |request, user| user&.subscription&.plan }
# Caching
config.use_rails_cache = true
config.cache_key_prefix = "shop:#{config.environment}:toggly"
# Development settings
config.enable_undefined_in_dev = Rails.env.development?
config.disable_background_refresh = Rails.env.test?
# Defaults for offline resilience
config.defaults = {
'critical-feature' => true
}
end
Custom Context Builder
Use the complete request builder inside the same initializer. Default Rails mapping produces identity, groups, traits and entity; it does not populate claims or structured request. A country trait does not feed the Country filter.
The Rails adapter forwards app_key, environment, base_url, definitions_url, refresh_interval, http_timeout, enable_undefined_in_dev, disable_background_refresh, app_version, instance_name, defaults, snapshot_provider, use_signed_definitions and allowed_key_ids. It supplies Rails.logger automatically. It has no logger, telemetry, enable_live_updates or disable_entity_context_registration setters. Use the single-client core-options recipe for those settings.
Environment Variables
You can use environment variables for sensitive values:
Toggly::Rails.configure do |config|
config.app_key = ENV.fetch('TOGGLY_APP_KEY')
config.environment = ENV.fetch('TOGGLY_ENVIRONMENT', 'Production')
config.base_url = ENV.fetch('TOGGLY_BASE_URL', 'https://definitions.toggly.io/')
end
Self-Hosted Toggly
Set these on your startup configuration. Both URL options are base prefixes, not complete JSON URLs: the SDK appends definitions/{appKey}/{environment} (or definitions-signed/...).
For self-hosted installations:
config.base_url = 'https://toggly.yourcompany.com/'
# Or use a CDN for definitions
config.definitions_url = 'https://cdn.yourcompany.com/toggly/'
Logging
The Rails adapter uses Rails.logger. For a core client, set a logger before construction:
require 'toggly'
require 'logger'
config = Toggly::Config.new(defaults: { 'ExpressCheckout' => false })
config.logger = Logger.new($stdout)
client = Toggly::Client.new(config)
client.close
Usage and metrics
| Core option | Default | Purpose |
|---|---|---|
enable_usage_tracking / enable_metrics | See below | Enable usage or metric batching |
metrics_base_url | https://app.toggly.io/ | Default telemetry service |
usage_flush_interval / metrics_flush_interval | 60.0 seconds | Batch flush intervals |
usage_client / metrics_client | nil | Optional transports implementing send_stats / send_metrics |
When app_key is passed to Config.new or Client.new, telemetry defaults on unless TOGGLY_DISABLE_TELEMETRY=1. Block configuration (Toggly.configure) and the Rails adapter first construct an empty core Config: assigning a key later does not recalculate these defaults. Set the two enable options explicitly on the core Config when using that path. Telemetry requires an app key; TOGGLY_DISABLE_TELEMETRY=1 disables it regardless of these options. Install grpc and google-protobuf for the default senders.
Inside request handling, after constructing that request's context and using the configured shared client:
if client.enabled?('ExpressCheckout', context: context)
# Call at the actual display and interaction points in your app.
client.record_view('ExpressCheckout', identity: context.identity)
client.record_usage('ExpressCheckout', identity: context.identity)
client.measure('checkout_total', 149.95, feature: 'ExpressCheckout', variant: 'enabled')
client.increment_counter('orders', 1, feature: 'ExpressCheckout', variant: 'enabled')
client.observe('checkout_ms', 85, feature: 'ExpressCheckout', variant: 'enabled')
end
# Normally batched automatically; useful at a controlled flush boundary.
client.flush_telemetry
enabled? records checks automatically. A view means displayed UI; usage means an interaction, so do not record both merely because you checked a flag. measure sums values in the flush window, increment_counter adds counts, and observe records individual observations. variant is a telemetry label, not a variant assignment API. Close the client at shutdown to stop its workers and flush pending telemetry.