Ruby
View the full source code at https://github.com/growthbook/growthbook-ruby.
Requirements
The Ruby SDK requires Ruby version 2.5.0 or higher.
Installation
Install the gem:
gem install growthbook
Quick start
require 'growthbook'
# Fetch features from a GrowthBook instance
# You should cache this in Redis or similar in production
features_repository = Growthbook::FeatureRepository.new(
  endpoint: 'https://cdn.growthbook.io/api/features/MY_API_KEY',
  decryption_key: nil
)
features = features_repository.fetch
# Create a context for the current user/request
gb = Growthbook::Context.new(
  features: features,
  # User attributes for targeting / variation assignment
  attributes: {
    id: '123',
    country: 'US'
  }
)
# Use a boolean feature flag
if gb.on? :my_feature_key
  puts 'My feature is on!'
end
# Get the value of a multivariate feature with a fallback
btn_color = gb.feature_value(:signup_btn_color, 'pink')
Tracking
Track experiment impressions
When a feature's value is determined by an experiment (A/B test), you typically want to track that assignment event for later analysis.
There are two ways to do this. First is by accessing all impressions at the end of a request:
gb.impressions.each do |key, result|
  puts "Assigned variation #{result.variation_id} in experiment #{key}"
end
Second is by using a listener to get alerted in realtime as users are put into experiments:
class MyImpressionListener
  def on_experiment_viewed(experiment, result)
    puts "Assigned variation #{result.variation_id} in experiment #{experiment.key}"
  end
end
gb.listener = MyImpressionListener.new
Track feature usage
GrowthBook can fire a callback whenever a feature is evaluated for a user. This can be useful to update 3rd party tools like NewRelic or DataDog.
Provide a receiver that can receive def on_feature_usage: (String _feature_key, FeatureResult _result) -> void. There's a convenience class FeatureUsageCallback with a method you can override but you can provide your own.
class MyFeatureUsageCallback < FeatureUsageCallback
  def on_feature_usage(feature_key, feature_result)
    puts "on_feature_usage_called with key: #{feature_key} and result #{feature_result}"
  end
end
on_feature_usage = MyFeatureUsageCallback.new
# you can pass it into the context
gb = Growthbook::Context.new({
  attributes: {
    id: 'user-abc123'
  },
  features: feature_repository.fetch || {},
  on_feature_usage: on_feature_usage,
})
# or assign it afterwards
gb.on_feature_usage = on_feature_usage
Using with Rails
You can use the provided Growthbook::FeatureRepository class along with the Rails cache to fetch features periodically within your usage limits. Here is a controller concern you can use:
require 'growthbook'
module GrowthbookSdk
  def growthbook
    @growthbook ||= Growthbook::Context.new(
      features: growthbook_features_json,
      attributes: {},
    )
  end
  # use this as a before_action on your controller
  def init_feature_flags
    return if current_user.nil?
    # TODO: Change this to get your user attributes as a hash in a way that works for your app
    growthbook.attributes = current_user.as_json
  end
  private
  def growthbook_features_json
    Rails.cache.fetch("growthbook_features", expires_in: 1.hour) do
      puts "🌎 Fetching GrowthBook features from the network"
      repo = Growthbook::FeatureRepository.new(
        endpoint: 'https://cdn.growthbook.io/api/features/java_NsrWldWd5bxQJZftGsWKl7R2yD2LtAK8C8EUYh9L8',
        decryption_key: nil,
      )
      repo.fetch || {}
    end
  end
end
And in your ApplicationController:
class ApplicationController < ActionController::API
  include Authentication # your own auth strategy
  include GrowthbookSdk # the controller concern code above
  before_action :authenticate!
  before_action :init_feature_flags # call this once you have a user from which to get attributes
end
The above code exposes the following methods on your application controller:
growthbook: an instance of the GrowthBook SDK for the requestinit_feature_flags: a method intended to be used as abefore_actionhook, e.g.before_action :init_feature_flags
It assumes you have a method current_user that returns the currently-authenticated user, and that it responds to as_json to return a hash of the targeting attributes.
How this works:
- With each request, the 
init_feature_flagsmethod is called. This creates a new instance ofGrowthbook::Context - When creating the context for the first time, features are fetched and cached in the Rails cache. Subsequent calls use the cached version until the cache expires.
 - Developers can call methods on 
growthbookin their controllers to use the GrowthBook SDK, e.g.growthbook.on?(:dark_mode). 
You can see the Rails example linked in the Code examples below.
Dev and QA helpers
For dev/QA it's often useful to force specific feature values.
# These take precedence over everything else when determining a feature's value
gb.forced_features = {
  my_feature: true,
  other_feature: "new value"
}
# Will always be true
gb.is_on?(:my_feature)
# Will always be "new value"
gb.feature_value(:other_feature)
For more predictability during QA, you can also globally disable all random assignment in experiments from running:
gb.enabled = false
Inline experiments
It's also possible to directly run an experiment directly in code without going through a feature flag.
# Simple 50/50 experiment
result = gb.run(Growthbook::InlineExperiment.new(
  key: "my-experiment-key",
  variations: ["red", "green"]
))
# Whether or not the user was included in the experiment (either true or false)
puts(result.in_experiment ? 'included' : 'excluded')
# The value of the assigned variation (either "red" or "green")
puts(result.value)
# The variation index (either 0 or 1)
puts(result.variation_id)
There are lots of additional options when running inline experiments:
gb.run(Growthbook::InlineExperiment.new(
  key: "my-experiment-key",
  variations: ["red", "green"],
  # Filter by context attributes
  condition: {
    country: {
      "$in": ["US", "CA"]
    }
  },
  # Adjust variation weights from the default 50/50 split
  weights: [0.8, 0.2],
  # Run for a subset of traffic (0 to 1, default = 1)
  coverage: 0.5,
  # Use a different context attribute for assigning a variation (default = "id")
  hash_attribute: "device_id",
  # Use a namespace to run mutually exclusive experiments
  namespace: ["pricing-page", 0, 0.25]
))
Working with Encrypted features
You can learn more about SDK Connection Endpoint Encryption.
Create a GrowthBook::Context with an encrypted payload and a decryption key:
# TODO: Replace these values with your own:
Growthbook::Context.new(
  encrypted_features: 'm5ylFM6ndyOJA2OPadubkw==.Uu7ViqgKEt/dWvCyhI46q088PkAEJbnXKf3KPZjf9IEQQ+A8fojNoxw4wIbPX3aj',
  decryption_key: 'Zvwv/+uhpFDznZ6SX28Yjg==',
  attributes: {
    id: '456',
    country: 'CA'
  }
)
When fetching features from the GrowthBook SDK endpoint, the encrypted features are available on a property encryptedFeatures instead of plain text on the property features. Here's an example with networking:
uri = URI('https://cdn.growthbook.io/api/features/MY_API_KEY')
res = Net::HTTP.get_response(uri)
encrypted_features = res.is_a?(Net::HTTPSuccess) ? JSON.parse(res.body)['encryptedFeatures'] : nil
Growthbook::Context.new(
  encrypted_features: encrypted_features,
  decryption_key: '<key-for-decrypting>',
  attributes: {
    id: '456',
    country: 'CA'
  }
)