On this page

PHP Server SDK

Statsig's Next-gen PHP Server SDK built in our [Server Core](/server-core) framework

Migrating from the legacy PHP SDK? Refer to our Migration Guide.

Set up the SDK

  1. Install the SDK

    Installation

    1. Install and Add as a Dependency

    Install the PHP Core SDK using Composer:

    shell
    composer require statsig/statsig-php-core
    

    2. PHP Configuration Requirements

    The PHP Core SDK uses the FFI extension to interface with the Rust core. Enable FFI in your PHP configuration by setting ffi.enable=true in your php.ini file.

    For more information about this setting, go to the PHP manual for ffi.enable.

    3. Add Scripts & Cron Job

    Add post-install and post-update scripts in composer.json:

    json
    // composer.json
    {
      "name": "awesome-php-project",
      ...
      "scripts": {
        ...
        "post-install-cmd": [
          "cd vendor/statsig/statsig-php-core && php post-install.php"
        ],
        "post-update-cmd": [
          "cd vendor/statsig/statsig-php-core && php post-install.php"
        ]
      }
    }
    
    Add a script to sync your Statsig configs and flush your events. For example files, go to Statsig's GitHub.

    Set up cron jobs to run these scripts periodically:

    shell
    */10 * * * * /usr/bin/php /var/www/example.com/bin/StatsigSyncConfig.php 1>> /dev/null 2>&1
    */1 * * * * /usr/bin/php /var/www/example.com/bin/StatsigFlushEvents.php 1>> /dev/null 2>&1
    

    Run the StatsigSyncConfig.php cron job at least once before proceeding.

  2. Initialize the SDK

    After installation, initialize the SDK using a Server Secret Key from the Statsig console.

    Keep Server Secret Keys private. If you expose one, you can disable and recreate it in the Statsig console.

    An optional options parameter accepts a StatsigOptions object to customize the SDK.

    Add your client secret key to the environment using a .env file or on the command line:

    shell
    export STATSIG_SECRET_KEY=secret-123456789
    
    php
    // At the top of your file
    use Statsig\Statsig;
    use Statsig\StatsigOptions;
    use Statsig\StatsigLocalFileEventLoggingAdapter;
    use Statsig\StatsigLocalFileSpecsAdapter;
    
    //In the case of slim framework, in container builder definitions:
    
    Statsig::class => function (ContainerInterface $c) {
        $sdk_key = getenv("STATSIG_SECRET_KEY");
    
        $options = new StatsigOptions(
            null,
            null,
            new StatsigLocalFileSpecsAdapter($sdk_key, "/tmp"),
            new StatsigLocalFileEventLoggingAdapter($sdk_key, "/tmp")
        );
    
        $statsig = new Statsig($sdk_key, $options);
        $statsig->initialize();
        return $statsig;
    },
    
    StatsigLocalFile Adapters rely on cron jobs and files. If you see errors around file access, ensure your cron job has run at least one time before using Statsig. See Add Scripts & Cron Job
    initialize performs a network request. After initialize completes, virtually all SDK operations are synchronous (refer to Evaluating Feature Gates in the Statsig SDK). The SDK fetches updates from Statsig in the background independently of API calls.

Working with the SDK

Checking a Feature Flag/Gate

After the SDK is initialized, you can fetch a Feature Gate. Feature Gates create logic branches in code that you can roll out to different users from the Statsig Console. Gates are always CLOSED or OFF (equivalent to return false;) by default.All APIs require you to specify the user (refer to Statsig user) associated with the request. For example:
php
use Statsig\Statsig;
use Statsig\StatsigUserBuilder;

$user = StatsigUserBuilder::withUserID('my_user')->build();
$passed = $statsig->checkGate($user, 'my_gate');

Reading a Dynamic Config

Feature Gates are useful for simple on/off switches with optional user targeting. To send a different set of values (strings, numbers, and similar types) to clients based on user attributes such as country, use Dynamic Configs. The API is similar to Feature Gates, but returns a full JSON object configurable on the server from which you can fetch typed parameters.
php
$user = StatsigUserBuilder::withUserID('my_user')->build();
$config = $statsig->getDynamicConfig($user, 'my_config');

