PHPackages                             loipv/growthbook-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. loipv/growthbook-php

ActiveLibrary[Testing &amp; Quality](/categories/testing)

loipv/growthbook-php
====================

PHP SDK for GrowthBook, the feature flagging and A/B testing platform

049PHP

Since Dec 13Pushed 2y agoCompare

[ Source](https://github.com/loipv/growthbook-php)[ Packagist](https://packagist.org/packages/loipv/growthbook-php)[ RSS](/packages/loipv-growthbook-php/feed)WikiDiscussions master Synced yesterday

READMEChangelogDependenciesVersions (1)Used By (0)

[![](https://camo.githubusercontent.com/71e15d924ee8ed6235c51c03051476ba53aa19bb2246f0c0ad025754e68584bd/68747470733a2f2f63646e2e67726f777468626f6f6b2e696f2f67726f777468626f6f6b2d6c6f676f4032782e706e67)](https://camo.githubusercontent.com/71e15d924ee8ed6235c51c03051476ba53aa19bb2246f0c0ad025754e68584bd/68747470733a2f2f63646e2e67726f777468626f6f6b2e696f2f67726f777468626f6f6b2d6c6f676f4032782e706e67)

GrowthBook - PHP
================

[](#growthbook---php)

Powerful Feature flagging and A/B testing for PHP.

[![Build Status](https://github.com/growthbook/growthbook-php/workflows/Build/badge.svg)](https://github.com/growthbook/growthbook-php/workflows/Build/badge.svg)

- **No external dependencies** (besides PSR interfaces)
- **Extremely fast**, all evaluation happens locally
- **PHP 7.1+** with 100% test coverage and phpstan on the highest level
- **Advanced user and page targeting**
- **Use your existing event tracking** (GA, Segment, Mixpanel, custom)
- **Adjust variation weights and targeting** without deploying new code

Installation
------------

[](#installation)

GrowthBook is available on Composer:

`composer require growthbook/growthbook`

Quick Usage
-----------

[](#quick-usage)

```
// Create a GrowthBook instance
$growthbook = Growthbook\Growthbook::create()
  ->withAttributes([
    // Targeting attributes
    'id' => $userId,
    'someCustomAttribute' => true
  ]);

// Load feature flags from the GrowthBook API
// Make sure to use caching in production! (see 'Loading Features' below)
$growthbook->loadFeatures("sdk-abc123", "https://cdn.growthbook.io");

// Feature gating
if ($growthbook->isOn("my-feature")) {
  echo "It's on!";
} else {
  echo "It's off :(";
}

// Remote configuration with fallback
$color = $growthbook->getValue("button-color", "blue");
echo "Click Me!";
```

Some of the feature flags you evaluate might be running an A/B test behind the scenes which you'll want to track in your analytics system.

At the end of the request, you can loop through all experiments and track them however you want to:

```
$impressions = $growthbook->getViewedExperiments();
foreach($impressions as $impression) {
  // Whatever you use for event tracking
  Segment::track([
    "userId" => $userId,
    "event" => "Experiment Viewed",
    "properties" => [
      "experimentId" => $impression->experiment->key,
      "variationId" => $impression->result->key
    ]
  ]);
}
```

### Loading Features

[](#loading-features)

There are 2 ways to load features into the SDK. You can use `loadFeatures` with a Client Key and API Host. Or, you can manually fetch and cache feature flags and pass them in with the `withFeatures` method.

#### loadFeatures method

[](#loadfeatures-method)

The `loadFeatures` method can fetch features from the GrowthBook API for you.

By default, there is no caching enabled. You can enable it by passing any PSR16-compatible instance into the `withCache` method.

**Caching is required for production usage**

```
// Any psr-16 library will work
use Cache\Adapter\Apcu\ApcuCachePool;

$cache = new ApcuCachePool()

$growthbook = Growthbook\Growthbook::create()
  ->withCache($cache);

// You can optionally pass in a TTL (default 60s)
$growthbook = Growthbook\Growthbook::create()
  ->withCache($cache, 120); // Cache for 120s instead
```

To load features, we require a PSR-17 (HttpClient) and PSR-18 (RequestFactoryInterface) compatible library like Guzzle to be installed.

We will auto-discover most HTTP libraries without any configuration required, but if you prefer to specify it explicitly, you can use the `withHttpClient` method. Note - you'll need to specify both an `HttpClient` and a `RequestFactoryInterface` implementation.

The `loadFeatures` method takes 3 arguments:

- `$clientKey` (required) - Get this from your SDK Connection in GrowthBook.
- `$apiHost` (optional) - Defaults to `https://cdn.growthbook.io`. If self-hosting GrowthBook, set this to your API host.
- `$decryptionKey` (optional) - Only required if you've enabled encryption for your SDK Connection.

#### withFeatures method

[](#withfeatures-method)

If you prefer to have full control over the fetching/caching behavior, you can use the `withFeatures` method instead to pass an associative array of features into the SDK.

```
// From the GrowthBook API, a custom cache layer, or somewhere else
$featuresJSON = '{"my-feature":{"defaultValue":true}}';

// Decode into an associative array
$features = json_decode($featuresJSON, true);

// Pass into the Growthbook instance
$growthbook = Growthbook\Growthbook::create()
  ->withFeatures($features);
```

The Growthbook Class
--------------------

[](#the-growthbook-class)

The `Growthbook` class has a number of properties. These can be set using a Fluent interface or can be passed into a constructor using an associative array. Every property also has a getter method if needed. Here's an example:

```
// Using the fluent interface
$growthbook = Growthbook\Growthbook::create()
  ->withFeatures($features)
  ->withAttributes($attributes);

// Using the constructor
$growthbook = new Growthbook\Growthbook([
  'features' => $features,
  'attributes' => $attributes
]);

// Getter methods
print_r($growthbook->getFeatures());
print_r($growthbook->getAttributes());
```

Note: you can also use the fluent methods (e.g. `withFeatures`) at any point to update properties.

### Attributes

[](#attributes)

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, or array.

```
$attributes = [
  'id' => "123",
  'loggedIn' => true,
  'deviceId' => "abc123def456",
  'age' => 21,
  'tags' => ["tag1", "tag2"],
  'account' => [
    'age' => 90
  ]
];
```

If you want to update attributes later, please note that the `withAttributes` method completely overwrites the attributes object. You can use `array_merge` if you only want to update a subset of fields:

```
// Only update the url attribute
$growthbook->withAttributes(array_merge(
  $growthbook->getAttributes(),
  [
    'url' => '/checkout'
  ]
));
```

### Tracking Experiments

[](#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 either do this via a callback function:

```
$trackingCallback = function (
  Growthbook\InlineExperiment $experiment,
  Growthbook\ExperimentResult $result
) {
  // Segment.io example
  Segment::track([
    "userId" => $userId,
    "event" => "Experiment Viewed",
    "properties" => [
      "experimentId" => $experiment->key,
      "variationId" => $result->key
    ]
  ]);
};

// Fluent interface
$growthbook = Growthbook\Growthbook::create()
  ->withTrackingCallback($callback);

// Using the constructor
$growthbook = new Growthbook([
  'trackingCallback' => $trackingCallback
]);

// Getter method
$trackingCallback = $growthbook->getTrackingCallback();
```

Or track all events at the end of the request by looping through an array:

```
$impressions = $growthbook->getViewedExperiments();
foreach($impressions as $impression) {
  // Segment.io example
  Segment::track([
    "userId" => $userId,
    "event" => "Experiment Viewed",
    "properties" => [
      "experimentId" => $impression->experiment->key,
      "variationId" => $impression->result->key
    ]
  ]);
}
```

Or, you can pass the impressions onto your front-end and fire analytics events from there. To do this, simply add a block to your template (shown here in plain PHP, but similar idea for Twig, Blade, etc.).

```

  // tracking code goes here

```

Below are examples for a few popular front-end tracking libraries:

#### Google Analytics

[](#google-analytics)

```
ga('send', 'event', 'experiment',
  "",
  "",
  {
    // Custom dimension for easier analysis
    'dimension1': ""
  }
);
```

#### Segment

[](#segment)

```
analytics.track("Experiment Viewed", );
```

#### Mixpanel

[](#mixpanel)

```
mixpanel.track("Experiment Viewed", );
```

### Logging

[](#logging)

GrowthBook can output log messages to help you debug your feature flags and experiments.

We support any PSR-3 comaptible logger. We implement a fluent interface (`withLogger`) as well as the standard LoggerAware interface (`setLogger`).

```
// Fluent interface
$growthbook
  ->withLogger($logger)
  ->with...;

// Setter
$growthbook->setLogger($logger);
```

Using Features
--------------

[](#using-features)

There are 3 main methods for interacting with features.

- `$growthbook->isOn("feature-key")` returns true if the feature is on
- `$growthbook->isOff("feature-key")` returns false if the feature is on
- `$growthbook->getValue("feature-key", "default")` returns the value of the feature with a fallback

In addition, you can use `$growthbook->getFeature("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
------------------

[](#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 `$growthbook->runInlineExperiment` method:

```
$exp = Growthbook\InlineExperiment::create(
  "my-experiment",
  ["red", "blue", "green"]
);

// Either "red", "blue", or "green"
echo $growthbook->runInlineExperiment($exp)->value;
```

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. The methods are all chainable. Here's an example that shows all of the possible settings:

```
$exp = Growthbook\InlineExperiment::create("my-experiment", ["red","blue"])
  // Run a 40/60 experiment instead of the default even split (50/50)
  ->withWeights([0.4, 0.6])
  // Only include 20% of users in the experiment
  ->withCoverage(0.2)
  // Targeting conditions using a MongoDB-like syntax
  ->withCondition([
    'country' => 'US',
    'browser' => [
      '$in' => ['chrome', 'firefox']
    ]
  ])
  // Use an alternate attribute for assigning variations (default is 'id')
  ->withHashAttribute("sessionId")
  // Namespaces are used to run mutually exclusive experiments
  // Another experiment in the "pricing" namespace with a non-overlapping range
  //   will be mutually exclusive (e.g. [0.5, 1])
  ->withNamespace("pricing", 0, 0.5);
```

### Inline Experiment Return Value

[](#inline-experiment-return-value)

A call to `runInlineExperiment` returns an `ExperimentResult` object with a few useful properties:

```
$result = $growthbook->runInlineExperiment($exp);

// If user is part of the experiment
echo($result->inExperiment); // true or false

// The index of the assigned variation
echo($result->variationId); // e.g. 0 or 1

// The key used to identify this variation when tracking the event
echo($result->key); // e.g. "control"

// The value of the assigned variation
echo($result->value); // e.g. "A" or "B"

// If the variations was randomly assigned based on a hash
echo($result->hashUsed); // true or false

// The user attribute that was hashed
echo($result->hashAttribute); // "id"

// The value of that attribute
echo($result->hashValue); // e.g. "123"
```

The `inExperiment` flag will be false if the user was excluded from being part of the experiment for any reason (e.g. failed targeting conditions).

The `hashUsed` flag will only be true if the user was randomly assigned a variation. If the user was forced into a specific variation instead, this flag will be false.

###  Health Score

15

—

LowBetter than 3% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity8

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity20

Early-stage or recently created project

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/b579d7051e1f6673f8bddabbe142f8e32fe8f8edca88649ce39dcd79097b7493?d=identicon)[loipv](/maintainers/loipv)

---

Top Contributors

[![jdorn](https://avatars.githubusercontent.com/u/1087514?v=4)](https://github.com/jdorn "jdorn (11 commits)")[![nhedger](https://avatars.githubusercontent.com/u/649677?v=4)](https://github.com/nhedger "nhedger (6 commits)")[![Auz](https://avatars.githubusercontent.com/u/46107?v=4)](https://github.com/Auz "Auz (4 commits)")[![loipv](https://avatars.githubusercontent.com/u/16409034?v=4)](https://github.com/loipv "loipv (2 commits)")[![andrejguran](https://avatars.githubusercontent.com/u/1847466?v=4)](https://github.com/andrejguran "andrejguran (1 commits)")[![Defrothew](https://avatars.githubusercontent.com/u/1146337?v=4)](https://github.com/Defrothew "Defrothew (1 commits)")

### Embed Badge

![Health badge](/badges/loipv-growthbook-php/health.svg)

```
[![Health](https://phpackages.com/badges/loipv-growthbook-php/health.svg)](https://phpackages.com/packages/loipv-growthbook-php)
```

###  Alternatives

[dms/phpunit-arraysubset-asserts

This package provides ArraySubset and related asserts once deprecated in PHPUnit 8

14429.2M361](/packages/dms-phpunit-arraysubset-asserts)[gong023/assert_chain

enable you to use phpunit assert with method chain

1478.9k3](/packages/gong023-assert-chain)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
