# PHP Server SDK

{% callout type="tip" %}
Migrating from the legacy PHP SDK? Refer to the

[Migration Guide](https://docs.statsig.com/server-core/migration-guides/php)

.
{% /callout %}

## Set up the SDK

{% steps %}
{% step title="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](https://www.php.net/manual/en/ffi.configuration.php#ini.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](https://github.com/daniel-statsig/statsig-php-core-slim-example/tree/main/bin).

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.
{% /step %}

{% step title="Initialize the SDK" %}
After installation, initialize the SDK using a [Server Secret Key from the Statsig console](https://console.statsig.com/api_keys).

{% callout type="warning" %}
Keep Server Secret Keys private. If you expose one, you can disable and recreate it in the Statsig console.
{% /callout %}

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;
},
```

{% callout type="warning" %}
`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.
Go to [Add Scripts & Cron Job](#2-add-scripts--cron-job)
{% /callout %}

`initialize` performs a network request. After `initialize` completes, virtually all SDK operations are synchronous (refer to [Evaluating Feature Gates in the Statsig SDK](https://blog.statsig.com/evaluating-feature-gates-in-the-statsig-sdk-a6f8881a1ad8)). The SDK fetches updates from Statsig in the background independently of API calls.
{% /step %}
{% /steps %}

## Working with the SDK

### Checking a feature flag/gate

After you initialize the SDK, you can fetch a [**Feature Gate**](https://docs.statsig.com/feature-flags/overview). 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](#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**](https://docs.statsig.com/dynamic-config/overview). 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. Statsig provides two APIs and recommends [Layers](https://docs.statsig.com/experiments/layers-overview) 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 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 aren't available for this SDK yet. Need it now? Reach out in [Slack](https://statsig.com/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.

Log Explorer event forwarding isn't available for this SDK yet. Need it now? Reach out in [Slack](https://statsig.com/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. Complete user information lets you take advantage of advanced gate and config conditions (like country or OS/browser-level checks) and correctly measure the impact of experiments on metrics and events. As explained in [why an ID is always required for server SDKs](https://docs.statsig.com/sdks/user#why-is-an-id-always-required-for-server-sdks), you must provide at least one identifier (userID or customID) to ensure 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'
    ]
]);
```

Set the `privateAttributes` parameter in the `StatsigUser` constructor to define which attributes are private so that Statsig doesn't forward them 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.

{% accordion title="StatsigOptions" %}
{% parameter name="specs_url" type="string" %}
Custom URL for fetching feature specifications.
{% /parameter %}

{% parameter name="log_event_url" type="string" %}
Custom URL for logging events.
{% /parameter %}

{% parameter name="specs_adapter" type="StatsigSpecsAdapter" %}
An adapter with custom storage behavior for config specs. For example, use `StatsigLocalFileSpecsAdapter` to store configs in the local filesystem.
{% /parameter %}

{% parameter name="event_logging_adapter" type="StatsigEventLoggingAdapter" %}
An adapter with custom event logging behavior. For example, use `StatsigLocalFileEventLoggingAdapter` to store events in the local filesystem.
{% /parameter %}

{% parameter name="environment" type="string" %}
Environment parameter for evaluation.
{% /parameter %}

{% parameter name="event_logging_flush_interval_ms" type="int" %}
How often the SDK flushes events to Statsig servers (in milliseconds).
{% /parameter %}

{% parameter name="event_logging_max_queue_size" type="Option<u32>" %}
Maximum number of events to queue before forcing a flush.

* Default is `2000`
* event\_logging\_max\_queue\_size \* event\_logging\_max\_pending\_batch\_queue\_size is the upper limit on how many events are queued
* Refer to `event_logging_max_pending_batch_queue_size`
{% /parameter %}

{% parameter name="event_logging_max_pending_batch_queue_size" type="Option<u32>" %}
Maximum number of event batches to hold in buffer to retry.

* Default is `100`.
* event\_logging\_max\_queue\_size \* event\_logging\_max\_pending\_batch\_queue\_size is the upper limit on how many events are queued
* eg: 2000 \* 100 means the SDK can process 200k event per second before events start getting dropped
* Refer to `event_logging_max_queue_size`.
{% /parameter %}

{% parameter name="specs_sync_interval_ms" type="int" %}
How often the SDK updates specifications from Statsig servers (in milliseconds).
{% /parameter %}

{% parameter name="output_log_level" type="string" %}
Controls the verbosity of SDK logs.
{% /parameter %}

{% parameter name="disable_country_lookup" type="bool" %}
Disables country lookup based on IP address. Set to `true` to improve performance if you don't need country-based targeting.
{% /parameter %}

{% parameter name="disable_user_agent_parsing" type="bool" %}
Disables user agent parsing. Set to `true` to improve performance if you don't need device or browser-based targeting.
{% /parameter %}

{% parameter name="init_timeout_ms" type="int" %}
Maximum time in milliseconds to wait for SDK initialization to complete. If initialization takes longer than this timeout, the SDK continues to operate but may return default values until it completes.
{% /parameter %}

{% parameter name="fallback_to_statsig_api" type="bool" %}
When set to true, the SDK falls back to the Statsig API directly if custom adapters (like local file adapters) fail to load configurations.
{% /parameter %}

{% parameter name="enable_id_lists" type="bool" %}
Enable/disable ID list functionality. **Required to be `true` when using segments with more than 1000 IDs.** Refer to [ID List segments](https://docs.statsig.com/segments/add-id-list) for more details.
{% /parameter %}

{% parameter name="proxy_config" type="ProxyConfig" %}
Configuration for connecting through a proxy server.
{% /parameter %}

{% accordion title="ProxyConfig" %}
{% parameter name="proxyHost" type="string" %}
The hostname or IP address of the proxy server (e.g., `"proxy.example.com"` or `"192.168.1.100"`).
{% /parameter %}

{% parameter name="proxyPort" type="int" %}
The port number of the proxy server (e.g., `8080`, `3128`, `1080`).
{% /parameter %}

{% parameter name="proxyAuth" type="string" %}
Authentication credentials for the proxy server in the format `"username:password"`. Required only if the proxy requires authentication.
{% /parameter %}

{% parameter name="proxyProtocol" type="string" %}
The protocol to use for the proxy connection. Supported values: `"http"`, `"https"`, `"socks5"`.
{% /parameter %}
{% /accordion %}
{% /accordion %}

### 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.

Statsig added these optimizations in response to performance issues identified in [PR #1119](https://github.com/statsig-io/private-statsig-server-core/pull/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();
```

{% callout type="warning" %}
When using `StatsigLocalFile` Adapters, ensure your cron job has run at least one time before using Statsig.
Go to [Add Scripts & Cron Job](#2-add-scripts--cron-job)
{% /callout %}

## 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 now go 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 flush all logged events 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](https://docs.statsig.com/server/concepts/persistent_assignment) documentation.

```php expandable MyPersistentStorage.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 expandable PersistentStorageUsage.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.

{% callout type="note" %}
Not supported yet.
{% /callout %}

## 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.

{% callout type="note" %}
Not supported yet.
{% /callout %}

## 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](https://docs.statsig.com/infrastructure/sdk-monitoring) documentation.

{% callout type="note" %}
Not supported yet.
{% /callout %}

## 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](https://github.com/daniel-statsig/statsig-php-core-slim-example) provides simple file-based adapters. More mature implementations may use a different, more performant caching approach. For help with setup, reach out on [Slack](https://statsig.com/slack).

## FAQ

{% accordion-group %}
{% accordion title="How do I run experiments for logged out users?" %}
Refer to the guide on [device level experiments](https://docs.statsig.com/guides/first-device-level-experiment).
{% /accordion %}
{% /accordion-group %}