Getting a Layer/Experiment

Use Layers/Experiments to run A/B/n experiments. Two APIs are available. Statsig recommends Layers because they make parameters reusable and support mutually exclusive experiments.
php
$user = StatsigUserBuilder::withUserID('my_user')->build();
$xp = $statsig->getExperiment($user, 'an_experiment');

Retrieving Feature Gate Metadata

In certain scenarios, you may need more information about a gate evaluation than just a boolean value. For additional metadata about the evaluation, use the Get Feature Gate API, which returns a FeatureGate object:

php
$gate = $statsig->getFeatureGate($user, "example_gate");

Parameter Stores

Use Parameter Stores when you want to define a parameter without deciding whether it should be a Feature Gate, Experiment, or Dynamic Config. Parameter Stores let you change the parameter type at any point in the Statsig console without a new deployment. Parameter Stores are optional, but parameterizing your application provides future flexibility and allows non-technical Statsig users to turn parameters into experiments.

Parameter stores are not yet available for this sdk. Need it now? Let us know in Slack.

Logging an Event

To track custom events, call the Log Event API. Specify the user, event name, and an optional value or metadata object:

php
$user = StatsigUserBuilder::withUserID('my_user')->build();
$statsig->logEvent($user, 'an_experiment');

Sending Events to Log Explorer

You can forward logs to Logs Explorer for convenient analysis using the Forward Log Line Event API. This lets you include custom metadata and event values with each log.

Sending events to Log Explorer is not yet available for this sdk. Need it now? Let us know in Slack.

Using shared instance

To create a single Statsig instance accessible globally throughout your codebase, use the shared instance functionality, which provides a singleton pattern:

php
use Statsig\Statsig;

// Initialize the shared instance
Statsig::initializeShared('your-server-secret-key', $options);

// Access the shared instance from anywhere in your code
$user = StatsigUserBuilder::withUserID('my_user')->build();
$gate = Statsig::shared()->checkGate($user, 'my_gate');

// Shutdown the shared instance when your application closes
Statsig::shared()->shutdown();

Statsig User

The StatsigUser object represents a user in Statsig. You must provide a userID or at least one of the customIDs to identify the user.

When calling APIs that require a user, pass as much information as possible to take advantage of advanced gate and config conditions (like country or OS/browser level checks) and to correctly measure the impact of experiments on metrics and events. As explained here, at least one identifier (userID or customID) is required to provide a consistent experience for a given user.

In addition to userID, the top-level fields on StatsigUser are: email, ip, userAgent, country, locale, and appVersion. You can also pass any key-value pairs in an object or dictionary to the custom field and create targeting based on them.

Private Attributes

Private attributes are user attributes that Statsig uses for evaluation but doesn't forward to any integrations. They are useful for PII or sensitive data that you don't want to send to third-party services.

php
use Statsig\StatsigUser;

$user = new StatsigUser([
    'userID' => 'a-user-id',
    'email' => 'user@example.com',
    'ip' => '192.168.1.1',
    'userAgent' => 'Mozilla/5.0...',
    'country' => 'US',
    'locale' => 'en_US',
    'appVersion' => '1.0.0',
    'custom' => [
        // Custom fields
        'plan' => 'premium',
        'age' => 25
    ],
    'customIDs' => [
        // Custom ID types
        'stableID' => 'stable-id-123'
    ],
    'privateAttributes' => [
        // Private attributes not forwarded to integrations
        'email' => 'private@example.com'
    ]
]);

Private Attributes

Set the privateAttributes parameter in the StatsigUser constructor to define which attributes are private and shouldn't be forwarded to any third-party integrations. The privateAttributes parameter is a key-value dictionary where keys are attribute names and values are the private values. In the example user object above, the key "email" appears both in the top-level email field and in privateAttributes. These are distinct: you can have a non-private value in the top-level email field and a private value in private_attributes, or vice versa.

