View the full documentation on GitHub.


pip install growthbook (recommended) or copy into your project

Quick Usage

import requests
from growthbook import GrowthBook

# We recommend using a db or cache layer in production
apiResp = requests.get("")
features = apiResp.json()["features"]

# User attributes for targeting and experimentation
attributes = {
  "id": "123",
  "customUserAttribute": "foo"

def on_experiment_viewed(experiment, result):
  # Use whatever event tracking system you want
  analytics.track(attributes["id"], "Experiment Viewed", {
    'experimentId': experiment.key,
    'variationId': result.variationId

# Create a GrowthBook instance
gb = GrowthBook(
  attributes = attributes,
  features = features,
  trackingCallback = on_experiment_viewed

# Simple on/off feature gating
if gb.isOn("my-feature"):
  print("My feature is on!")

# Get the value of a feature with a fallback
color = gb.getFeatureValue("button-color-feature", "blue")

GrowthBook class

The GrowthBook constructor has the following parameters:

  • enabled (bool) - Flag to globally disable all experiments. Default true.
  • attributes (dict) - Dictionary of user attributes that are used for targeting and to assign variations
  • url (str) - The URL of the current request (if applicable)
  • features (dict) - Feature definitions from the GrowthBook API
  • forcedVariations (dict) - Dictionary of forced experiment variations (used for QA)
  • qaMode (boolean) - If true, random assignment is disabled and only explicitly forced variations are used.
  • trackingCallback (callable) - A function that takes experiment and result as arguments.

There are also getter and setter methods for features and attributes if you need to update them later in the request:



Defines all of the available features plus rules for how to assign values to users. Features are usually fetched from the GrowthBook API and persisted in cache or a database in production.

Feature definitions are defined in a JSON format. You can fetch them directly from the GrowthBook API:

import requests

apiResp = requests.get("")
features = apiResp.json()["features"]

Or, you can use a copy stored in your database or cache server instead:

import json

json_string = '{"feature-1":{...},"feature-2":{...},...}'
features = json.loads(json_string)

We recommend using the db/cache approach for production.


You can specify attributes about the current user and request. These are used for two things:

  1. Feature targeting (e.g. paid users get one value, free users get another)
  2. Assigning persistent variations in A/B tests (e.g. user id "123" always gets variation B)

Attributes can be any JSON data type - boolean, integer, float, string, list, or dict.

attributes = {
  'id': "123",
  'loggedIn': True,
  'age': 21.5,
  'tags': ["tag1", "tag2"],
  'account': {
    'age': 90

Tracking Experiments

Any time an experiment is run to determine the value of a feature, you want to track that event in your analytics system.

You can use the trackingCallback option to do this:

from growthbook import GrowthBook, Experiment, Result

def on_experiment_viewed(experiment: Experiment, result: Result):
  # Use whatever event tracking system you want
  analytics.track(attributes["id"], "Experiment Viewed", {
    'experimentId': experiment.key,
    'variationId': result.variationId

gb = GrowthBook(
  trackingCallback = on_experiment_viewed

Using Features

There are 3 main methods for interacting with features.

  • gb.isOn("feature-key") returns true if the feature is on
  • gb.isOff("feature-key") returns false if the feature is on
  • gb.getFeatureValue("feature-key", "default") returns the value of the feature with a fallback

In addition, you can use gb.evalFeature("feature-key") to get back a FeatureResult object with the following properties:

  • value - The JSON-decoded value of the feature (or null if not defined)
  • on and off - The JSON-decoded value cast to booleans
  • source - Why the value was assigned to the user. One of unknownFeature, defaultValue, force, or experiment
  • experiment - Information about the experiment (if any) which was used to assign the value to the user
  • experimentResult - The result of the experiment (if any) which was used to assign the value to the user

Inline Experiments

Instead of declaring all features up-front and referencing them by ids in your code, you can also just run an experiment directly. This is done with the gb->run method:

from growthbook import Experiment

exp = Experiment(
  key = "my-experiment",
  variations = ["red", "blue", "green"]

# Either "red", "blue", or "green"

As you can see, there are 2 required parameters for experiments, a string key, and an array of variations. Variations can be any data type, not just strings.

There are a number of additional settings to control the experiment behavior:

  • key (str) - The globally unique tracking key for the experiment
  • variations (any[]) - The different variations to choose between
  • weights (float[]) - How to weight traffic between variations. Must add to 1.
  • coverage (float) - What percent of users should be included in the experiment (between 0 and 1, inclusive)
  • condition (dict) - Targeting conditions
  • force (int) - All users included in the experiment will be forced into the specified variation index
  • hashAttribute (string) - What user attribute should be used to assign variations (defaults to "id")
  • namespace (tuple[str,float,float]) - Used to run mutually exclusive experiments.

Here's an example that uses all of them:

exp = Experiment(
  # Variations can be a list of any data type
  variations=[0, 1],
  # Run a 40/60 experiment instead of the default even split (50/50)
  weights=[0.4, 0.6],
  # Only include 20% of users in the experiment
  # Targeting condition using a MongoDB-like syntax
    'country': 'US',
    'browser': {
      '$in': ['chrome', 'firefox']
  # Use an alternate attribute for assigning variations (default is 'id')
  # Includes the first 50% of users in the "pricing" namespace
  # Another experiment with a non-overlapping range will be mutually exclusive (e.g. [0.5, 1])
  namespace=("pricing", 0, 0.5),

Inline Experiment Return Value

A call to run returns a Result object with a few useful properties:

result =

# If user is part of the experiment
print(result.inExperiment) # True or False

# The index of the assigned variation
print(result.variationId) # e.g. 0 or 1

# The value of the assigned variation
print(result.value) # e.g. "A" or "B"

# The user attribute used to assign a variation
print(result.hashAttribute) # "id"

# The value of that attribute
print(result.hashValue) # e.g. "123"

The inExperiment flag is only set to True if the user was randomly assigned a variation. If the user failed any targeting rules or was forced into a specific variation, this flag will be false.

Example Experiments

3-way experiment with uneven variation weights:
  key = "3-way-uneven",
  variations = ["A","B","C"],
  weights = [0.5, 0.25, 0.25]

Slow rollout (10% of users who match the targeting condition):

# User is marked as being in "qa" and "beta"
gb = GrowthBook(
  attributes = {
    "id": "123",
    "beta": True,
    "qa": True,
  key = "slow-rollout",
  variations = ["A", "B"],
  coverage = 0.1,
  condition = {
    'beta': True

Complex variations

result =
  key = "complex-variations",
  variations = [
    ("blue", "large"),
    ("green", "small")

# Either "blue,large" OR "green,small"
print(result.value[0] + "," + result.value[1])

Assign variations based on something other than user id

gb = GrowthBook(
  attributes = {
    "id": "123",
    "company": "growthbook"

# Users in the same company will always get the same variation
  key = "by-company-id",
  variations = ["A", "B"],
  hashAttribute = "company"


For Django (and other web frameworks), we recommend adding a simple middleware where you instantiate the GrowthBook object

from growthbook import GrowthBook

def growthbook_middleware(get_response):
    def middleware(request): = GrowthBook(
          # ...
        response = get_response(request) # Cleanup

        return response
    return middleware

Then, you can easily evaluate a feature (or run an inline experiment) in any of your views:

def index(request):
    featureEnabled ="my-feature")
    # ...