
## Set up the SDK

{% steps %}
{% step title="Install the SDK" %}
If you are using CMake, add the following to a `.cmake` file:

```cmake
FetchContent_Declare(statsig
        GIT_REPOSITORY    https://github.com/statsig-io/cpp-server-sdk.git
        GIT_TAG           v0.1.0
)

FetchContent_MakeAvailable(statsig)
```

And include the following in your `CMakeLists.txt` file:

```cmake
cmake_minimum_required(VERSION 3.11)

include(FetchContent)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/statsig.cmake)
```

Check out the latest versions on [https://github.com/statsig-io/cpp-server-sdk/releases/latest](https://github.com/statsig-io/cpp-server-sdk/releases/latest)
{% /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" %}
Don't embed your Server Secret Key in client-side applications or expose it in any external-facing documents. If you accidentally expose it, you can create a new one in the Statsig console.
{% /callout %}

```cpp
#include <statsig.h>

statsig::initialize('server-secret-key');

// Or, if you want to initialize with certain options
statsig::Options options;
options.localMode = true
statsig::initialize('server-secret-key', options)
```

`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 the SDK is initialized, you can fetch a [**Feature Gate**](/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:

```cpp
statsig::User user;
user.userID = "some_user_id"
if (statsig::checkGate(user, 'use_new_feature'))
{
  // Gate is on, enable new feature
}
else {
  // Gate is off
}
```

## 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**](/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.

```cpp
statsig::DynamicConfig config = statsig::get_config(user, 'awesome_product_details')

auto item_name = config.value['product_name'];
auto price = config.value['price'];
auto shouldDiscount = config.value['discount'];
```

## Getting a Layer/Experiment

Use **Layers/Experiments** to run A/B/n experiments. Two APIs are available. Statsig recommends [Layers](/experiments/layers-overview) because they enable quicker iterations with parameter reuse.

```cpp
// Values via getLayer

statsig::Layer layer = statsig::getLayer(user, "user_promo_experiments")
auto title = layer.get("title", "Welcome to Statsig!")
auto discount = layer.get("discount")

// or, via getExperiment

statsig::DynamicConfig title_exp = statsig::getExperiment(user, "new_user_promo_title")
statsig::DynamicConfig price_exp = statsig::getExperiment(user, "new_user_promo_price")

title = title_exp.value["title"]
discount = price_exp.value["discount"]

...

price = msrp * (1 - discount)


```

## Logging an Event

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

```cpp
statsig::logEvent(user, 'add_to_cart')
```

Learn more about identifying users, group analytics, and best practices for logging events in the [logging events guide](/guides/logging-events).

## Statsig 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](/sdks/user#why-is-an-id-always-required-for-server-sdks), 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.

{% callout type="note" %}
While typing is lenient on the `StatsigUser` object, evaluation operators only work on primitive types (mostly strings and numbers). The SDK attempts to cast custom field types to match the operator, but evaluation results for non-primitive types are not guaranteed. For example, an array set as a custom field is compared only as a string.
{% /callout %}

### Private Attributes

The `StatsigUser` object also has a `privateAttributes` field, which is a dictionary for setting private user attributes. The SDK uses attributes in `privateAttributes` only for evaluation and targeting, and removes them from logs before sending them to the Statsig server.

For example, if a feature gate should pass only for users with emails ending in "@statsig.com" but you don't want to log email addresses to Statsig, add the key-value pair `{ email: "my_user@statsig.com" }` to `privateAttributes`.

## Statsig Options

`initialize()` takes an optional `options` parameter in addition to the secret key to customize the Statsig client. Available options include:

* **api** string, default `"https://statsigapi.net/v1"`
  * The base url to use for network requests from the SDK
* **rulesetsSyncIntervalMs**: int, default `10000`
  * The interval to poll for changes to your gate and config definition changes
* **loggingIntervalMs**: int, default `60000`
  * The default interval to flush logs to Statsig servers
* **loggingMaxBufferSize**: int, default `1000`, can be set lower but anything over 1000 will be dropped on the server
  * The maximum number of events to batch before flushing logs to the server
* **localMode**: bool, default `false`
  * Restricts the SDK to not issue any network requests and only respond with default values (or local overrides)

{% callout type="info" %}
ID Lists are not supported in the C++ server SDK
{% /callout %}

## Shutdown

To gracefully shut down the SDK and ensure all events are flushed:

```cpp
statsig::shutdown()
```

## Local overrides

You can override the values the SDK returns for testing. This is useful for local development when you want to test specific scenarios.

```cpp
// Adding gate overrides
statsig::overrideGate("a_gate_name", true)

// Adding config overrides
std::unordered_map<std::string, JSON::any> overrideValue = {
    {"overridden key", "overridden field"},
};
statsig::overrideConfig("a_config_name", overrideValue)
```

## FAQ

#### How do I run experiments for logged out users?

Refer to the guide on [device level experiments](/guides/first-device-level-experiment).

## Reference

### User

```cpp
struct User
{
  std::string userID;
  std::string email;
  std::string ipAddress;
  std::string userAgent;
  std::string country;
  std::string locale;
  std::string appVersion;
  std::unordered_map<std::string, JSON::any> custom;
  std::unordered_map<std::string, JSON::any> privateAttribute;
  std::unordered_map<std::string, std::string> statsigEnvironment;
  std::unordered_map<std::string, std::string> customIDs;
};
inline bool operator==(User const &a, User const &b)
{
  return a.userID == b.userID &&
          a.email == b.email &&
          a.ipAddress == b.ipAddress &&
          a.userAgent == b.userAgent &&
          a.country == b.country &&
          a.locale == b.locale &&
          a.appVersion == b.appVersion &&
          a.custom == b.custom &&
          a.privateAttribute == b.privateAttribute &&
          a.statsigEnvironment == b.statsigEnvironment &&
          a.customIDs == b.customIDs;
};
```

### Options

```cpp
struct Options
{
  std::string api;
  bool localMode;
  int rulesetsSyncIntervalMs;
  int loggingIntervalMs;
  int loggingMaxBufferSize;
  Options() : api("https://statsigapi.net"),
              localMode(false),
              rulesetsSyncIntervalMs(10 * 1000),
              loggingIntervalMs(60 * 1000),
              loggingMaxBufferSize(1000){};
};
```