php
$user = new StatsigUser([
    'userID' => 'a-user-id',
    'email' => 'non_private@example.com',
    'privateAttributes' => [
        'email' => 'private@example.com'
    ]
]);

Statsig Options

You can pass an optional options parameter in addition to sdkKey during initialization to customize the Statsig client.

Proxy and Custom Network Routing

The PHP Server Core SDK supports a dedicated proxy_config for a standard outbound HTTP proxy. If you only need to route Statsig traffic to different endpoints, use specs_url, log_event_url, and id_lists_url.


Performance Recommendations

If you experience performance issues, particularly with long initialization times, disable user agent parsing and country lookup to improve performance:

  • Set disable_user_agent_parsing: true if you don't need device or browser-based targeting.
  • Set disable_country_lookup: true if you don't need country-based targeting.
These optimizations were added in response to performance issues identified in PR #1119.

Example Usage

php
use Statsig\Statsig;
use Statsig\StatsigOptions;
use Statsig\ProxyConfig;
use Statsig\StatsigLocalFileSpecsAdapter;
use Statsig\StatsigLocalFileEventLoggingAdapter;

// Create proxy configuration
$proxyConfig = new ProxyConfig(
    proxyHost: "proxy.example.com",
    proxyPort: 8080,
    proxyAuth: "username:password",  // Optional, only if the proxy requires authentication
    proxyProtocol: "http"
);

// Initialize StatsigOptions with custom parameters
$options = new StatsigOptions(
    specs_url: null,
    log_event_url: null,
    specs_adapter: new StatsigLocalFileSpecsAdapter($sdk_key, "/tmp"),
    event_logging_adapter: new StatsigLocalFileEventLoggingAdapter($sdk_key, "/tmp"),
    environment: "development",
    event_logging_flush_interval_ms: 60000,
    event_logging_max_queue_size: 1000,
    specs_sync_interval_ms: 600000,
    output_log_level: "INFO",
    disable_country_lookup: true, // For better performance
    wait_for_country_lookup_init: false,
    wait_for_user_agent_init: false,
    enable_id_lists: false,
    disable_network: false,
    id_lists_url: null,
    id_lists_sync_interval_ms: null,
    disable_all_logging: false,
    init_timeout_ms: 3000,
    fallback_to_statsig_api: false,
    use_third_party_ua_parser: null,
    persistent_storage: null,
    proxy_config: $proxyConfig  // Add proxy configuration
);

// Pass the options object into Statsig constructor
$statsig = new Statsig($sdk_key, $options);
$statsig->initialize();
When using StatsigLocalFile Adapters, ensure your cron job has run at least one time before using Statsig. See Add Scripts & Cron Job

Custom adapters

SpecsAdapterBase - Custom Configuration Sources

The SpecsAdapterBase lets you fetch Statsig configurations from custom sources instead of (or in addition to) Statsig's servers. This is useful when you want to:

  • Store configurations in your own database or cache (e.g., Redis, Memcached)
  • Implement custom caching strategies
  • Use Statsig in environments with restricted network access
  • Reduce latency by serving configs from a local source

Implementation

To create a custom specs adapter, extend the SpecsAdapterBase class and implement the required methods.

php
<?php

use Statsig\SpecsAdapterBase;
use Statsig\SpecsUpdateListener;

class RedisSpecsAdapter extends SpecsAdapterBase
{
    private $redis;
    private $listener;

    public function __construct($redis)
    {
        parent::__construct();
        $this->redis = $redis;
    }

    public function setup(SpecsUpdateListener $listener): void
    {
        $this->listener = $listener;
    }

    public function start(): void
    {
        // Fetch initial specs when SDK starts
        $this->refreshSpecsFromRedis();
        
        // Optionally, trigger a background job or set up a timer
        $this->refreshSpecsFromRedis();
    }

    private function fetchSpecsFromRedis()
    {
        try {
            $specs = $this->redis->get('statsig_config_specs');
            return $specs ?: null;
        } catch (Exception $e) {
            error_log("Failed to fetch specs from Redis: " . $e->getMessage());
            return null;
        }
    }

    private function refreshSpecsFromRedis()
    {
        $specs = $this->fetchSpecsFromRedis();
        if ($specs && $this->listener) {
            $timestamp = intval(microtime(true) * 1000);
            $this->listener->didReceiveSpecsUpdate($specs, "Redis", $timestamp);
        }
    }
}

Usage

php
use Statsig\Statsig;
use Statsig\StatsigOptions;

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$specsAdapter = new RedisSpecsAdapter($redis);

$options = new StatsigOptions(
    specs_adapter: $specsAdapter
);

$statsig = new Statsig('your-server-secret-key', $options);
$statsig->initialize();

Key Methods

  • setup(SpecsUpdateListener $listener): Called during initialization to provide the listener for spec updates
  • start(): Called when the SDK starts. Fetch and provide initial configuration specs
  • shutdown(): Called when the SDK shuts down. Clean up resources
  • scheduleBackgroundSync(): Called to schedule periodic updates of configuration specs

The SpecsUpdateListener provides:

  • didReceiveSpecsUpdate(string $specs, string $source, int $timestamp): Notify the SDK of new specs
  • getCurrentSpecsInfo(): Get information about current specs

EventLoggingAdapterBase - Custom Event Destinations

The EventLoggingAdapterBase lets you send events to custom destinations instead of or in addition to Statsig's servers. This is useful when you want to:

  • Send events to your existing analytics platform
  • Store events in a database for custom analysis
  • Forward events to multiple destinations
  • Implement custom batching or retry logic

Implementation

To create a custom event logging adapter, extend the EventLoggingAdapterBase class and implement the required methods.

php
<?php

use Statsig\EventLoggingAdapterBase;
use Statsig\LogEventRequest;

class AnalyticsEventAdapter extends EventLoggingAdapterBase
{
    private $analyticsClient;
    private $isStarted = false;

    public function __construct($analyticsClient)
    {
        parent::__construct();
        $this->analyticsClient = $analyticsClient;
    }

    public function start(): void
    {
        $this->isStarted = true;
        // Initialize analytics client connection if needed
        $this->analyticsClient->connect();
    }

    public function logEvents(LogEventRequest $request): bool
    {
        if (!$this->isStarted) {
            return false;
        }

        try {
            $events = $request->payload->events;
            $metadata = $request->payload->statsig_metadata;

            foreach ($events as $event) {
                // Transform Statsig event to analytics platform format
                $analyticsEvent = [
                    'event_name' => $event['eventName'],
                    'user_id' => $event['user']['userID'] ?? null,
                    'timestamp' => $event['time'],
                    'properties' => array_merge(
                        $event['metadata'] ?? [],
                        ['statsig_metadata' => $metadata]
                    )
                ];

                // Send to analytics platform
                $this->analyticsClient->track($analyticsEvent);
            }

            return true;
        } catch (Exception $e) {
            error_log("Failed to log events to analytics platform: " . $e->getMessage());
            return false;
        }
    }

    public function shutdown(): void
    {
        $this->isStarted = false;
        // Clean up analytics client connection
        $this->analyticsClient->disconnect();
    }
}

Usage

php
use Statsig\Statsig;
use Statsig\StatsigOptions;

$analyticsClient = new MyAnalyticsClient('api-key');
$eventAdapter = new AnalyticsEventAdapter($analyticsClient);

$options = new StatsigOptions(
    event_logging_adapter: $eventAdapter
);

$statsig = new Statsig('your-server-secret-key', $options);
$statsig->initialize();

// Events will now be sent to your custom analytics platform
$statsig->logEvent($user, 'button_clicked', ['button_id' => 'signup']);

Key Methods

  • start(): Called when the SDK starts. Initialize connections or resources
  • logEvents(LogEventRequest $request): bool: Process and send events. Return true on success, false on failure
  • shutdown(): Called when the SDK shuts down. Clean up resources

The LogEventRequest contains:

  • event_count: Number of events in the request
  • retries: Number of retry attempts for this request
  • payload: LogEventPayload with events and metadata

The LogEventPayload contains:

  • events: Array of event objects with user data, event names, and metadata
  • statsig_metadata: SDK metadata including version and environment information

Shutting Statsig down

Statsig batches and periodically flushes events. To ensure all logged events are flushed before shutdown, call shutdown() before your app or server shuts down:

php
// Method signature
public function shutdown(): void

// example usage
try {
    $statsig->shutdown();
    echo "Statsig instance has been successfully shutdown.\n";
} catch (Exception $e) {
    error_log($e->getMessage());
}

Alternatively, if you operate in a serverless environment or cloud function and want to keep Statsig running in case the function is recycled, flush the logs to Statsig servers. To wait for logs to post before resolving, use:

php
// Method signature
public function flushEvents(): void

// example usage
try {
    $statsig->flushEvents();
    echo "All events have been successfully flushed.\n";
} catch (Exception $e) {
    echo "Failed to flush events: " . $e->getMessage() . "\n";
}

Local overrides

Local Overrides let you override the values of gates, configs, experiments, and layers for testing. This is useful for local development or testing when you want to force a specific value without changing the configuration in the Statsig console.

php
$statsig->overrideGate("a_gate_name", true);

$statsig->overrideDynamicConfig("a_config_name", [
    "key" => "value",
]);

$statsig->overrideExperiment("an_experiment_name", [
    "key" => "value",
]);

$statsig->overrideExperimentByGroupName("an_experiment_name", "a_group_name");

$statsig->overrideLayer("a_layer_name", [
    "key" => "value",
]);

You can also pass a third argument to scope an override to a specific ID:

php
$statsig->overrideExperimentByGroupName("an_experiment_name", "a_group_name", "user_123");

Persistent storage

The Persistent Storage interface lets you implement custom storage for experiment assignments. This ensures consistent user experiences across sessions by persisting experiment assignments. For more information, go to the Persistent Assignment documentation.
php
use Statsig\PersistentStorage;
use Statsig\StickyValues;

class MyPersistentStorage extends PersistentStorage
{
    private array $storage = [];

    public function load(string $key): ?array
    {
        return $this->storage[$key] ?? null;
    }

    public function save(string $key, string $config_name, StickyValues $data): void
    {
        $this->storage[$key] ??= [];
        $this->storage[$key][$config_name] = $data->toArray();
    }

    public function delete(string $key, string $config_name): void
    {
        unset($this->storage[$key][$config_name]);
    }
}
php
$persistent_storage = new MyPersistentStorage();

$options = new StatsigOptions(
    persistent_storage: $persistent_storage
);

$statsig = new Statsig("secret-key", $options);
$statsig->initialize();

$persisted_user = new StatsigUser("test-123");
$values = $persistent_storage->getValuesForUser($persisted_user, "userID") ?? [];

$experiment = $statsig->getExperiment(
    $persisted_user,
    "active_experiment",
    ["user_persisted_values" => $values],
);

Data store

The Data Store interface lets you implement custom storage for Statsig configurations, enabling advanced caching strategies and integration with your preferred storage systems.

Not supported at this time.

Custom output logger

The Output Logger interface lets you customize how the SDK logs messages, enabling integration with your own logging system and control over log verbosity.

Not supported at this time.

Observability client

The Observability Client interface lets you monitor the health of the SDK by integrating with your own observability systems. This enables you to track metrics, errors, and performance data. For more information on the metrics Statsig SDKs emit, refer to the Monitoring documentation.

Not supported at this time.

Notes on beta version

The PHP SDK requires an adapter for both logging and saving config specs, given the stateless nature of PHP. The example repository provides simple file-based adapters. More mature implementations may use a different, more performant caching approach. For help with setup, reach out on Slack.

FAQ

Was this helpful?