> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kameleoon.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK C++

> Intégrez le SDK C++ de Kameleoon pour exécuter des expériences et activer des feature flags dans vos services C++ et back-ends web.

L'intégration du SDK dans votre application est simple, et son empreinte (mémoire et utilisation réseau) est faible.

**Pour commencer** : pour vous aider à démarrer, consultez le [guide du développeur](#guide-du-développeur).

**Dernière version** : `0.8.5`. Consultez le [changelog du SDK C++](https://github.com/Kameleoon-new/client-cpp/blob/main/CHANGELOG.md) pour les notes de version, ou l'[index des changelogs des SDK](/fr/developer-docs/sdks/versions) pour tous les SDK.

**Méthodes du SDK** : pour la documentation de référence complète du SDK C++, consultez la section [référence](#référence).

## Guide du développeur

Ce guide est conçu pour vous aider à intégrer rapidement le SDK C++ et à commencer à évaluer des feature flags dans votre application C++.

### Pour commencer

#### Installer le client C++

Le SDK C++ est une bibliothèque C++17 construite au-dessus du Kameleoon SDK Core, une bibliothèque partagée native (`libkameleoon_ffi`) écrite en Rust qui implémente le comportement du SDK. Votre application lie la bibliothèque C++ statiquement et charge la bibliothèque core à l'exécution.

<Warning>
  Le Kameleoon SDK Core est compilé depuis les sources pour votre plateforme et votre architecture cibles. Assurez-vous que **Rust** et **Cargo** sont installés et disponibles dans le `PATH` de votre système, et installez `cbindgen`, qui génère l'en-tête C de la bibliothèque core :

  ```bash theme={null}
  cargo install cbindgen --locked
  ```

  Installer Rust et Cargo : [https://rust-lang.org/tools/install](https://rust-lang.org/tools/install)

  Les versions futures fourniront des bibliothèques core précompilées pour les plateformes courantes afin de simplifier l'installation. La compilation locale restera disponible pour les utilisateurs qui préfèrent compiler depuis les sources.
</Warning>

Prérequis :

* Un compilateur C++17 (GCC, Clang ou MSVC) et CMake 3.16 ou version ultérieure.
* Rust 1.91 ou version ultérieure, Cargo et `cbindgen` pour compiler la bibliothèque SDK Core (`libkameleoon_ffi.so` sous Linux, `libkameleoon_ffi.dylib` sous macOS, `kameleoon_ffi.dll` avec sa bibliothèque d'import `kameleoon_ffi.dll.lib` sous Windows).

Clonez le [dépôt du SDK C++](https://github.com/Kameleoon-new/client-cpp) et compilez la bibliothèque core, puis compilez la bibliothèque C++ en la liant à celle-ci :

```bash theme={null}
git clone https://github.com/Kameleoon-new/client-cpp.git
cd client-cpp

# Builds the SDK Core shared library into target/release
cargo build --locked -p kameleoon-ffi --release

# Builds the C++ library; cbindgen generates the core header during this step
cmake -S cpp/client -B cpp/client/build -DKAMELEOON_CPP_BUILD_TESTS=OFF -DKAMELEOON_CPP_BUILD_EXAMPLES=OFF
cmake --build cpp/client/build
```

Pour intégrer le SDK dans votre propre projet CMake, ajoutez le répertoire `cpp/client` avec `add_subdirectory()` et liez la cible `Kameleoon::CppClient`. Faites pointer `KAMELEOON_FFI_LIBRARY` vers la bibliothèque core que vous avez compilée ; l'en-tête C est généré avec `cbindgen`, ou vous pouvez en fournir un existant avec `KAMELEOON_FFI_HEADER` :

```cmake title="CMakeLists.txt" theme={null}
set(KAMELEOON_FFI_LIBRARY "${CMAKE_SOURCE_DIR}/third_party/client-cpp/target/release/libkameleoon_ffi.so" CACHE FILEPATH "")
set(KAMELEOON_CPP_BUILD_TESTS OFF CACHE BOOL "")
set(KAMELEOON_CPP_BUILD_EXAMPLES OFF CACHE BOOL "")

add_subdirectory(third_party/client-cpp/cpp/client)

target_link_libraries(my_app PRIVATE Kameleoon::CppClient)
```

<Note>
  * `libkameleoon_ffi` est chargée à l'exécution : installez-la dans un emplacement de bibliothèques standard, ou livrez-la à côté de votre exécutable. Sous Linux et macOS, la livrer à côté de l'exécutable nécessite un RPATH de `$ORIGIN` ou `@loader_path` (par exemple, `set_target_properties(my_app PROPERTIES INSTALL_RPATH "$ORIGIN")`). Sous Windows, copiez `kameleoon_ffi.dll` à côté de vos binaires.
  * Lorsque vous créez un client, le SDK vérifie que la bibliothèque `libkameleoon_ffi` chargée correspond à la version avec laquelle il a été compilé et lève une `KameleoonException` avec `ErrorCode::Internal` dans le cas contraire. Mettez toujours à niveau la bibliothèque C++ et la bibliothèque core ensemble.
  * Tous les types publics du SDK se trouvent dans l'espace de noms `kameleoon`. Incluez `kameleoon/kameleoon.hpp` pour obtenir l'ensemble de l'API publique.
</Note>

#### Configuration supplémentaire

Créez un fichier de configuration JSON (par exemple, `client-cpp.json`) pour fournir les identifiants et personnaliser le comportement du SDK. Vous pouvez également [télécharger notre fichier de configuration d'exemple](/assets/developer-docs/sdks/web-sdks/client-configs/client-config.json).

Le SDK C++ peut être configuré soit avec un fichier JSON dont vous passez le chemin à `KameleoonClientFactory::create()`, soit en remplissant une structure `KameleoonClientConfig` directement dans le code.

Le tableau suivant présente les propriétés disponibles que vous pouvez définir :

| Clé (Code / Fichier de configuration) | Description | Valeur par défaut |
| - | - | - |
| `client_id` / `clientId` <Badge color="red" size="sm">obligatoire</Badge> | Requis pour l'authentification auprès du service Kameleoon. Pour trouver votre `client_id`, consultez la documentation [identifiants d'API](/fr/user-manual/account-and-team-management/users-and-teams/api-credentials). | |
| `client_secret` / `clientSecret` <Badge color="red" size="sm">obligatoire</Badge> | Requis pour l'authentification auprès du service Kameleoon. Pour trouver votre `client_secret`, consultez la documentation [identifiants d'API](/fr/user-manual/account-and-team-management/users-and-teams/api-credentials). | |
| `session_duration_minutes` / `sessionDurationMinutes` <Badge color="green" size="sm">facultatif</Badge> | Intervalle de temps, en minutes, pendant lequel le SDK conserve un visiteur et ses données associées en mémoire. | `30` minutes |
| `refresh_interval_minutes` / `refreshIntervalMinutes` <Badge color="green" size="sm">facultatif</Badge> | Intervalle, en minutes, utilisé pour rafraîchir la configuration des expériences actives et des feature flags. | `60` minutes |
| `default_timeout_millis` / `defaultTimeoutMillis` <Badge color="green" size="sm">facultatif</Badge> | Délai d'attente par défaut, en millisecondes, pour les requêtes réseau du SDK. | `10000` millisecondes |
| `tracking_interval_millis` / `trackingIntervalMillis` <Badge color="green" size="sm">facultatif</Badge> | Intervalle, en millisecondes, utilisé pour regrouper les requêtes de tracking. Les valeurs sont restreintes à l'intervalle `[1000, 5000]`. | `1000` millisecondes |
| `environment` / `environment` <Badge color="green" size="sm">facultatif</Badge> | Environnement à partir duquel la configuration des feature flags doit être utilisée. La valeur peut être `production`, `staging` ou `development`. | `std::nullopt` (traité comme `production`) |
| `top_level_domain` / `topLevelDomain` <Badge color="green" size="sm">facultatif</Badge> | Le domaine de premier niveau actuel pour votre site web. Utilisez le format `example.com` sans protocole ni sous-domaines. | `std::nullopt` |
| `proxy_host` / `proxyHost` <Badge color="green" size="sm">facultatif</Badge> | Hôte proxy pour les appels SDK sortants. Formats pris en charge : `https://my.prox`, `https://my.prox:4545`, `socks5://192.168.1.1:9000`. | `std::nullopt` |
| `network_domain` / `networkDomain` <Badge color="green" size="sm">facultatif</Badge> | Domaine personnalisé utilisé par les SDK pour les requêtes sortantes, souvent pour le proxying. Doit être un domaine valide (par exemple, example.com ou sub.example.com). Les formats invalides utilisent la valeur de Kameleoon par défaut. | `std::nullopt` |

#### Initialiser le client Kameleoon

Après avoir installé le SDK et configuré vos identifiants, créez un `KameleoonClient` en utilisant `KameleoonClientFactory`.

<Tabs>
  <Tab title="Config File">
    ```cpp theme={null}
    #include "kameleoon/kameleoon.hpp"

    using namespace kameleoon;

    KameleoonClient create_client()
    {
        const std::string site_code = "a8st4f59bj";

        KameleoonClient client = KameleoonClientFactory::create(site_code, "/etc/kameleoon/client-cpp.json");
        client.initialize();

        return client;
    }
    ```
  </Tab>

  <Tab title="Code">
    ```cpp theme={null}
    #include "kameleoon/kameleoon.hpp"

    using namespace kameleoon;

    KameleoonClient create_client()
    {
        const std::string site_code = "a8st4f59bj";

        KameleoonClientConfig config{
            .client_id = "<client-id>",                  // mandatory
            .client_secret = "<client-secret>",          // mandatory
            .refresh_interval_minutes = 60,              // optional (60 minutes by default)
            .session_duration_minutes = 30,              // optional (30 minutes by default)
            .default_timeout_millis = 10'000,            // optional (10000 ms by default)
            .tracking_interval_millis = 1'000,           // optional (1000 ms by default)
            .proxy_host = "http://192.168.0.25:8080",    // optional
            .environment = "development",                // optional
            .top_level_domain = ".example.com",          // mandatory if you use hybrid mode (engine or web experiments)
            .network_domain = "example.com",             // optional
        };

        KameleoonClient client = KameleoonClientFactory::create(site_code, config);
        client.initialize();

        return client;
    }
    ```
  </Tab>
</Tabs>

<Note>
  Les exemples de cette page utilisent les [designated initializers](https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers) de C++20 (`GetVariationOptions{.track = false}`) pour remplir les structures de configuration, d'options et de données du SDK. Avec un compilateur C++17, déclarez la structure et définissez ses champs un par un à la place.
</Note>

Un `KameleoonClient` est l'objet principal utilisé pour évaluer les feature flags, ajouter des données de visiteur et envoyer des requêtes de tracking.

<Warning>
  * Il est recommandé d'utiliser `KameleoonClient` comme un objet singleton, car il sert de pont entre votre application et la plateforme Kameleoon. Il expose toutes les méthodes et propriétés requises pour exécuter des expériences efficacement. `KameleoonClient` est move-only : conservez-le à un seul endroit et passez-le par référence.
  * Le SDK C++ s'initialise de manière asynchrone. Vous devez appeler [`initialize()`](#initialize) avant de vous appuyer sur l'évaluation des fonctionnalités dans le code de production.
  * Chaque échec du SDK est signalé sous la forme d'une [`KameleoonException`](#gestion-des-erreurs). Entourez les appels au SDK de blocs `try`/`catch`.
</Warning>

#### Activer un feature flag

##### Attribution d'un ID unique à un utilisateur

Pour attribuer un ID unique à un utilisateur, vous pouvez utiliser la méthode [`get_visitor_code()`](#get_visitor_code). Si un **visitor code** n'existe pas (dans le cookie des en-têtes de requête), la méthode génère un ID unique aléatoire ou utilise un `default_visitor_code` que vous auriez généré. L'ID est ensuite défini dans un cookie des en-têtes de réponse.

Si vous utilisez Kameleoon en [mode hybride](/fr/developer-docs/feature-experimentation/get-started/hybrid-experimentation), l'appel à la méthode `get_visitor_code()` garantit que le fichier d'application `engine.js` (anciennement nommé `kameleoon.js`) et le SDK partagent l'ID unique (**visitor code**).

##### Récupération de la configuration d'un flag

Pour implémenter un feature flag dans votre code, vous devez d'abord créer le feature flag dans votre compte Kameleoon.

Pour déterminer le statut ou la variation d'un feature flag pour un utilisateur spécifique, vous devez utiliser la méthode [`get_variation()`](#get_variation) ou [`is_feature_active()`](#is_feature_active) pour récupérer la configuration en fonction de la `feature_key`.

La méthode `get_variation()` gère à la fois les feature flags simples avec des états ON/OFF et les flags plus complexes avec plusieurs variations. La méthode récupère la variation appropriée pour l'utilisateur en vérifiant les règles du feature, en attribuant la variation et en la renvoyant en fonction de la `feature_key` et du `visitor_code`.

Vous pouvez utiliser la méthode `is_feature_active()` pour récupérer la configuration d'un feature flag simple qui n'a qu'un état ON ou OFF, par opposition aux feature flags plus complexes avec plusieurs variations ou options de ciblage.

Si votre feature flag a des variables associées (comme des comportements spécifiques liés à chaque variation), `get_variation()` vous permet également d'accéder à l'objet [`Variation`](#variation), qui fournit des détails sur la variation attribuée et son expérience associée. Cette méthode vérifie si le feature flag cible l'utilisateur, trouve la variation attribuée au visiteur et l'enregistre dans le stockage. Lorsque `track=true`, le SDK envoie l'événement d'exposition à l'expérience spécifiée lors de la prochaine requête de tracking, qu'il déclenche automatiquement en fonction du [`tracking_interval_millis`](#configuration-supplémentaire) du SDK. L'intervalle par défaut est de 1000 millisecondes (1 seconde).

La méthode `get_variation()` vous permet de contrôler si le SDK suit le visiteur. Si `track=false`, le SDK n'envoie aucun événement d'exposition. Cette option est utile si vous préférez ne pas suivre les données via le SDK et vous appuyer plutôt sur le tracking côté client géré par le moteur Kameleoon, par exemple. De plus, définir `track=false` est utile lorsque vous utilisez la méthode `get_variations()`, où vous pourriez n'avoir besoin que des variations pour tous les flags sans déclencher d'événements de tracking. Pour en savoir plus sur le fonctionnement du tracking, consultez [cet article](/fr/developer-docs/feature-experimentation/technical-reference/faq-global#when-does-the-sdk-send-a-tracking-request-for-analytics)

##### Ajout de points de données pour cibler un utilisateur ou filtrer / segmenter les visites dans les rapports

Pour cibler un utilisateur, assurez-vous d'avoir ajouté les points de données pertinents à son profil avant de récupérer la variation du feature ou de vérifier si le flag est actif. Utilisez la méthode [`add_data()`](#add_data) pour ajouter ces points de données au profil de l'utilisateur.

Pour récupérer les points de données collectés sur d'autres appareils ou pour accéder aux données passées de l'utilisateur (collectées côté client lors de l'utilisation de Kameleoon en mode hybride), utilisez la méthode [`get_remote_visitor_data()`](#get_remote_visitor_data). Cette méthode récupère les données depuis les serveurs de manière asynchrone. Il est important d'appeler `get_remote_visitor_data()` *avant* de récupérer la variation ou de vérifier si le feature flag est actif, car le SDK peut avoir besoin de ces données pour attribuer un utilisateur à une variation donnée.

Pour en savoir plus sur les conditions de ciblage disponibles, consultez [l'article détaillé sur le sujet](/fr/developer-docs/feature-experimentation/targeting-and-segmentation/native-segmentation).

De plus, les points de données que vous ajoutez au profil du visiteur seront disponibles lors de l'analyse de vos expériences, vous permettant de filtrer et de segmenter vos résultats par des facteurs tels que l'appareil et le navigateur. Le mode hybride de Kameleoon collecte automatiquement une variété de points de données côté client, ce qui facilite la segmentation de vos résultats sur la base de ces points de données pré-collectés. Voir la liste complète [ici](/fr/user-manual/experiment-analytics/analyze-results/results-page/results-page-settings#ventiler-l’audience).

Si vous devez suivre des points de données supplémentaires au-delà de ce qui est collecté automatiquement, vous pouvez utiliser la fonctionnalité [Custom Data](#customdata) de Kameleoon. Les custom data vous permettent de capturer et d'analyser des informations spécifiques pertinentes pour vos expériences. N'oubliez pas d'appeler la méthode [`flush()`](#flush) pour envoyer les données collectées aux serveurs Kameleoon pour analyse.

<Note>
  Pour garantir l'exactitude de vos résultats, il est recommandé de filtrer les bots en utilisant le type de données [`UserAgent`](#useragent).
</Note>

##### Suivi des conversions d'objectifs

Lorsqu'un utilisateur effectue une action souhaitée (comme un achat), elle est enregistrée comme une conversion. Pour suivre les conversions, utilisez la méthode [`track_conversion()`](#track_conversion) et fournissez les paramètres requis `visitor_code` et `goal_id`.

Le SDK envoie la requête de tracking de conversion avec la prochaine requête de tracking planifiée, qui a lieu à intervalles réguliers (définis par [`tracking_interval_millis`](#configuration-supplémentaire)). Si vous préférez envoyer la requête immédiatement, utilisez la méthode [`flush_instant()`](#flush).

##### Envoi d'événements aux solutions d'analyse

Pour suivre les conversions et envoyer les événements d'exposition à votre solution d'analyse client, vous devez d'abord implémenter Kameleoon en [mode hybride](/fr/developer-docs/feature-experimentation/get-started/hybrid-experimentation/). Ensuite, utilisez la méthode [`get_engine_tracking_code()`](#get_engine_tracking_code).

La méthode `get_engine_tracking_code()` récupère le code de tracking unique requis pour envoyer les événements d'exposition à votre solution d'analyse. L'utilisation de cette méthode vous permet d'enregistrer des événements et de les envoyer à la plateforme d'analyse de votre choix.

### Gestion des erreurs

Chaque erreur levée par le SDK est une `KameleoonException`, donc un seul gestionnaire pour ce type intercepte tous les échecs du SDK. Gérez un type d'erreur spécifique lorsque votre application doit réagir à un échec particulier, par exemple pour revenir à votre comportement par défaut lorsqu'un feature flag n'est pas dans la configuration ou que le SDK n'est pas encore initialisé. La section de référence de chaque méthode liste les erreurs qu'elle peut lever.

`KameleoonException` dérive de `std::runtime_error`. Appelez `code()` pour obtenir le `ErrorCode` qui distingue les erreurs, et `what()` pour obtenir le message.

```cpp theme={null}
#include "kameleoon/kameleoon.hpp"

#include <iostream>

using namespace kameleoon;

try {
    Variation variation = client.get_variation(visitor_code, "new_checkout");
} catch (const KameleoonException& error) {
    switch (error.code()) {
    case ErrorCode::FeatureNotFound:
        // The feature flag isn't in the SDK configuration.
        break;
    case ErrorCode::Initialization:
        // The SDK isn't ready yet; fall back to your default behavior.
        break;
    default:
        std::cerr << "Kameleoon error: " << error.what() << "\n";
        break;
    }
}
```

| Code d'erreur | Description |
| - | - |
| `ErrorCode::Initialization` | Le client n'a pas pu être créé (site code vide, configuration manquante ou illisible, identifiants vides), le SDK n'est pas encore initialisé, ou aucun résultat d'initialisation n'était disponible avant l'expiration du délai d'attente de `initialize()`. |
| `ErrorCode::FeatureNotFound` | Exception indiquant que la clé de feature demandée n'a pas été trouvée dans la configuration interne du SDK. Cela signifie généralement que le feature flag n'est pas activé dans l'application Kameleoon (mais que le code implémentant le feature est déjà déployé dans l'application). |
| `ErrorCode::FeatureExperimentNotFound` | Exception indiquant que l'ID d'expérience demandé n'est pas dans la configuration interne du SDK. Ce comportement est généralement normal et signifie que l'expérience correspondant à la règle n'est pas encore active côté Kameleoon. |
| `ErrorCode::FeatureVariationNotFound` | Exception indiquant que la clé (ID) de variation demandée n'est pas dans la configuration interne du SDK. Ce comportement est généralement normal et signifie que l'expérience correspondant à la variation n'est pas encore active côté Kameleoon. |
| `ErrorCode::FeatureEnvironmentDisabled` | Exception indiquant que le feature flag est désactivé pour l'environnement actuel du visiteur (par exemple, production, staging ou development). |
| `ErrorCode::FeatureRuleNotFound` | La règle demandée n'a pas été trouvée dans la configuration du SDK. |
| `ErrorCode::FeatureEvaluationBlocked` | Exception indiquant que l'évaluation du feature est bloquée. La raison est décrite dans le message d'erreur. Cela se produit généralement en raison des restrictions RGPD lorsque le visiteur n'a pas donné son consentement légal. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |
| `ErrorCode::InvalidSimVarCookieFormat` | Indique que le cookie `kameleoonSimulationFFData` contient du JSON mal formé et que les variations simulées n'ont pas pu être analysées. |
| `ErrorCode::InvalidArgument` | Un argument est invalide : une chaîne n'est pas de l'UTF-8 valide, une valeur d'énumération est inconnue, un délai d'attente est nul ou négatif, ou une entrée dépasse la longueur prise en charge. |
| `ErrorCode::Network` | Une requête réseau a échoué ou le serveur a répondu avec un code de statut non réussi : la récupération de la configuration, une requête de données distantes ou de données de visiteur distantes, ou une requête d'audience warehouse. Également renvoyé lorsque le client ne peut pas être créé parce que `proxy_host` est invalide. |
| `ErrorCode::Internal` | Une erreur interne inattendue du SDK, par exemple une incompatibilité de version de `libkameleoon_ffi`, une méthode appelée sur un client déplacé (moved-from), ou une clé de variation absente de la configuration. |

<Note>
  Les chaînes passées au SDK doivent être de l'UTF-8 valide. Les callbacks que vous fournissez au SDK (surcharges de `CookieAccessor`, gestionnaires d'événements et loggers) ne doivent pas lever d'exception : toute exception qui s'en échappe est interceptée à la frontière du SDK et ignorée.
</Note>

<Note>
  Les erreurs du SDK sont un comportement attendu, pas des plantages : un feature flag qui n'est pas encore activé, un SDK qui charge encore sa configuration ou une défaillance réseau sont toutes des conditions normales. Lorsque l'évaluation d'un feature échoue, journalisez l'erreur et revenez à votre comportement par défaut afin que le visiteur bénéficie toujours d'une expérience fonctionnelle.
</Note>

### Opérations asynchrones

Les opérations liées au réseau ([`initialize()`](#initialize), [`flush_instant()`](#flush), [`get_remote_data()`](#get_remote_data), [`get_remote_visitor_data()`](#get_remote_visitor_data) et [`get_visitor_warehouse_audience()`](#get_visitor_warehouse_audience)) s'exécutent sur le thread de travail propre au SDK. Chacune existe sous trois formes, afin que vous puissiez choisir celle qui convient au thread appelant :

| Forme | Exemple | À utiliser quand |
| - | - | - |
| Bloquante | `client.initialize(timeout)` | Le thread peut attendre : démarrage, arrêt, tâches batch, tests. |
| Completion | `client.initialize_async(timeout, on_done)` | Vous exécutez une boucle d'événements (C++17). L'appel retourne immédiatement et `on_done` reçoit le résultat. |
| Awaitable | `co_await client.co_initialize(timeout)` | Vous écrivez des coroutines C++20. |

```cpp theme={null}
// Blocking: waits until the data is fetched, throws a KameleoonException on failure.
client.get_remote_visitor_data(visitor_code);

// Completion: returns immediately; `error` is null on success.
client.get_remote_visitor_data_async(visitor_code, {}, [](std::exception_ptr error) {
    if (error) {
        // Rethrow `error` to get the KameleoonException.
        return;
    }
    // The remote data is now available locally.
});

// C++20 coroutine: throws a KameleoonException on failure.
co_await client.co_get_remote_visitor_data(visitor_code);
```

Une completion est une `Completion<void>` (`std::function<void(std::exception_ptr)>`), ou une `Completion<T>` (`std::function<void(std::exception_ptr, T)>`) pour les opérations qui renvoient une valeur. Le SDK l'invoque exactement une fois. Vous pouvez omettre la completion pour exécuter l'opération en mode fire-and-forget : les échecs n'apparaissent alors que dans le journal du SDK.

<Warning>
  Les completions et les gestionnaires d'événements s'exécutent généralement sur le thread de travail du SDK, mais une completion peut aussi s'exécuter sur le thread appelant, avant que l'appel `*_async` ne retourne : par exemple, lorsque le SDK échoue immédiatement (le client n'est pas prêt, le visitor code est invalide) ou lorsque `initialize_async()` est appelé sur un client déjà initialisé. Ne supposez pas qu'une completion s'exécute sur un thread particulier ou après le retour de l'appel, et ne conservez pas un verrou pendant l'appel si la completion prend le même verrou. Les completions et les gestionnaires d'événements ne doivent pas bloquer, ne doivent pas lever d'exception et ne doivent pas appeler la forme bloquante d'une opération du SDK : elle attend le même thread de travail et provoque un interblocage. Transmettez le résultat à votre propre boucle d'événements et terminez-y le travail.
</Warning>

<Note>
  C++20 n'a pas de type de tâche de coroutine intégré, donc `co_await` ne fonctionne qu'à l'intérieur d'une coroutine dont le type de promesse accepte l'`Awaitable<T>` du SDK (`KAMELEOON_HAS_COROUTINES` est défini par `kameleoon/async.hpp` lorsque les coroutines sont disponibles). Par défaut, la coroutine reprend sur le thread de travail du SDK ; appelez `.via(executor)` sur l'awaitable pour reprendre sur votre propre boucle d'événements à la place. Les frameworks avec leurs propres types de coroutines, comme Boost.Asio, nécessitent un petit adaptateur autour de la forme completion ; consultez l'exemple de serveur fourni avec le SDK.
</Note>

Les méthodes d'évaluation (`get_visitor_code()`, `get_variation()`, `get_variations()`, `is_feature_active()`, `add_data()`, `track_conversion()` et `flush()`) sont des appels synchrones en mémoire et n'ont besoin de rien de tout cela.

### Utiliser une clé de bucketing personnalisée

Par défaut, Kameleoon utilise un identifiant visiteur unique et anonyme (`visitor_code`) pour attribuer les utilisateurs aux variations des feature flags. Cet identifiant est généralement généré et stocké sur l'appareil de l'utilisateur (dans un cookie de navigateur pour les SDK côté client et côté serveur, et dans le stockage persistant pour les SDK mobiles). Cependant, dans certains scénarios, vous pouvez avoir besoin de garantir que tous les utilisateurs d'une même organisation voient le même variant d'un feature flag.

L'option **Custom Bucketing Key** vous permet de remplacer ce comportement par défaut en fournissant votre propre identifiant personnalisé pour le bucketing. Ce remplacement garantit que la logique d'attribution de Kameleoon utilise la clé que vous spécifiez au lieu du `visitor_code` par défaut.

#### Cas d'usage

L'utilisation d'une clé de bucketing personnalisée est essentielle pour maintenir la cohérence et la précision de vos attributions de feature flags, en particulier dans ces situations :

* **Expériences au niveau d'un compte ou d'une organisation :** pour les produits B2B ou les scénarios où vous souhaitez attribuer tous les utilisateurs d'une même organisation à la même variation, vous pouvez utiliser un identifiant comme un `account_id`. Les clés de bucketing personnalisées sont cruciales pour l'A/B testing de fonctionnalités qui impactent toute une équipe ou une entreprise.

En implémentant une clé de bucketing personnalisée, vous garantissez une plus grande cohérence et précision dans vos expériences, ce qui conduit à des résultats plus fiables et à une meilleure expérience utilisateur.

#### Détails techniques

Lorsque vous configurez une clé de bucketing personnalisée pour un feature flag, vous fournissez à Kameleoon un identifiant spécifique issu des données de votre application :

```cpp theme={null}
using namespace kameleoon;

client.add_data(visitor_code, {CustomData(42, {"new_visitor_code"})});
```

* **Fournir la clé personnalisée :** vous fournissez votre identifiant personnalisé au SDK Kameleoon en utilisant la méthode [`add_data()`](#add_data). Dans cette méthode, vous passez la clé de bucketing personnalisée de votre choix sous la forme d'un objet [`CustomData`](#customdata). Ici, `new_visitor_code` fait référence à l'identifiant que vous souhaitez utiliser pour votre bucketing (par exemple, le nouveau `user_id` ou `account_id`).

<Warning>
  Pour que la clé de bucketing personnalisée fonctionne correctement, vous devez également la définir et la configurer pour le feature flag lors du processus de création ou de modification du flag. Sans cette configuration correspondante, le bucketing du SDK n'appliquera pas votre clé personnalisée. Pour des instructions détaillées sur la configuration dans Kameleoon, consultez cet [article](/fr/user-manual/experimentation/feature-experimentation/create-and-manage-flags/create-a-feature-flag#paramètres-avancés-du-flag).
</Warning>

* **Logique de bucketing :** une fois que vous fournissez une clé de bucketing personnalisée via la méthode `add_data()`, tous les calculs de hachage pour attribuer les utilisateurs aux variations utilisent ce `new_visitor_code` (votre clé personnalisée) au lieu du `visitor_code` par défaut. L'utilisation du `new_visitor_code` signifie que la décision de bucketing dépend de votre identifiant personnalisé, garantissant des attributions cohérentes dans les différents contextes où cet identifiant est présent.
* **Tracking des données et analytics :** il est crucial de noter que, bien que le `new_visitor_code` (votre clé personnalisée) soit utilisé pour les décisions de bucketing, le SDK envoie **toutes les données ultérieures (événements de tracking et conversions, par exemple) en les associant au `visitor_code` *d'origine*.** Cette séparation garantit que vos analytics reflètent fidèlement les parcours et interactions individuels des utilisateurs dans le contexte plus large de votre expérience, même lorsque vous effectuez le bucketing à un niveau supérieur (comme un compte) ou sur plusieurs appareils/sessions. Vos données de visiteur d'origine restent intactes pour des rapports complets.

#### Exigences techniques

Pour utiliser efficacement une clé de bucketing personnalisée :

* La clé doit être une `std::string`.
* Elle doit être unique pour l'entité que vous souhaitez bucketer (par exemple, si vous utilisez un `user_id`, l'ID de chaque utilisateur doit être unique).
* La clé doit être disponible pour le SDK au moment exact où il évalue la décision du feature flag pour cet utilisateur ou cette requête.

### Conditions de ciblage

Les SDK Kameleoon prennent en charge une variété de conditions de ciblage prédéfinies que vous pouvez utiliser pour cibler les utilisateurs dans vos campagnes. Pour la liste des conditions prises en charge par ce SDK, consultez [utiliser l'historique de visite pour cibler les utilisateurs](/fr/developer-docs/feature-experimentation/targeting-and-segmentation/native-segmentation).

Vous pouvez également utiliser vos propres [données externes pour cibler les utilisateurs](/fr/developer-docs/apis/data-api-rest/tutorials/storing-and-retrieving-external-data-to-target-users).

### Expérimentation cross-device

Pour prendre en charge les visiteurs qui accèdent à une application depuis plusieurs appareils, Kameleoon permet la synchronisation des données de visiteur précédemment collectées sur chacun des appareils du visiteur et la réconciliation de leur historique de visites entre les appareils grâce à l'expérimentation cross-device. Des études de cas et des informations détaillées sur la façon dont Kameleoon gère les données entre les appareils sont disponibles dans l'[article sur l'expérimentation cross-device](/fr/developer-docs/cross-device-experimentation).

#### Synchronisation des custom data entre les appareils

Bien que la synchronisation par mapping personnalisé aligne les données de visiteur entre les appareils, elle n'est pas toujours nécessaire. Voici deux scénarios où la synchronisation par mapping personnalisé n'est pas requise :

**Même ID utilisateur sur tous les appareils**
Si vous utilisez le même ID utilisateur de manière cohérente sur tous les appareils, le SDK gère la synchronisation automatiquement sans synchronisation par mapping personnalisé. Il suffit d'appeler la méthode `get_remote_visitor_data()` lorsque vous souhaitez synchroniser les données collectées entre plusieurs appareils.

**Instances multi-serveurs avec des ID cohérents**
Dans les configurations complexes impliquant plusieurs serveurs (par exemple, des instances de serveurs distribuées), où le même ID utilisateur est disponible sur tous les serveurs, la synchronisation entre serveurs (avec `get_remote_visitor_data()`) est suffisante sans synchronisation supplémentaire par mapping personnalisé.

Les clients qui ont besoin de données supplémentaires peuvent se référer à la description de la méthode [`get_remote_visitor_data()`](#get_remote_visitor_data) pour plus d'informations. Dans le code ci-dessous, il est supposé que vous utilisez le même identifiant unique (dans ce cas, le `visitor_code`, également appelé `userId`) de manière cohérente entre les deux appareils pour une récupération précise des données.

<Note>
  Si vous souhaitez synchroniser les données collectées en temps réel, vous devez choisir la portée **Visitor** pour vos custom data.
</Note>

```cpp title="Device A" theme={null}
// In this example, a Custom data with index `90` was set to "Visitor" scope in Kameleoon.
using namespace kameleoon;

constexpr uint32_t VISITOR_SCOPE_CUSTOM_DATA_INDEX = 90;

client.add_data(visitor_code, {CustomData(VISITOR_SCOPE_CUSTOM_DATA_INDEX, {"your data"})});

client.flush_instant(visitor_code);
```

```cpp title="Device B" theme={null}
// Before working with the data, call the `get_remote_visitor_data` method.
client.get_remote_visitor_data(visitor_code);

// After calling the method, the SDK on Device B will have access to CustomData of Visitor scope defined on Device A.
// So, "your data" will be available for targeting and tracking the visitor.
```

#### Utiliser les custom data pour la fusion de sessions

L'[expérimentation cross-device](/fr/developer-docs/cross-device-experimentation) permet de combiner l'historique d'un visiteur sur chacun de ses appareils (réconciliation d'historique). La réconciliation d'historique permet de fusionner différentes sessions de visiteurs en une seule. Pour réconcilier l'historique des visites, utilisez [`CustomData`](#customdata) pour fournir un identifiant unique pour le visiteur. Pour plus d'informations, consultez la [documentation dédiée](/fr/developer-docs/cross-device-experimentation/#activer-la-réconciliation-d’historique-cross-device).

Après avoir activé la réconciliation cross-device, l'appel à [`get_remote_visitor_data()`](#get_remote_visitor_data) avec le paramètre `userId` récupère toutes les données connues pour un utilisateur donné.

Les sessions avec le même identifiant voient toujours la même variation dans une expérience. Dans la vue Visiteur des pages de résultats de votre expérience, ces sessions apparaîtront comme un seul visiteur.

La configuration du SDK garantit que les sessions associées voient toujours la même variation de l'expérience. Cependant, il existe certaines limites concernant l'allocation des variations cross-device. La [documentation sur l'expérimentation cross-device](/fr/developer-docs/cross-device-experimentation#points-critiques-et-informations-pratiques) décrit ces limites.

Suivez le guide [activer la réconciliation d'historique cross-device](#expérimentation-cross-device) pour configurer vos custom data sur la plateforme Kameleoon.

Ensuite, vous pouvez utiliser le SDK normalement. Les méthodes suivantes peuvent être utiles dans le contexte de la fusion de sessions :

* `get_remote_visitor_data()` avec la donnée `UniqueIdentifier(true)` ajoutée - pour récupérer les données de tous les visiteurs liés.
* [`track_conversion()`](#track_conversion) ou [`flush()`](#flush) avec la donnée `UniqueIdentifier(true)` ajoutée - pour suivre des données pour un visiteur spécifique associé à un autre visiteur.

<Tip>
  Comme les custom data que vous utilisez comme identifiant nécessitent la **portée Visitor**, vous devez utiliser la [synchronisation cross-device des custom data](/fr/developer-docs/cross-device-experimentation) pour récupérer l'identifiant avec la méthode [`get_remote_visitor_data()`](#get_remote_visitor_data) sur chaque appareil.
</Tip>

Voici un exemple d'utilisation des custom data pour la fusion de sessions.

```cpp theme={null}
// In this example, 91 represents the Custom Data's index configured as a unique identifier in Kameleoon.
using namespace kameleoon;

constexpr uint32_t MAPPING_INDEX = 91;
const std::string FEATURE_KEY = "ff123";

const std::string anonymous_visitor_code = "anonymous-visitor";
const std::string user_id = "authenticated-user";

// 1. Before the visitor is authenticated

// Retrieve the variation for an unauthenticated visitor.
// Assume anonymousVisitorCode is the randomly generated ID for that visitor.
Variation anonymous_variation = client.get_variation(anonymous_visitor_code, FEATURE_KEY);

// 2. After the visitor is authenticated

// Assume `userId` is the visitor code of the authenticated visitor.
client.add_data(anonymous_visitor_code, {CustomData(MAPPING_INDEX, {user_id})});
client.flush_instant(anonymous_visitor_code);

// Indicate that `userId` is a unique identifier.
client.add_data(user_id, {UniqueIdentifier{true}});

// 3. After the visitor was authorized

// Retrieve the variation for the `userId`, which will match the anonymous visitor code's variation.
Variation user_variation = client.get_variation(user_id, FEATURE_KEY);
bool is_same_variation = user_variation.key == anonymous_variation.key; // true

// `userId` and `anonymousVisitorCode` are now linked and can be tracked as a single visitor.
client.track_conversion(user_id, 123);

// Additionally, the linked visitors share all fetched previously tracked remote data.
client.get_remote_visitor_data(user_id);
```

Dans cet exemple, l'application a une page de connexion. Comme l'ID utilisateur est inconnu au moment de la connexion, l'application utilise un identifiant visiteur anonyme généré par la méthode [`get_visitor_code()`](#get_visitor_code). Après la connexion de l'utilisateur, l'application associe le visiteur anonyme à l'ID utilisateur et l'utilise comme identifiant unique pour le visiteur.

### Journalisation

Le SDK génère des journaux pour refléter divers processus internes et problèmes.

#### Niveaux de journalisation

Le SDK permet de limiter la journalisation par niveau de journalisation.

```cpp theme={null}
#include "kameleoon/logging.hpp"

using namespace kameleoon;

// The `None` log level does not allow logging.
KameleoonLogger::set_log_level(LogLevel::None);

// The `Error` log level only allows logging issues that may affect the SDK's primary behaviour.
KameleoonLogger::set_log_level(LogLevel::Error);

// The `Warning` log level allows logging issues which may require attention.
// It extends the `Error` log level.
// The `Warning` log level is the default log level.
KameleoonLogger::set_log_level(LogLevel::Warning);

// The `Info` log level allows logging general information on the SDK's internal processes.
// It extends the `Warning` log level.
KameleoonLogger::set_log_level(LogLevel::Info);

// The `Debug` level logs additional details about the SDK's internal processes and extends the `Info` level
// with more granular diagnostic output.
// This information is not intended for end-user interpretation but can be sent to our support team
// to assist with internal troubleshooting.
KameleoonLogger::set_log_level(LogLevel::Debug);
```

#### Gestion personnalisée des journaux

Le SDK écrit ses journaux dans la sortie console par défaut. Ce comportement peut être remplacé.

<Note>
  Le SDK limite la journalisation par niveau de journalisation séparément de la logique de gestion des journaux.
</Note>

```cpp theme={null}
#include "kameleoon/logging.hpp"

#include <spdlog/spdlog.h>

using namespace kameleoon;

// Log level filtering is applied separately from log handling logic.
// The custom logger will only receive logs that meet or exceed the specified log level.
// Ensure the log level is set correctly.
KameleoonLogger::set_log_level(LogLevel::Debug); // Optional; defaults to `LogLevel::Warning`.

// The logger is any callable accepting the log level and the message.
// It may be invoked from SDK threads, so it must be thread-safe and must not throw.
KameleoonLogger::set_logger([](LogLevel level, const std::string& message) {
    switch (level) {
    case LogLevel::Error:   spdlog::error(message); break;
    case LogLevel::Warning: spdlog::warn(message); break;
    case LogLevel::Info:    spdlog::info(message); break;
    case LogLevel::Debug:   spdlog::debug(message); break;
    case LogLevel::None:    break;
    }
});

// Passing an empty logger restores the default logger of the SDK, which writes to stdout.
KameleoonLogger::set_logger({});
```

## Référence

Ceci est la documentation de référence complète du SDK C++.

### Initialisation

#### create()

Pour utiliser le SDK, créez un `KameleoonClient` avec `KameleoonClientFactory::create()`, soit à partir d'une structure `KameleoonClientConfig`, soit à partir d'un fichier de configuration JSON.

Les clients sont mis en cache par site code et environnement : des appels répétés à `create()` avec le même site code et le même environnement renvoient des clients reposant sur la même instance SDK sous-jacente, et la configuration du premier appel prévaut.

<Tabs>
  <Tab title="create(config struct)">
    ```cpp theme={null}
    #include "kameleoon/kameleoon.hpp"

    using namespace kameleoon;

    KameleoonClientConfig config{
        .client_id = "<client-id>",                  // mandatory
        .client_secret = "<client-secret>",          // mandatory
        .refresh_interval_minutes = 60,              // optional (60 minutes by default)
        .session_duration_minutes = 30,              // optional (30 minutes by default)
        .default_timeout_millis = 10'000,            // optional (10000 ms by default)
        .tracking_interval_millis = 1'000,           // optional (1000 ms by default)
        .proxy_host = "http://192.168.0.25:8080",    // optional
        .environment = "development",                // optional
        .top_level_domain = ".example.com",          // mandatory if you use hybrid mode (engine or web experiments)
        .network_domain = "example.com",             // optional
    };

    KameleoonClient client = KameleoonClientFactory::create(site_code, config);
    ```

    ##### Paramètres

    | Nom | Type | Description |
    | - | - | - |
    | `site_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Clé unique du projet Kameleoon utilisé par le SDK. |
    | `config` <Badge color="red" size="sm">obligatoire</Badge> | `KameleoonClientConfig` | Structure de configuration du SDK. |
  </Tab>

  <Tab title="create(config file)">
    ```cpp theme={null}
    #include "kameleoon/kameleoon.hpp"

    using namespace kameleoon;

    KameleoonClient client = KameleoonClientFactory::create("a8st4f59bj", "/etc/kameleoon/client-cpp.json");
    ```

    ##### Paramètres

    | Nom | Type | Description |
    | - | - | - |
    | `site_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Clé unique du projet Kameleoon utilisé par le SDK. |
    | `config_path` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Chemin vers le fichier de configuration JSON. |
  </Tab>
</Tabs>

##### Valeur de retour

| Type | Description |
| - | - |
| `KameleoonClient` | Une instance de client. Le client n'est pas prêt à évaluer des feature flags tant que [`initialize()`](#initialize) n'est pas terminé. |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Le site code est vide, `client_id` ou `client_secret` est vide, ou le fichier de configuration ne peut pas être lu ou analysé. Le message d'erreur indique la cause exacte. |
| `ErrorCode::Internal` | La bibliothèque `libkameleoon_ffi` chargée ne correspond pas à la version avec laquelle le SDK a été compilé. |

#### initialize()

Utilisez `initialize()` lorsque votre application doit attendre que le client Kameleoon ait terminé son initialisation avant d'évaluer des feature flags.

L'appel renvoie le résultat de la récupération de la configuration : il se termine avec succès lorsque le client finit de s'initialiser, et échoue si la récupération initiale de la configuration échoue avant que le client ne soit prêt. Les nouvelles tentatives en arrière-plan continuent après ce premier échec. Une fois qu'une nouvelle tentative réussit, les appels suivants renvoient un résultat positif. Si aucun résultat d'initialisation n'est disponible avant l'expiration du délai d'attente, l'appel échoue. Si vous ne fournissez pas de valeur `timeout`, le SDK utilise le délai d'attente par défaut défini par [`default_timeout_millis`](#configuration-supplémentaire).

<Tip>
  Appelez `initialize()` une seule fois au démarrage de l'application pour attendre que le SDK ait chargé sa configuration ou que le délai d'attente expire. À chaque requête entrante, utilisez [`is_ready()`](#is_ready) comme garde non bloquante avant d'évaluer des feature flags. Même si `initialize()` échoue, le SDK continue de retenter la récupération de la configuration en arrière-plan, de sorte que `is_ready()` commence à renvoyer `true` dès qu'une nouvelle tentative réussit.
</Tip>

```cpp theme={null}
#include <chrono>

// Initializes the client using the configured default timeout (blocking).
client.initialize();

// Initializes the client with a custom timeout of 5 seconds (blocking).
client.initialize(std::chrono::seconds(5));

// Initializes the client without blocking; the completion receives the outcome.
client.initialize_async(std::chrono::seconds(5), [](std::exception_ptr error) {
    if (error) {
        // Initialization failed: rethrow `error` to get the `KameleoonException`.
        return;
    }
    // The client is ready.
});

// C++20 coroutines
co_await client.co_initialize(std::chrono::seconds(5));
```

##### Paramètres

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `timeout` <Badge color="green" size="sm">facultatif</Badge> | `std::optional<std::chrono::milliseconds>` | Le temps maximal d'attente d'un résultat d'initialisation. | `default_timeout_millis` |

##### Valeur de retour

| Type | Description |
| - | - |
| `void` | Retourne une fois que le SDK est prêt. Lève une `KameleoonException` si la récupération initiale de la configuration échoue ou si aucun résultat d'initialisation n'est disponible avant l'expiration du délai d'attente. |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Aucun résultat d'initialisation n'était disponible avant l'expiration du délai d'attente. |
| `ErrorCode::Network` | La récupération initiale de la configuration a échoué en raison d'une erreur réseau ou d'un statut HTTP inattendu. Le SDK continue de réessayer en arrière-plan, donc un appel ultérieur réussit dès qu'une nouvelle tentative aboutit. |
| `ErrorCode::InvalidArgument` | Le `timeout` fourni est nul ou négatif. |

#### is\_ready()

`is_ready()` vérifie si le SDK est prêt à être utilisé, c'est-à-dire que sa configuration a été chargée avec succès. Contrairement à [`initialize()`](#initialize), cette méthode retourne immédiatement sans bloquer ni lever d'exception.

<Tip>
  * Une fois que le SDK est prêt, il le reste. Si un rafraîchissement ultérieur de la configuration échoue, le SDK continue d'utiliser la configuration précédemment téléchargée et ne repasse pas à un état non prêt.
  * Appelez `initialize()` une seule fois au démarrage de l'application pour attendre que le SDK ait chargé sa configuration ou que le délai d'attente expire. À chaque requête entrante, utilisez [`is_ready()`](#is_ready) comme garde non bloquante avant d'évaluer des feature flags. Même si `initialize()` échoue, le SDK continue de retenter la récupération de la configuration en arrière-plan, de sorte que `is_ready()` commence à renvoyer `true` dès qu'une nouvelle tentative réussit.
</Tip>

```cpp theme={null}
if (client.is_ready()) {
    // The client is ready
}
```

##### Valeur de retour

| Type | Description |
| - | - |
| `bool` | `true` si le SDK a été initialisé avec succès ; `false` sinon (y compris lorsque l'initialisation est encore en cours ou a échoué). |

#### forget()

Supprime le client SDK mis en cache associé au `site_code` spécifié, de sorte que le prochain appel à `create()` avec le même site code et le même environnement en crée un nouveau.

`forget()` ne supprime que la référence de la factory. Chaque `KameleoonClient` créé pour ce site code maintient l'instance SDK sous-jacente (ainsi que son thread de travail, son polling et son tracking) en vie jusqu'à sa destruction, et les opérations asynchrones en cours la maintiennent en vie jusqu'à ce que leurs completions se terminent. Pour libérer les ressources d'arrière-plan, appelez `forget()` et détruisez toutes les instances `KameleoonClient` de ce site code.

```cpp theme={null}
using namespace kameleoon;

// Removes the cached client created for the given site code without an environment
KameleoonClientFactory::forget("a8st4f59bj");

// Removes the cached client for the given site code and environment
KameleoonClientFactory::forget("a8st4f59bj", "production");
```

##### Paramètres

| Nom | Type | Description |
| - | - | - |
| `site_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique du projet Kameleoon. |
| `environment` <Badge color="green" size="sm">facultatif</Badge> | `std::string` | Environnement avec lequel le client a été créé. Un client créé avec un `environment` n'est supprimé que lorsque la même valeur est passée ici. |

### Feature flags et variations

#### is\_feature\_active()

* 📨 *Envoie des données de tracking à Kameleoon (selon l'option `track`)*

Détermine si un feature flag est actif pour un utilisateur donné.

Si le visiteur n'a pas encore été évalué pour ce feature flag, le SDK évalue les règles de ciblage et renvoie le résultat. Si le visiteur a déjà une évaluation stockée pour le feature, le SDK réutilise le résultat existant pour assurer la cohérence.

<Note>
  Kameleoon utilise le tracking pour compter les sessions et les visiteurs lorsque vous appelez certaines méthodes, telles que `is_feature_active()`, `get_variation()` ou `get_variations()`.

  Utilisez la valeur par défaut `true` pour le paramètre `track` lorsque vous exposez les visiteurs à une variation et devez les compter. Définissez le paramètre `track` sur `false` uniquement si vous appelez ces méthodes avant d'exposer les visiteurs.

  Par exemple, si vous appelez `get_variations()` pour récupérer toutes les variations avant d'exposer les visiteurs, définissez le paramètre `track` sur `false`. Ce réglage empêche Kameleoon de compter prématurément une session. Vous pouvez ensuite déclencher le tracking plus tard, lorsque vous exposez explicitement le visiteur.

  Kameleoon envoie les données de tracking toutes les secondes par défaut. Vous pouvez configurer cet intervalle jusqu'à 5 secondes à l'aide de l'option de configuration de l'intervalle de tracking. Kameleoon regroupe les événements de tracking en une seule session tant que l'intervalle entre les événements est inférieur à 30 minutes. Si plus de 30 minutes s'écoulent entre les événements de tracking, Kameleoon compte les événements comme des sessions distinctes. Une visite apparaît dans vos rapports 30 minutes après le dernier événement enregistré dans la session.
</Note>

<Warning>
  La méthode `is_feature_active()` évalue le variant servi, pas l'état du flag principal. Si vous excluez des règles, la méthode utilise l'état par défaut **Then, for everyone else serve**. Si vous sélectionnez **Off** pour cet état par défaut, la méthode renvoie toujours `false` même lorsque le feature flag principal est **On**.
</Warning>

```cpp theme={null}
using namespace kameleoon;

const std::string feature_key = "new_checkout";

// Evaluates the feature flag and sends tracking data (default behavior)
bool active = client.is_feature_active(visitor_code, feature_key);

// Evaluates the feature flag without sending tracking data
bool active_without_tracking = client.is_feature_active(
    visitor_code, feature_key, IsFeatureActiveOptions{.track = false});
```

##### Paramètres

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique de l'utilisateur. | |
| `feature_key` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Clé du feature à évaluer pour l'utilisateur. | |
| `options` <Badge color="green" size="sm">facultatif</Badge> | `IsFeatureActiveOptions` | Structure d'options avec un seul champ `track` (`bool`) qui active ou désactive le tracking de l'évaluation du feature. | `track = true` |

##### Valeur de retour

| Type | Description |
| - | - |
| `bool` | Indique si le feature flag est actif pour le `visitor_code` spécifié. |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::FeatureNotFound` | Exception indiquant que la clé de feature demandée n'a pas été trouvée dans la configuration interne du SDK. Cela signifie généralement que le feature flag n'est pas activé dans l'application Kameleoon (mais que le code implémentant le feature est déjà déployé dans l'application). |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |

#### get\_variation()

* 📨 *Envoie des données de tracking à Kameleoon (selon le paramètre `track`)*

Récupère la [`Variation`](#variation) attribuée à un visiteur donné pour un feature flag spécifique.

Cette méthode prend un `visitor_code` et une `feature_key` comme arguments obligatoires. L'argument `track` est facultatif et vaut `true` par défaut.

Elle renvoie la `Variation` attribuée au visiteur. Si le visiteur n'est associé à aucune règle du feature flag, la méthode renvoie la `Variation` par défaut du feature flag donné.

Assurez-vous que votre code inclut une gestion d'erreurs appropriée pour gérer les exceptions potentielles.

<Note>
  La variation par défaut fait référence à la variation attribuée à un visiteur lorsqu'il ne correspond à aucune règle de diffusion prédéfinie pour un feature flag. En d'autres termes, il s'agit de la variation de repli appliquée à tous les utilisateurs qui ne sont pas ciblés par des règles spécifiques. Elle est représentée par la variation de la section "Then, for everyone else..." dans l'interface de gestion.
</Note>

```cpp theme={null}
using namespace kameleoon;

const std::string feature_key = "new_checkout";

// Retrieves the variation assigned to the visitor (with tracking enabled by default)
Variation variation = client.get_variation(visitor_code, feature_key);

// Retrieves the variation without sending tracking data
Variation variation_without_tracking = client.get_variation(
    visitor_code, feature_key, GetVariationOptions{.track = false});
```

##### Paramètres

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique du visiteur. | |
| `feature_key` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Clé du feature que vous souhaitez exposer à un visiteur. | |
| `track` <Badge color="green" size="sm">facultatif</Badge> | `bool` | Paramètre facultatif pour activer ou désactiver le tracking de l'évaluation du feature. | `true` |

<Note>
  Le paramètre facultatif `track` est passé comme champ `track` d'une structure `GetVariationOptions`.
</Note>

##### Valeur de retour

| Type | Description |
| - | - |
| `Variation` | La [`Variation`](#variation) attribuée à un visiteur donné pour un feature flag spécifique. |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |
| `ErrorCode::FeatureNotFound` | Exception indiquant que la clé de feature demandée n'a pas été trouvée dans la configuration interne du SDK. Cela signifie généralement que le feature flag n'est pas activé dans l'application Kameleoon (mais que le code implémentant le feature est déjà déployé dans l'application). |
| `ErrorCode::FeatureEnvironmentDisabled` | Exception indiquant que le feature flag est désactivé pour l'environnement actuel du visiteur (par exemple, production, staging ou development). |
| `ErrorCode::FeatureEvaluationBlocked` | Exception indiquant que l'évaluation du feature est bloquée. La raison est décrite dans le message d'erreur. Cela se produit généralement en raison des restrictions RGPD lorsque le visiteur n'a pas donné son consentement légal. |

#### get\_variations()

* 📨 *Envoie des données de tracking à Kameleoon (selon le paramètre `track`)*

Récupère une map d'objets [`Variation`](#variation) attribués à un visiteur donné pour l'ensemble des feature flags.

Cette méthode parcourt tous les feature flags disponibles et renvoie la `Variation` attribuée pour chaque flag associé au visiteur spécifié. Elle prend `visitor_code` comme argument obligatoire, tandis que `only_active` et `track` sont facultatifs.

* Si vous définissez `only_active` sur `true`, la méthode `get_variations()` renvoie les variations des feature flags uniquement si le visiteur n'est pas bucketé avec la variation `off`.
* Le paramètre `track` contrôle si la méthode effectue le tracking des attributions de variations. Par défaut, il vaut `true`. S'il vaut `false`, la méthode n'effectue pas le tracking des attributions de variations.

La map renvoyée est constituée des clés des feature flags comme clés et de leur `Variation` correspondante comme valeurs. Si le SDK n'attribue aucune variation pour un feature flag, la méthode renvoie la `Variation` par défaut de ce flag.

Implémentez une gestion d'erreurs appropriée pour gérer les exceptions potentielles.

<Note>
  La variation par défaut fait référence à la variation attribuée à un visiteur lorsqu'il ne correspond à aucune règle de diffusion prédéfinie pour un feature flag. En d'autres termes, il s'agit de la variation de repli appliquée à tous les utilisateurs qui ne sont pas ciblés par des règles spécifiques. Elle est représentée par la variation de la section "Then, for everyone else..." dans l'interface de gestion.
</Note>

```cpp theme={null}
using namespace kameleoon;

// Retrieves all variations assigned to the visitor (with default options)
std::unordered_map<std::string, Variation> variations = client.get_variations(visitor_code);

// Retrieves only active variations for the visitor
auto only_active_variations = client.get_variations(
    visitor_code, GetVariationsOptions{.only_active = true});

// Retrieves variations without sending tracking data
auto variations_without_tracking = client.get_variations(
    visitor_code, GetVariationsOptions{.track = false});
```

##### Paramètres

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique du visiteur. | |
| `only_active` <Badge color="green" size="sm">facultatif</Badge> | `bool` | Paramètre facultatif indiquant s'il faut renvoyer les variations des feature flags actifs (`true`) ou de tous les feature flags (`false`). | `false` |
| `track` <Badge color="green" size="sm">facultatif</Badge> | `bool` | Paramètre facultatif pour activer ou désactiver le tracking de l'évaluation du feature. | `true` |

<Note>
  Les paramètres facultatifs `only_active` et `track` sont passés comme champs d'une structure `GetVariationsOptions`.
</Note>

##### Valeur de retour

| Type | Description |
| - | - |
| `std::unordered_map<std::string, Variation>` | Map qui contient les objets [`Variation`](#variation) attribués des feature flags, avec les clés des features correspondants comme clés. |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |

#### set\_forced\_variation()

Cette méthode vous permet d'attribuer de manière programmatique une [`Variation`](#variation) spécifique à un utilisateur, en contournant le processus d'évaluation standard. La méthode est particulièrement utile pour les expériences contrôlées où la logique d'évaluation habituelle n'est pas requise ou doit être ignorée. Elle peut également être utile dans des scénarios comme le débogage ou les tests personnalisés.

Lorsque vous définissez une variation **forcée**, elle remplace la logique d'évaluation en temps réel de Kameleoon. Le SDK ignore des processus comme la segmentation, les conditions de ciblage et les calculs algorithmiques. Pour préserver la segmentation et les conditions de ciblage pendant une expérience, définissez plutôt `force_targeting=false`.

<Info>
  Les variations **simulées** ont toujours la priorité dans l'ordre d'exécution. Si un calcul de variation **simulée** démarre, le SDK le traite et le termine entièrement en premier.
</Info>

Kameleoon traite une variation forcée de la même manière qu'une variation évaluée. Elle est suivie dans les analytics et stockée dans le contexte utilisateur comme toute variation évaluée standard, garantissant la cohérence des rapports.

La méthode peut lever des exceptions dans certaines conditions (par exemple, paramètres invalides, contexte utilisateur ou problèmes internes). Une gestion appropriée des exceptions est essentielle pour garantir que votre application reste stable et résiliente.

<Warning>
  Il est important de distinguer les variations **forcées** des variations **[simulées](#get_visitor_code)** :

  * **Variations forcées** : sont spécifiques à une expérience individuelle.
  * **Variations simulées** : affectent le résultat global du **feature flag**.
</Warning>

```cpp theme={null}
using namespace kameleoon;

const uint32_t experiment_id = 202387;

// Forces the visitor into "variation_2" for the given experiment
client.set_forced_variation(visitor_code, experiment_id, "variation_2");

// Removes any previously forced variation for the visitor in this experiment
client.set_forced_variation(visitor_code, experiment_id, std::nullopt);

// Forces the visitor into "variation_2" with custom options
// In this case, targeting rules are respected (force_targeting = false)
client.set_forced_variation(
    visitor_code, experiment_id, "variation_2", SetForcedVariationOptions{.force_targeting = false});
```

##### Paramètres

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique du visiteur. | |
| `experiment_id` <Badge color="red" size="sm">obligatoire</Badge> | `uint32_t` | **ID de l'expérience** que le SDK cible et sélectionne pendant le processus d'évaluation. | |
| `variation_key` <Badge color="red" size="sm">obligatoire</Badge> | `std::optional<std::string>` | **Clé de variation** correspondant à une `Variation` que le SDK force comme valeur renvoyée pour l'expérience. Si la valeur est `std::nullopt`, la variation forcée sera réinitialisée. | |
| `force_targeting` <Badge color="green" size="sm">facultatif</Badge> | `bool` | Indique si le SDK force et ignore le ciblage pour l'expérience (`true`) ou l'applique comme dans le processus d'évaluation standard (`false`). | `true` |

<Note>
  Le paramètre facultatif `force_targeting` est passé comme champ `force_targeting` d'une structure `SetForcedVariationOptions`.
</Note>

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |
| `ErrorCode::FeatureExperimentNotFound` | Exception indiquant que l'ID d'expérience demandé n'est pas dans la configuration interne du SDK. Ce comportement est généralement normal et signifie que l'expérience correspondant à la règle n'est pas encore active côté Kameleoon. |
| `ErrorCode::FeatureVariationNotFound` | Exception indiquant que la clé (ID) de variation demandée n'est pas dans la configuration interne du SDK. Ce comportement est généralement normal et signifie que l'expérience correspondant à la variation n'est pas encore active côté Kameleoon. |

#### evaluate\_audiences()

* 📨 *Envoie des données de tracking à Kameleoon*

Cette méthode évalue les visiteurs par rapport à tous les segments Audiences Explorer disponibles et effectue le tracking de ceux qui correspondent.

Appelez `evaluate_audiences()` **après avoir défini ou mis à jour toutes les données de visiteur pertinentes**, et **juste avant** de récupérer une variation de feature ou de vérifier un feature flag. Cette approche garantit que Kameleoon évalue le visiteur sur la base des données les plus récentes disponibles, permettant une attribution d'audience précise basée sur tous les critères.

Après avoir appelé cette méthode, vous pouvez effectuer une analyse détaillée des performances des segments dans Audiences Explorer.

```cpp theme={null}
client.evaluate_audiences(visitor_code);
```

##### Paramètres

| Nom | Type | Description |
| - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique du visiteur. |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |

<Info>
  Dans la plupart des cas, vous n'avez besoin de gérer que l'erreur de base, `KameleoonException`, comme le montre l'exemple. Cependant, si différents types d'erreurs nécessitent une réponse, gérez chacun séparément en fonction des exigences spécifiques. De plus, pour une fiabilité accrue, vous pouvez gérer les erreurs générales du langage en incluant `std::exception`.
</Info>

#### get\_datafile()

<Tip>
  Pour évaluer tous les feature flags, utilisez [`get_variations()`](#get_variations). Cette méthode est plus efficace que d'appeler `DataFile` et d'itérer sur les flags avec [`get_variation()`](#get_variation).
</Tip>

Renvoie la configuration actuelle du SDK sous la forme d'un objet [`DataFile`](#datafile).

Le `DataFile` renvoyé est une copie de la configuration actuelle : il ne change pas lorsque le SDK rafraîchit sa configuration.

```cpp theme={null}
using namespace kameleoon;

DataFile datafile = client.get_datafile();
```

##### Valeur de retour

| Type | Description |
| - | - |
| `DataFile` | Le [`DataFile`](#datafile) contenant la configuration du SDK |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |

### Données de visiteur

#### get\_visitor\_code()

Utilisez `get_visitor_code()` pour obtenir le `visitor_code` Kameleoon du visiteur actuel. La méthode fonctionne avec tout stockage de cookies qui implémente l'interface `CookieAccessor`.

La logique d'implémentation est la suivante :

1. Le SDK vérifie si un cookie `kameleoonVisitorCode` est déjà disponible via l'accesseur fourni.
2. Si le cookie est absent, le SDK utilise `default_visitor_code` lorsque vous en fournissez un.
3. Sinon, le SDK génère un nouveau visitor code et le stocke via l'accesseur.

Pour plus d'informations, consultez l'[expérimentation hybride](/fr/developer-docs/feature-experimentation/get-started/hybrid-experimentation/).

<Warning>
  Si vous fournissez votre propre `visitor_code`, son unicité doit être garantie de votre côté. Notez également que la longueur du `visitor_code` est limitée à `255` caractères.
</Warning>

<Info>
  La méthode `get_visitor_code()` vous permet de définir des variations **simulées** pour un visiteur. Lorsque les cookies (d'une **requête** ou d'un **document**) contiennent la clé `kameleoonSimulationFFData`, la méthode lit le cookie et stocke les variations simulées pour ce visiteur ; sa valeur de retour ne change pas. Les évaluations de features ultérieures pour le visiteur, telles que [`get_variation()`](#get_variation) et [`is_feature_active()`](#is_feature_active), contournent alors le processus d'évaluation standard et renvoient la [`Variation`](#variation) simulée en fonction des données fournies.

  Vous pouvez appliquer les simulations de deux manières :

  * **Automatiquement (recommandé) :** si vous utilisez Kameleoon Web Experimentation ou le SDK en [mode hybride](/fr/developer-docs/feature-experimentation/get-started/hybrid-experimentation#lier-les-expériences-de-feature-au-code-de-suivi-front-end), Kameleoon crée le cookie automatiquement lorsque vous simulez l'affichage d'un variant à l'aide du [panneau de simulation](/fr/user-manual/experimentation/feature-experimentation/using-the-rollout-planner/validation-and-rollback/using-simulation-mode).
  * **Manuellement :** définissez le cookie `kameleoonSimulationFFData` manuellement.

  Il est important de distinguer les variations **simulées** des variations **[forcées](#set_forced_variation)** :

  * **Variations simulées** : affectent le résultat global du **feature flag**.
  * **Variations forcées** : sont spécifiques à une expérience individuelle.

  ⚙️ **Configuration manuelle**

  Assurez-vous que le cookie `kameleoonSimulationFFData` respecte ce format :

  * `kameleoonSimulationFFData={"featureKey":{"expId":10,"varId":20}}` : simule la variation avec le `varId` de l'expérience `expId` pour la `featureKey` donnée.
  * `kameleoonSimulationFFData={"featureKey":{"expId":0}}` : simule la variation par défaut (définie dans la section **Then, for everyone else in Production, serve**) pour la `featureKey` donnée.

  ⚠️ Pour garantir que la valeur du cookie fonctionne correctement, encodez-la en tant que composant URI à l'aide d'une méthode telle que [`encodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent).
</Info>

##### Interface `CookieAccessor`

Implémentez `kameleoon::CookieAccessor` pour relier les lectures et écritures de cookies du SDK à votre framework HTTP :

| Méthode | Description |
| - | - |
| `std::optional<std::string> get(const std::string& key)` | Renvoie la valeur du cookie pour `key`, ou `std::nullopt` lorsque le cookie est absent. |
| `void set(const std::string& key, const std::string& value, uint32_t max_age, std::optional<std::string> top_level_domain)` | Stocke le cookie dans la réponse, avec le `max_age` (en secondes) et, lorsqu'il est présent, le `top_level_domain` comme domaine du cookie. |

<Note>
  * `get()` doit renvoyer un cookie déjà écrit via `set()` dans la réponse en priorité par rapport au cookie de requête du même nom. Le SDK ne conserve aucun état de cookie entre les appels, c'est donc ce qui permet à un second appel de `get_visitor_code()` au sein de la même requête de renvoyer le code écrit par le premier au lieu d'en générer un nouveau.
  * Les surcharges sont invoquées depuis l'intérieur du SDK et ne doivent pas lever d'exception. Une exception s'échappant de `get()` est traitée comme un cookie absent. Les valeurs des cookies doivent être de l'UTF-8 valide.
</Note>

<Tabs>
  <Tab title="Custom">
    ```cpp theme={null}
    #include "kameleoon/kameleoon.hpp"

    #include <optional>
    #include <string>
    #include <unordered_map>

    using namespace kameleoon;

    // A cookie accessor over the cookies of an HTTP request. Cookies written by the
    // SDK are collected in `response_` and must be emitted as `Set-Cookie` headers.
    class RequestCookies final : public CookieAccessor {
    public:
        explicit RequestCookies(std::unordered_map<std::string, std::string> request)
            : request_(std::move(request)) {}

        void set(const std::string& key, const std::string& value, uint32_t max_age,
                 std::optional<std::string> top_level_domain) override {
            response_[key] = value;
            // Emit a `Set-Cookie` header with `max_age` and `top_level_domain` here.
        }

        std::optional<std::string> get(const std::string& key) override {
            // Prefer a cookie already written to the response in this request.
            if (const auto it = response_.find(key); it != response_.end()) return it->second;
            if (const auto it = request_.find(key); it != request_.end()) return it->second;
            return std::nullopt;
        }

    private:
        std::unordered_map<std::string, std::string> request_;
        std::unordered_map<std::string, std::string> response_;
    };

    RequestCookies cookies{parse_request_cookies(request)};

    // Generate or retrieve a visitor code using an auto-generated value
    std::string visitor_code = client.get_visitor_code(cookies);
    // Generate or retrieve a visitor code using a predefined user ID
    std::string visitor_code_with_default = client.get_visitor_code(cookies, "user_id");
    ```
  </Tab>

  <Tab title="Drogon">
    ```cpp theme={null}
    #include "kameleoon/kameleoon.hpp"

    #include <drogon/drogon.h>

    #include <map>
    #include <optional>
    #include <string>

    using namespace kameleoon;

    // Reads cookies from the request Drogon already parsed and collects the
    // SDK's cookies for the response.
    class DrogonCookieAccessor final : public CookieAccessor {
    public:
        explicit DrogonCookieAccessor(const drogon::HttpRequestPtr& request) : request_(request) {}

        void set(const std::string& key, const std::string& value, uint32_t max_age,
                 std::optional<std::string> top_level_domain) override {
            drogon::Cookie cookie{key, value};
            cookie.setPath("/");
            cookie.setMaxAge(static_cast<int>(max_age));
            if (top_level_domain.has_value() && !top_level_domain->empty()) {
                cookie.setDomain(std::move(*top_level_domain));
            }
            // Keyed by name: setting the same cookie twice yields one header.
            response_[key] = std::move(cookie);
        }

        std::optional<std::string> get(const std::string& key) override {
            // Check response cookies first, then fall back to request cookies
            if (const auto it = response_.find(key); it != response_.end()) return it->second.value();
            const auto& request_cookies = request_->getCookies();
            if (const auto it = request_cookies.find(key); it != request_cookies.end()) return it->second;
            return std::nullopt;
        }

        // Attach the SDK cookies to the response
        void apply(const drogon::HttpResponsePtr& response) const {
            for (const auto& [name, cookie] : response_) response->addCookie(cookie);
        }

    private:
        drogon::HttpRequestPtr request_;
        std::map<std::string, drogon::Cookie> response_;
    };

    void get_visitor_code(const drogon::HttpRequestPtr& request,
                          std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
        DrogonCookieAccessor cookies{request};

        // Retrieve or generate a visitor code using the SDK
        std::string visitor_code = client.get_visitor_code(cookies);

        auto response = drogon::HttpResponse::newHttpResponse();
        response->setBody(visitor_code);
        // Attach any new/updated cookies to the response headers
        cookies.apply(response);
        callback(response);
    }
    ```
  </Tab>
</Tabs>

##### Paramètres

| Nom | Type | Description |
| - | - | - |
| `cookies` <Badge color="red" size="sm">obligatoire</Badge> | `CookieAccessor&` | Accesseur de cookies utilisé pour lire et stocker le cookie du visiteur. |
| `default_visitor_code` <Badge color="green" size="sm">facultatif</Badge> | `std::optional<std::string>` | Visitor code à utiliser lorsqu'aucun cookie n'est présent. |

##### Valeur de retour

| Type | Description |
| - | - |
| `std::string` | Chaîne représentant un visitor code unique utilisé dans le SDK. |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |
| `ErrorCode::InvalidSimVarCookieFormat` | Indique que le cookie `kameleoonSimulationFFData` contient du JSON mal formé et que les variations simulées n'ont pas pu être analysées. |

#### add\_data()

La méthode `add_data()` ajoute des [données de ciblage](#types-de-données) au stockage afin que d'autres méthodes puissent utiliser ces données pour décider de cibler ou non le visiteur actuel.

La méthode `add_data()` ne renvoie aucune valeur et n'interagit pas d'elle-même avec les serveurs back-end de Kameleoon. Au lieu de cela, le SDK enregistre toutes les données déclarées pour une transmission future via la méthode [`flush()`](#flush). Cette approche réduit le nombre d'appels serveur effectués, car les données sont généralement regroupées en un seul appel serveur déclenché par le `flush()`.

La méthode [`track_conversion()`](#track_conversion) envoie également toutes les données précédemment associées, tout comme le `flush()`. Il en va de même pour les méthodes [`get_variation()`](#get_variation) et [`get_variations()`](#get_variations) si une règle d'expérimentation est déclenchée.

<Tip>
  Chaque visiteur ne peut avoir qu'une seule instance de données associées pour la plupart des types de données. Cependant, [`CustomData`](#customdata) est une exception. Les visiteurs peuvent avoir une instance de `CustomData` associée par index.
</Tip>

Le paramètre `data` est un `std::vector<Data>`, où `Data` est un `std::variant` de tous les [types de données](#types-de-données). Chaque type de données se convertit implicitement en `Data`, vous pouvez donc passer une liste entre accolades d'objets de données.

```cpp theme={null}
using namespace kameleoon;

client.add_data(visitor_code, {Browser{.type = BrowserType::Chrome, .version = 123.0F}});

client.add_data(visitor_code, {
    PageView{.url = "https://example.com/pricing", .title = "Pricing", .referrers = {3}},
    UserAgent{"Mozilla/5.0"},
});

// Stores the data locally for targeting only, without sending it to Kameleoon
client.add_data(visitor_code, {PageView{.url = "https://example.com/checkout", .title = "Checkout"}}, false);
```

##### Paramètres

| Nom | Type | Description | Valeur par défaut |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique du visiteur. | |
| `data` <Badge color="red" size="sm">obligatoire</Badge> | `const std::vector<Data>&` | Collection de types de données Kameleoon. | |
| `track` <Badge color="green" size="sm">facultatif</Badge> | `bool` | Spécifie si les données ajoutées sont éligibles au tracking. Lorsqu'il est défini sur `false`, le SDK stocke les données localement, les utilise uniquement pour l'évaluation du ciblage et ne les envoie pas à la Data API de Kameleoon. | `true` |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |
| `ErrorCode::InvalidArgument` | Une chaîne n'est pas de l'UTF-8 valide ou une valeur d'énumération est inconnue. |

#### flush()

* *📨 Envoie des données de tracking à Kameleoon*

La méthode `flush()` agrège toutes les données Kameleoon associées à un visiteur et envoie une requête de tracking au serveur. Cette requête inclut toutes les données précédemment ajoutées via la méthode [`add_data`](#add_data) qui n'ont pas encore été transmises par d'autres mécanismes de tracking (consultez les méthodes référencées pour plus de détails). L'opération `flush()` est non bloquante, car l'appel serveur est effectué de manière asynchrone.

Cette méthode permet de contrôler le moment où les données liées à un `visitor_code` spécifique sont transmises. Par exemple, si `add_data()` est appelée plusieurs fois, envoyer une requête après chaque invocation serait inefficace. Au lieu de cela, vous pouvez regrouper ces mises à jour et appeler `flush()` une seule fois pour envoyer toutes les données accumulées en une seule requête.

La méthode `flush()` utilise le `visitor_code` fourni comme identifiant unique du visiteur.

<Tip>
  * `flush()` : met en file d'attente une opération de flush selon l'intervalle de tracking configuré.
  * `flush_instant()` : envoie les données de tracking immédiatement sans attendre l'intervalle.
</Tip>

```cpp theme={null}
// Queues a flush operation for the given visitor_code.
// Data will be sent according to the configured tracking interval (non-blocking).
client.flush(visitor_code);

// Immediately sends all pending tracking data for the given visitor_code
// and blocks until the request completes.
client.flush_instant(visitor_code);

// Immediately sends all pending tracking data without blocking.
client.flush_instant_async(visitor_code, [](std::exception_ptr error) {
    // The immediate tracking operation completed.
});

// C++20 coroutines
co_await client.co_flush_instant(visitor_code);
```

##### Paramètres

| Nom | Type | Description |
| - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique du visiteur. |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |

#### get\_remote\_data()

La méthode `get_remote_data()` vous permet de récupérer des données distantes stockées sur les serveurs Kameleoon pour la `key` spécifiée. Dans la plupart des configurations, ces données sont écrites via la Data API de Kameleoon et peuvent ensuite être récupérées par votre service C++ chaque fois que vous avez besoin de contexte applicatif supplémentaire.

Cette méthode est utile lorsque vous souhaitez conserver des informations structurées sur l'infrastructure distante de Kameleoon et les réutiliser depuis votre back-end sans maintenir un mécanisme de récupération distinct.

```cpp theme={null}
// Blocking
std::string data = client.get_remote_data("test-key");

// Completion: the value is only meaningful when `error` is null
client.get_remote_data_async("test-key", [](std::exception_ptr error, std::string data) {
    if (!error) {
        // Use `data`.
    }
});

// C++20 coroutines
std::string data = co_await client.co_get_remote_data("test-key");
```

##### Paramètres

| Nom | Type | Description |
| - | - | - |
| `key` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Clé associée aux données distantes que vous souhaitez récupérer. |

##### Valeur de retour

| Type | Description |
| - | - |
| `std::string` | Charge utile associée à la `key` spécifiée. Dans la plupart des cas, la charge utile est du JSON sérialisé sous forme de chaîne. La charge utile est une chaîne d'octets et peut contenir des octets arbitraires. |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::Network` | Levée lorsque la requête de données distantes échoue ou que le serveur répond avec un code de statut non réussi. |

#### get\_remote\_visitor\_data()

`get_remote_visitor_data()` récupère les données de visite Kameleoon pour le `visitor_code` fourni. La méthode ajoute les données au stockage local des visiteurs afin que les autres méthodes du SDK puissent les utiliser pour les décisions de ciblage.

Les données obtenues avec cette méthode sont particulièrement utiles lorsque vous souhaitez :

* utiliser des données collectées depuis d'autres appareils.
* accéder à l'historique d'un visiteur, comme les pages précédemment consultées lors de visites passées.
* utiliser des données qui ne sont disponibles que côté client, telles que les variables du datalayer et les conversions d'objectifs front-end.

Lisez [cet article](/fr/developer-docs/feature-experimentation/targeting-and-segmentation/native-segmentation) pour une meilleure compréhension des cas d'usage possibles.

<Warning>
  Par défaut, `get_remote_visitor_data()` récupère automatiquement les dernières custom data stockées avec `scope=Visitor` et les associe au visiteur sans qu'il soit nécessaire d'appeler [`add_data()`](#add_data). Cela est particulièrement utile pour [synchroniser les custom data entre plusieurs appareils](/fr/developer-docs/cross-device-experimentation/).
</Warning>

```cpp theme={null}
using namespace kameleoon;

// Fetch remote visitor data without any filter
// This will return all available data for the given visitor
client.get_remote_visitor_data(visitor_code);

// Create a filter to limit the returned data
RemoteVisitorDataFilter filter{
    .previous_visit_amount = 5,  // Include data from the last 5 visits
    .page_views = true,          // Include page view history
    .conversions = true,         // Include conversion events (e.g., goals, transactions)
};

// Fetch remote visitor data using the specified filter
// This will return only the data matching the filter criteria
client.get_remote_visitor_data(visitor_code, filter);

// Non-blocking form
client.get_remote_visitor_data_async(visitor_code, filter, [](std::exception_ptr error) {
    // The data is available locally when `error` is null.
});

// C++20 coroutines
co_await client.co_get_remote_visitor_data(visitor_code, filter);
```

##### Paramètres

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Visitor code dont les données doivent être récupérées. | |
| `filter` <Badge color="green" size="sm">facultatif</Badge> | `RemoteVisitorDataFilter` | Filtre décrivant quelles données de visiteur distantes doivent être récupérées. | `RemoteVisitorDataFilter{}` |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |
| `ErrorCode::Network` | Levée lorsque la requête de données de visiteur distantes échoue, ne peut pas être analysée, ou que le serveur répond avec un code de statut non réussi. |

##### Utilisation des paramètres dans get\_remote\_visitor\_data()

La méthode `get_remote_visitor_data()` vous permet de contrôler quelles données sont récupérées pour un visiteur. La même approche de filtrage fonctionne pour les objectifs, les expériences, les variations et les autres données de visiteur.

Par exemple, si vous souhaitez cibler les utilisateurs qui ont converti sur un objectif lors de leurs cinq dernières visites, vous pouvez définir `previous_visit_amount` sur `5` et `conversions` sur `true`.

La flexibilité illustrée dans cet exemple ne se limite pas aux données d'objectifs. Vous pouvez utiliser le filtre pour récupérer de nombreux comportements de visiteurs différents et les rendre disponibles pour la logique de ciblage et de reporting de votre application C++.

##### Champs de `RemoteVisitorDataFilter`

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `previous_visit_amount` | `uint32_t` | Nombre de visites précédentes dont les données doivent être récupérées. | `1` |
| `current_visit` | `bool` | Si `true`, les données de la visite actuelle seront récupérées. | `true` |
| `custom_data` | `bool` | Si `true`, les custom data seront récupérées. | `true` |
| `visitor_code` | `bool` | Si `true`, le visitor code le plus récent sera réutilisé. | `true` |
| `page_views` | `bool` | Si `true`, les données de pages vues seront récupérées. | `false` |
| `geolocation` | `bool` | Si `true`, les données de géolocalisation seront récupérées. | `false` |
| `device` | `bool` | Si `true`, les données d'appareil seront récupérées. | `false` |
| `browser` | `bool` | Si `true`, les données de navigateur seront récupérées. | `false` |
| `operating_system` | `bool` | Si `true`, les données de système d'exploitation seront récupérées. | `false` |
| `conversions` | `bool` | Si `true`, les données de conversion seront récupérées. | `false` |
| `experiments` | `bool` | Si `true`, les données d'expérience seront récupérées. | `false` |
| `kcs` | `bool` | Si `true`, les données du Kameleoon Conversion Score seront récupérées. | `false` |
| `personalizations` | `bool` | Si `true`, les données de personnalisation seront récupérées. | `false` |
| `cbs` | `bool` | Si `true`, le SDK récupère les données de score Contextual Bandit. | `false` |

#### get\_visitor\_warehouse\_audience()

Cette méthode récupère les données d'audience associées à un visiteur dans votre intégration warehouse en utilisant le `visitor_code` spécifié et, éventuellement, une `warehouse_key`. La `warehouse_key` est généralement votre ID utilisateur interne. Le paramètre `custom_data_index` correspond à la custom data Kameleoon que Kameleoon utilise pour cibler vos visiteurs.

Lorsque l'appel réussit, le SDK convertit la liste d'audiences renvoyée en [`CustomData`](#customdata), l'ajoute localement au visiteur et la rend disponible à des fins de ciblage. Pour plus de contexte, consultez la [documentation sur le ciblage warehouse](/fr/user-manual/integrations/data-warehouses/bigquery/use-bigquery-as-a-source-audience-targeting).

```cpp theme={null}
// Fetch audience data for a visitor using only the visitor_code.
client.get_visitor_warehouse_audience(visitor_code, 98);

// Fetch audience data for a visitor using both visitor_code and warehouse_key.
// Useful when your warehouse uses a different identifier than visitor_code.
client.get_visitor_warehouse_audience(visitor_code, 98, "internal-user-id");

// Non-blocking form
client.get_visitor_warehouse_audience_async(visitor_code, 98, "internal-user-id", [](std::exception_ptr error) {
    // The audience data is available locally when `error` is null.
});

// C++20 coroutines
co_await client.co_get_visitor_warehouse_audience(visitor_code, 98, "internal-user-id");
```

##### Paramètres

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Visiteur dont les audiences warehouse doivent être récupérées. | |
| `custom_data_index` <Badge color="red" size="sm">obligatoire</Badge> | `uint32_t` | Index de la custom data configurée dans Kameleoon pour le ciblage d'audience warehouse. | |
| `warehouse_key` <Badge color="green" size="sm">facultatif</Badge> | `std::optional<std::string>` | Clé warehouse externe, généralement votre ID utilisateur interne. Lorsqu'elle est omise, le SDK utilise `visitor_code`. | `std::nullopt` |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |
| `ErrorCode::Network` | Levée lorsque la requête d'audience warehouse échoue, ne peut pas être analysée, ou que le serveur répond avec un code de statut non réussi. |

#### set\_legal\_consent()

Vous devez utiliser cette méthode pour spécifier si le visiteur a donné son consentement légal à l'utilisation de ses données personnelles. Définir `consent` sur `false` limite les types de données pouvant être inclus dans les requêtes de tracking. Cela vous aide à respecter les exigences légales et réglementaires tout en gérant de manière responsable les données des visiteurs. Pour plus d'informations, consultez la [politique de gestion du consentement](/fr/user-manual/project-management/consent-management-policy).

Si vous passez un `CookieAccessor`, le SDK met également à jour les cookies du visiteur en fonction du statut de consentement.

```cpp theme={null}
// Set consent and update cookies
client.set_legal_consent(visitor_code, true, &cookies);

// Set consent without updating cookies
client.set_legal_consent(visitor_code, true);
```

##### Paramètres

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique de l'utilisateur. | |
| `consent` <Badge color="red" size="sm">obligatoire</Badge> | `bool` | `true` indique que le visiteur a donné son consentement légal, `false` indique que le visiteur n'a jamais donné, ou a retiré, son consentement légal. | |
| `cookies` <Badge color="green" size="sm">facultatif</Badge> | `CookieAccessor*` | Accesseur de cookies facultatif utilisé pour mettre à jour les cookies. | `nullptr` |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |

##### Comportement en cas de retrait du consentement

Lorsque vous appelez `set_legal_consent()` avec `consent=false`, le SDK ne supprime pas le cookie `kameleoonVisitorCode`. Au lieu de cela, il cesse de prolonger la date d'expiration du cookie, permettant au cookie de persister jusqu'à son expiration naturelle.

Si vos exigences de conformité imposent la suppression immédiate du fichier cookie lors de l'opt-out, vous devez le supprimer manuellement à l'aide des méthodes natives de gestion des cookies de votre framework. Le SDK ne supprimera pas le fichier automatiquement.

### Objectifs et analytics tiers

#### track\_conversion()

* 📨 *Envoie des données de tracking à Kameleoon*

Utilisez cette méthode pour suivre une conversion pour un [objectif](/fr/user-manual/assets/goals/create-a-goal) et un utilisateur spécifiques. Cette méthode nécessite `visitor_code` et `goal_id`. De plus, cette méthode accepte également des arguments optionnels `revenue`, `negative` et `metadata`. Le `visitor_code` est généralement identique à celui utilisé lors du déclenchement de l'expérience.

<Tip>
  Cette méthode est non bloquante car le SDK effectue l'appel serveur de manière asynchrone.
</Tip>

```cpp theme={null}
using namespace kameleoon;

// Track a goal
client.track_conversion(visitor_code, goal_id);

// Track a goal with revenue
client.track_conversion(visitor_code, goal_id, TrackConversionOptions{.revenue = 100.0F});

// Track a goal with negative revenue
client.track_conversion(
    visitor_code, goal_id, TrackConversionOptions{.revenue = 100.0F, .negative = true});

// Track a goal with custom metadata
client.track_conversion(
    visitor_code, goal_id, TrackConversionOptions{.metadata = {CustomData(4, {"true"})}});
```

##### Paramètres

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique du visiteur. | |
| `goal_id` <Badge color="red" size="sm">obligatoire</Badge> | `uint32_t` | ID de l'objectif. | |
| `revenue` <Badge color="green" size="sm">facultatif</Badge> | `float` | Revenu de la conversion. | `0` |
| `negative` <Badge color="green" size="sm">facultatif</Badge> | `bool` | Définit si le revenu est positif ou négatif. | `false` |
| `metadata` <Badge color="green" size="sm">facultatif</Badge> | `std::vector<CustomData>` | Métadonnées de la conversion. [Doivent être définies au préalable dans l'application Kameleoon](/fr/user-manual/assets/goals/create-a-goal#métadonnées). | `{}` |

<Note>
  Les paramètres facultatifs `revenue`, `negative` et `metadata` sont passés comme champs d'une structure `TrackConversionOptions`.
</Note>

<Note>
  Les valeurs de metadata sont accessibles via les [exports de données brutes](/fr/user-manual/experiment-analytics/analyze-results/results-page/results-page-actions#exporter) et [la page de résultats](/fr/user-manual/experiment-analytics/analyze-results/data-and-metrics/goal-metadata).

  Si vous fournissez le paramètre `metadata`, Kameleoon utilise ces valeurs spécifiées pour la conversion actuelle au lieu de ce que vous avez précédemment collecté avec la méthode [`add_data()`](#add_data). Si vous omettez le paramètre, Kameleoon utilise les dernières valeurs suivies pour ces [`CustomData`](#customdata) avant la conversion et au sein de la même visite.

  Kameleoon ne prendra en compte que les valeurs de metadata explicitement passées en paramètres à la méthode `track_conversion()`.

  Dans l'exemple ci-dessous, Kameleoon associera la conversion uniquement à la valeur de custom data explicitement fournie en paramètre (ici : l'index 5 avec la valeur 'Amex Credit Card').

  ```cpp theme={null}
  client.add_data(visitor_code, {
      CustomData(5, {"Credit Card"}),
      CustomData(9, {"Express Delivery"}),
  });

  client.track_conversion(
      visitor_code, goal_id, TrackConversionOptions{.metadata = {CustomData(5, {"Amex Credit Card"})}});
  ```
</Note>

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |

#### get\_engine\_tracking\_code()

Kameleoon s'intègre à plusieurs solutions d'analyse, notamment Mixpanel, Google Analytics 4 et Segment. Pour suivre correctement les expériences côté serveur, appelez la méthode `get_engine_tracking_code()` après que le visiteur a déclenché une expérience. Le SDK renvoie des commandes de file d'attente JavaScript pour les expériences que le visiteur a déclenchées au cours des 5 dernières secondes. Lorsque vous insérez ce code dans la page, Engine.js traite les commandes et envoie les événements d'exposition via l'intégration d'analyse active.

Consultez l'[expérimentation hybride](/fr/developer-docs/feature-experimentation/get-started/hybrid-experimentation) pour plus d'informations sur l'implémentation de cette méthode.

```cpp theme={null}
std::string tracking_code = client.get_engine_tracking_code(visitor_code);
```

<Note>
  * Pour utiliser cette fonctionnalité, implémentez à la fois le SDK C++ et [Engine.js](/fr/developer-docs/web-experimentation/implementation-and-deployment/standard-implementation) de Kameleoon. Comme ce flux n'utilise Engine.js que pour le tracking, vous pouvez installer le tag asynchrone avant la balise fermante `</body>`.
  * Si vous souhaitez uniquement suivre les expériences dans Kameleoon et n'avez pas besoin d'envoyer des événements d'exposition à des outils d'analyse tiers, utilisez le [SDK JavaScript / TypeScript](/fr/developer-docs/sdks/web-sdks/js-sdk). Cette option fonctionne bien pour les [plateformes de calcul edge serverless](/fr/developer-docs/feature-experimentation/implementation-and-deployment/serverless-edge-compute-starter-kits). Le SDK JavaScript / TypeScript suit automatiquement les variations lorsque vous appelez [`getVisitorCode`](/fr/developer-docs/sdks/web-sdks/js-sdk#getvisitorcode), à condition d'ajouter les attributions d'expériences correspondantes à `window.kameleoonQueue`.
  * Vous pouvez insérer le code de tracking renvoyé directement dans une balise HTML `<script>`.

  ```html theme={null}
  <html lang="en">
    <body>
      <script>
        const engineTrackingCode = `
          window.kameleoonQueue = window.kameleoonQueue || [];
          window.kameleoonQueue.push(['Experiments.assignVariation', 123456, 7890, true]);
          window.kameleoonQueue.push(['Experiments.trigger', 123456, true]);
          window.kameleoonQueue.push(['Experiments.assignVariation', 234567, 8901, true]);
          window.kameleoonQueue.push(['Experiments.trigger', 234567, true]);
        `;
        const script = document.createElement('script');

        script.textContent = engineTrackingCode;
        document.body.appendChild(script);
      </script>

    </body>
  </html>
  ```

  Dans cet exemple, `123456` et `234567` sont des ID d'expériences, et `7890` et `8901` sont des ID de variations. Dans votre implémentation, le SDK génère ces valeurs dans le code de tracking renvoyé.
</Note>

##### Paramètres

| Nom | Type | Description |
| - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Identifiant unique du visiteur. |

##### Valeur de retour

| Type | Description |
| - | - |
| `std::string` | Code JavaScript à insérer dans la page. |

##### Exceptions

| Type | Description |
| - | - |
| `ErrorCode::Initialization` | Indique que le SDK n'est pas encore entièrement initialisé. |
| `ErrorCode::VisitorCodeInvalid` | Exception indiquant que le visitor code fourni n'est pas valide. Il est soit vide, soit plus long que 255 caractères. |

### Événements

#### set\_event\_handler()

Utilisez cette méthode pour enregistrer un gestionnaire pour les événements du SDK. Le SDK appelle le gestionnaire lorsque l'événement sélectionné se produit. Le client conserve au plus un gestionnaire par type d'événement : l'enregistrement d'un nouveau gestionnaire pour le même type d'événement remplace le gestionnaire précédent.

Le constructeur `EventHandler` que vous utilisez (`EventHandler::datafile_update()` ou `EventHandler::http_request()`) sélectionne le type d'événement, de sorte qu'un gestionnaire et les événements qu'il reçoit ne peuvent pas se désynchroniser. Passer une `std::function` vide (`{}`) supprime le gestionnaire actuel pour le type d'événement sélectionné.

<Tabs>
  <Tab title="datafile_update">
    ```cpp theme={null}
    #include "kameleoon/events.hpp"

    using namespace kameleoon;

    client.set_event_handler(EventHandler::datafile_update([](const DataFileUpdateEvent& event) {
        DataFileUpdateSource source = event.source; // DataFileUpdateSource::Polling or DataFileUpdateSource::Streaming
        uint64_t date_modified = event.date_modified; // Data file modification date in milliseconds.

        // React to the data file update.
    }));

    // Clear the handler.
    client.set_event_handler(EventHandler::datafile_update({}));
    ```

    <Tip>
      `DataFileUpdateEvent` contient des informations sur une mise à jour du fichier de données du SDK.

      | Nom | Type | Description |
      | - | - | - |
      | `source` | `DataFileUpdateSource` | La source de la mise à jour. [`DataFileUpdateSource::Polling`](/fr/developer-docs/feature-experimentation/technical-reference/technical-considerations#polling-par-défaut) indique un rafraîchissement planifié du fichier de données, et [`DataFileUpdateSource::Streaming`](/fr/developer-docs/feature-experimentation/technical-reference/technical-considerations#streaming-option-premium) indique une mise à jour en temps réel reçue via le mode streaming. |
      | `date_modified` | `uint64_t` | La date de modification du fichier de données mis à jour, en millisecondes. |
    </Tip>
  </Tab>

  <Tab title="http_request">
    ```cpp theme={null}
    #include "kameleoon/events.hpp"

    #include <variant>

    using namespace kameleoon;

    client.set_event_handler(EventHandler::http_request([](const HttpRequestEvent& event) {
        if (const auto* succeeded = std::get_if<HttpRequestSucceeded>(&event)) {
            // The SDK request completed successfully.
            RequestType request_type = succeeded->request_type;
            uint16_t http_status = succeeded->http_status;
            std::chrono::milliseconds duration = succeeded->duration;
        } else if (const auto* failed = std::get_if<HttpRequestFailed>(&event)) {
            // The SDK request failed.
            HttpRequestFailureReason reason = failed->failure.reason; // HttpStatus, Error, or Cancelled
            std::optional<uint16_t> http_status = failed->failure.http_status;
            std::optional<std::string> cause = failed->failure.cause;
        }
    }));

    // Clear the handler.
    client.set_event_handler(EventHandler::http_request({}));
    ```

    <Tip>
      `HttpRequestEvent` est un `std::variant<HttpRequestSucceeded, HttpRequestFailed>`. Le SDK signale l'événement une fois pour chaque tentative réelle de requête HTTP, y compris les nouvelles tentatives. Utilisez `std::get_if` ou `std::visit` pour distinguer une requête réussie d'une requête échouée.

      | Type | Description |
      | - | - |
      | `HttpRequestSucceeded` | Décrit une requête HTTP du SDK qui s'est terminée avec succès. Porte toujours `http_status`. |
      | `HttpRequestFailed` | Décrit une requête HTTP du SDK qui a échoué en raison d'un statut HTTP, d'une erreur ou d'une annulation. Porte toujours `failure`. |

      <Accordion title="Champs de données de l'événement et détails de l'échec">
        ##### Champs de données de l'événement

        | Nom | Type | Description |
        | - | - | - |
        | `request_type` | `RequestType` | Le type de requête du SDK. Les valeurs possibles sont `RequestType::DataFile`, `RequestType::Tracking`, `RequestType::RemoteVisitorData`, `RequestType::RemoteData` et `RequestType::AccessToken`. |
        | `http_status` | `uint16_t` | Le code de statut HTTP renvoyé par la requête. Présent uniquement dans `HttpRequestSucceeded`. |
        | `failure` | `HttpRequestFailure` | Détails sur la raison de l'échec de la requête. Présent uniquement dans `HttpRequestFailed`. |
        | `duration` | `std::chrono::milliseconds` | La durée de la requête. |

        ##### HttpRequestFailure

        `HttpRequestFailure` contient des détails sur une requête HTTP du SDK qui a échoué.

        | Nom | Type | Description |
        | - | - | - |
        | `reason` | `HttpRequestFailureReason` | La raison de l'échec. Les valeurs possibles sont `HttpRequestFailureReason::HttpStatus`, `HttpRequestFailureReason::Error` et `HttpRequestFailureReason::Cancelled`. |
        | `http_status` | `std::optional<uint16_t>` | Le code de statut HTTP pour les échecs causés par une réponse HTTP non réussie. Cette valeur est `std::nullopt` pour les échecs dus à une exception ou à une annulation. |
        | `cause` | `std::optional<std::string>` | L'exception (erreur) qui a causé l'échec de la requête. Cette valeur est `std::nullopt` lorsque la requête a échoué en raison d'un statut HTTP ou d'une annulation. |
      </Accordion>
    </Tip>
  </Tab>
</Tabs>

<Note>
  Les gestionnaires sont appelés de manière synchrone sur le thread de travail unique du SDK, ils ne doivent donc pas bloquer : le temps passé dans un gestionnaire retarde le polling du fichier de données et les envois de tracking. Ils doivent être thread-safe et ne doivent pas lever d'exception : une exception s'échappant d'un gestionnaire est interceptée et ignorée, et n'affecte jamais le comportement du SDK. N'appelez pas d'opérations SDK bloquantes depuis un gestionnaire ; utilisez les formes `*_async` et terminez le travail sur un thread applicatif.

  Une invocation déjà en cours peut se terminer après que vous avez supprimé le gestionnaire ou détruit le client, et le gestionnaire (avec ses captures) est détruit sur un thread du SDK une fois qu'il n'est plus utilisé. Maintenez les objets capturés en vie et thread-safe en conséquence. Un gestionnaire peut se supprimer ou se remplacer lui-même.

  Toutes les instances `KameleoonClient` créées pour le même site code et le même environnement partagent un gestionnaire par type d'événement : le dernier gestionnaire défini prévaut, et la destruction de l'une de ces instances le supprime. Conservez une seule instance de client par site code et environnement.
</Note>

##### Paramètres

| Nom | Type | Description |
| - | - | - |
| `handler` <Badge color="red" size="sm">obligatoire</Badge> | `EventHandler` | Le gestionnaire à enregistrer, construit avec `EventHandler::datafile_update()` à partir d'un `DataFileUpdateHandler` (`std::function<void(const DataFileUpdateEvent&)>`), ou avec `EventHandler::http_request()` à partir d'un `HttpRequestHandler` (`std::function<void(const HttpRequestEvent&)>`). Passez une `std::function` vide pour supprimer le gestionnaire actuel pour ce type d'événement. |

### Types de données

Cette section liste les types de données C++ déclarés par le SDK dans l'espace de noms `kameleoon` (`kameleoon/data/*.hpp`). Ce sont tous des structures simples que vous passez à [`add_data()`](#add_data).

#### ApplicationVersion

`ApplicationVersion` représente le numéro de version sémantique de votre application.

<Tip>
  Un **visiteur** ne peut avoir qu'une seule `ApplicationVersion`. L'ajout d'une seconde instance écrasera la première.
</Tip>

| Nom | Type | Description |
| - | - | - |
| `value` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | La version de l'application. Ce champ doit suivre le versionnement sémantique. Les formats acceptés sont `major`, `major.minor` ou `major.minor.patch`. |

```cpp theme={null}
using namespace kameleoon;

// major
client.add_data(visitor_code, {ApplicationVersion{"10"}});
// major.minor
client.add_data(visitor_code, {ApplicationVersion{"10.20"}});
// major.minor.patch
client.add_data(visitor_code, {ApplicationVersion{"10.20.30"}});
```

#### Browser

Les données `Browser` stockées ici peuvent être utilisées pour filtrer les rapports d'expérience et de personnalisation par n'importe quelle valeur associée.

| Nom | Type | Description |
| - | - | - |
| `type` <Badge color="red" size="sm">obligatoire</Badge> | `BrowserType` | Liste des navigateurs : `BrowserType::Chrome`, `BrowserType::InternetExplorer`, `BrowserType::Firefox`, `BrowserType::Safari`, `BrowserType::Opera`, `BrowserType::Other`. |
| `version` <Badge color="green" size="sm">facultatif</Badge> | `std::optional<float>` | Version du navigateur, nombre à virgule flottante représentant les versions majeure et mineure du navigateur |

```cpp theme={null}
using namespace kameleoon;

// Browser data with a version
client.add_data(visitor_code, {Browser{.type = BrowserType::Safari, .version = 26.4F}});
// Browser data without a version
client.add_data(visitor_code, {Browser{.type = BrowserType::Chrome}});
```

#### Conversion

Les données `Conversion` stockées ici peuvent être utilisées pour filtrer les rapports d'expérience et de personnalisation par n'importe quel objectif associé.

<Tip>
  * Chaque visiteur peut avoir plusieurs objets `Conversion`.
  * Vous pouvez trouver le `goal_id` dans l'application Kameleoon.
</Tip>

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `goal_id` <Badge color="red" size="sm">obligatoire</Badge> | `uint32_t` | ID de l'objectif. | |
| `revenue` <Badge color="green" size="sm">facultatif</Badge> | `float` | Revenu de la conversion | `0` |
| `negative` <Badge color="green" size="sm">facultatif</Badge> | `bool` | Définit si le revenu est positif ou négatif. | `false` |
| `metadata` <Badge color="green" size="sm">facultatif</Badge> | `std::vector<CustomData>` | Métadonnées de la conversion. | `{}` |

```cpp theme={null}
using namespace kameleoon;

// Add a simple conversion with ID 32
client.add_data(visitor_code, {Conversion{.goal_id = 32}});

// Add conversion with ID 33 including revenue and marked as negative
client.add_data(visitor_code, {Conversion{.goal_id = 33, .revenue = 10.0F, .negative = true}});

// Add conversion with ID 34 including revenue, negative flag, and custom metadata
client.add_data(visitor_code, {
    Conversion{
        .goal_id = 34,
        .revenue = 10.0F,
        .negative = true,
        .metadata = {
            CustomData(3, {"metadata1", "md2"}),
            CustomData(5, {"md3"}),
        },
    },
});
```

#### Cookie

`Cookie` contient des informations sur les cookies stockés sur l'appareil du visiteur.

| Nom | Type | Description |
| - | - | - |
| `cookies` | `std::unordered_map<std::string, std::string>` | Une map de chaînes contenant les clés et valeurs des cookies. |

<Tip>
  Chaque visiteur ne peut avoir qu'un seul `Cookie`. L'ajout d'un second `Cookie` écrase le premier.
</Tip>

```cpp theme={null}
using namespace kameleoon;

client.add_data(visitor_code, {Cookie{.cookies = {{"segment", "vip"}}}});
```

#### CustomData

`CustomData` permet d'associer tout type de données à chaque visiteur, ce qui en fait un outil efficace pour les conditions de ciblage dans les [segments](/fr/user-manual/assets/segments/create-a-segment/). De plus, elles peuvent être utilisées comme filtre ou segmentation dans les rapports d'expérience. Pour plus d'informations sur les custom data, consultez cet [article](/fr/developer-docs/custom-data).

Définissez les types de custom data dans l'application Kameleoon ou la Data API et utilisez-les depuis le SDK.

`CustomData` a deux constructeurs : l'un identifie la custom data par son `id` (index), l'autre par son `name`.

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `id`/`name` <Badge color="red" size="sm">obligatoire</Badge> | `uint32_t`/`std::string` | Index ou nom de la custom data. **`id` ou `name` doit être fourni** pour identifier la donnée. | |
| `values` <Badge color="red" size="sm">obligatoire</Badge> | `std::vector<std::string>` | Valeurs de la custom data à stocker. | |
| `overwrite` <Badge color="green" size="sm">facultatif</Badge> | `bool` | Indicateur pour contrôler explicitement la façon dont les valeurs sont stockées et dont elles apparaissent dans les rapports. [En savoir plus](/fr/developer-docs/custom-data#logique-par-défaut-lorsque-le-paramètre-overwrite-est-false-ou-omis) | `true` |

<Note>
  * Chaque visiteur ne peut avoir qu'une seule `CustomData` pour chaque `id` (`name`) unique. L'ajout d'une autre `CustomData` avec le même `id` (`name`) remplacera l'existante.

  * L'« index » de la custom data se trouve dans le [tableau de bord Custom Data](/fr/user-manual/assets/custom-data/manage-custom-data) sous la colonne « INDEX ».

  * Pour empêcher le SDK d'envoyer les données avec l'index sélectionné aux serveurs Kameleoon pour des raisons de confidentialité, activez l'option : **Use this data only locally for targeting purposes** lors de la création de la custom data.

  * L'ajout d'une instance `CustomData` créée avec un nom alors que l'instance du SDK n'est pas initialisée ou que le nom n'est pas enregistré entraînera l'ignorance de la donnée.
</Note>

```cpp theme={null}
using namespace kameleoon;

client.add_data(visitor_code, {CustomData(1, {"value"})});

// With several values
client.add_data(visitor_code, {CustomData(1, {"value1", "value2"})});

// To set the `overwrite` flag to false
client.add_data(visitor_code, {CustomData(1, {"value"}, false)});

// To use a name instead of the index
client.add_data(visitor_code, {CustomData("my-custom-data", {"value"})});

// To use a name instead of the index and set the `overwrite` flag to false
client.add_data(visitor_code, {CustomData("my-custom-data", {"value"}, false)});
```

#### Device

Vous pouvez utiliser les données d'appareil pour filtrer les rapports d'expérience et de personnalisation par n'importe quelle valeur associée.

| Nom | Type | Description |
| - | - | - |
| `type` | `DeviceType` | Type d'appareil. Les valeurs possibles sont `DeviceType::Phone`, `DeviceType::Tablet` et `DeviceType::Desktop`. |

```cpp theme={null}
using namespace kameleoon;

client.add_data(visitor_code, {Device{DeviceType::Desktop}});
```

#### Geolocation

`Geolocation` contient les détails de géolocalisation du visiteur.

| Nom | Type | Description |
| - | - | - |
| `country` <Badge color="red" size="sm">obligatoire</Badge> | `std::string` | Le pays du visiteur. |
| `region` <Badge color="green" size="sm">facultatif</Badge> | <nobr>`std::optional<std::string>`</nobr> | La région du visiteur. |
| `city` <Badge color="green" size="sm">facultatif</Badge> | <nobr>`std::optional<std::string>`</nobr> | La ville du visiteur. |
| `postal_code` <Badge color="green" size="sm">facultatif</Badge> | <nobr>`std::optional<std::string>`</nobr> | Le code postal du visiteur. |
| `latitude` <Badge color="green" size="sm">facultatif</Badge> | `std::optional<float>` | La coordonnée de latitude représentant la position du visiteur. Le nombre de la coordonnée représente des degrés décimaux. |
| `longitude` <Badge color="green" size="sm">facultatif</Badge> | `std::optional<float>` | La coordonnée de longitude représentant la position du visiteur. Le nombre de la coordonnée représente des degrés décimaux. |

<Tip>
  * Chaque visiteur ne peut avoir qu'une seule `Geolocation`. L'ajout d'une seconde `Geolocation` écrase la première.
</Tip>

```cpp theme={null}
using namespace kameleoon;

client.add_data(visitor_code, {
    Geolocation{
        .country = "France",
        .region = "Ile-de-France",
        .city = "Paris",
        .postal_code = "75009",
        .latitude = 48.8720171F,
        .longitude = 2.3338352F,
    },
});
```

#### OperatingSystem

`OperatingSystem` contient des informations sur le système d'exploitation de l'appareil du visiteur.

| Nom | Type | Description |
| - | - | - |
| `type` | `OperatingSystemType` | Famille de systèmes d'exploitation. Les valeurs possibles sont `OperatingSystemType::Windows`, `OperatingSystemType::Mac`, `OperatingSystemType::IOS`, `OperatingSystemType::Linux`, `OperatingSystemType::Android` et `OperatingSystemType::WindowsPhone`. |

<Tip>
  Chaque visiteur ne peut avoir qu'un seul `OperatingSystem`. L'ajout d'un second `OperatingSystem` écrase le premier.
</Tip>

```cpp theme={null}
using namespace kameleoon;

client.add_data(visitor_code, {OperatingSystem{OperatingSystemType::Windows}});
```

#### PageView

Stocke les événements de pages vues.

| Nom | Type | Description | Défaut |
| - | - | - | - |
| `url` | `std::string` | URL de la page vue. | |
| `title` | `std::optional<std::string>` | Titre de la page vue. | `std::nullopt` |
| `referrers` | `std::vector<int32_t>` | Index des référents des pages vues précédemment. | `{}` |

<Note>
  L'index du référent est disponible dans l'application Kameleoon sur la page de [configuration des canaux d'acquisition](/fr/user-manual/assets/advanced-targeting-tools/create-an-acquisition-channel). Attention : l'index commence à `0`, donc le premier canal d'acquisition que vous créez a l'ID `0`, et non `1`.
</Note>

```cpp theme={null}
using namespace kameleoon;

// Full initialization with url, title, and referrers
client.add_data(visitor_code, {PageView{.url = "https://example.com", .title = "Homepage", .referrers = {3}}});

// Minimal initialization, only requires a URL
client.add_data(visitor_code, {PageView{.url = "https://example.com"}});
```

#### UniqueIdentifier

Si vous n'ajoutez pas `UniqueIdentifier` pour un visiteur, le `visitor_code` est utilisé comme identifiant unique du visiteur, ce qui est utile pour l'[expérimentation cross-device](/fr/developer-docs/cross-device-experimentation/). Lorsque vous ajoutez `UniqueIdentifier{true}`, le SDK lie les données envoyées (flush) au visiteur associé à l'identifiant spécifié.

Cela peut être utile dans les situations où vous ne pouvez pas accéder au `visitor_code` anonyme initialement attribué à un visiteur, mais où vous avez accès à un identifiant interne lié à ce visiteur via la fusion de sessions.

| Nom | Type | Description |
| - | - | - |
| `value` | `bool` | Indique si le `visitor_code` actuel doit être traité comme un identifiant unique. |

```cpp theme={null}
using namespace kameleoon;

client.add_data(visitor_code, {UniqueIdentifier{true}});
```

#### UserAgent

Les expériences côté serveur sont plus susceptibles d'être affectées par le trafic de bots que les expériences côté client. Kameleoon utilise la liste internationale des spiders et bots IAB/ABC pour reconnaître les bots et spiders connus, et utilise également le champ `UserAgent` pour filtrer tout autre trafic indésirable qui pourrait fausser vos métriques de conversion. Pour plus d'informations, consultez l'article d'aide sur le [filtrage des bots](/fr/user-manual/experiment-analytics/troubleshooting/data-discrepancies#how-does-kameleoon-filter-bot-traffic-from-my-results).

Si vous utilisez des bots internes, envoyez la valeur de user-agent `curl/8.0` pour les exclure des analytics.

| Nom | Type | Description |
| - | - | - |
| `value` | `std::string` | Valeur du User-Agent envoyée avec les requêtes de tracking. |

```cpp theme={null}
using namespace kameleoon;

client.add_data(visitor_code, {UserAgent{"Mozilla/5.0"}});
```

### Types renvoyés

#### DataFile

Le `DataFile` contient les détails de la configuration du SDK.

Il peut être étendu avec des informations supplémentaires si les clients en ont besoin. Si vous avez besoin de plus de détails, contactez votre Customer Success Manager.

| Nom | Type | Description |
| - | - | - |
| `feature_flags` | `std::unordered_map<std::string, FeatureFlag>` | Une map d'objets [`FeatureFlag`](#featureflag), avec les clés des feature flags comme clés. |
| `date_modified` | `uint64_t` | Le timestamp (en millisecondes) indiquant la dernière modification du `DataFile`. |

```cpp theme={null}
// Retrieves the map of feature flags from the DataFile.
// The map is keyed by feature flag identifiers, with each value being a FeatureFlag object.
const std::unordered_map<std::string, FeatureFlag>& feature_flags = datafile.feature_flags;

// Retrieves the last modification timestamp of the DataFile.
// The value is a uint64_t representing milliseconds since the Unix epoch.
uint64_t date_modified = datafile.date_modified;
```

#### FeatureFlag

Le `FeatureFlag` représente un ensemble de propriétés qui définissent un feature flag lui-même (par exemple, ses [`Variations`](#variation), ses [`Rules`](#rule), le statut de l'environnement et d'autres détails associés).

Il peut être étendu avec des informations supplémentaires si les clients en ont besoin. Si vous avez besoin de plus de détails, contactez votre Customer Success Manager.

| Nom | Type | Description |
| - | - | - |
| `environment_enabled` | `bool` | Indique si le feature flag est activé dans l'environnement actuel. |
| `default_variation_key` | `std::string` | La clé de la variation par défaut associée au feature flag. |
| `variations` | `std::unordered_map<std::string, Variation>` | Une map d'objets `Variation`, avec les clés de variations comme clés. |
| `rules` | `std::vector<Rule>` | Une liste d'objets `Rule` |

```cpp theme={null}
// Check whether the feature flag is enabled in the current environment.
bool environment_enabled = feature_flag.environment_enabled;

// Retrieve the key of the default variation.
const std::string& default_variation_key = feature_flag.default_variation_key;

// Retrieve the default variation object (nullptr if the key isn't in `variations`).
const Variation* default_variation = feature_flag.default_variation();

// Retrieve all variations of the feature flag as a map (key = variation key, value = Variation object).
const std::unordered_map<std::string, Variation>& variations = feature_flag.variations;

// Retrieve all targeting rules associated with the feature flag.
const std::vector<Rule>& rules = feature_flag.rules;
```

#### Rule

La `Rule` représente un ensemble de propriétés qui définissent une règle elle-même (par exemple, ses [`Variations`](#variation)).

Elle peut être étendue avec des informations supplémentaires si les clients en ont besoin. Si vous avez besoin de plus de détails, contactez votre Customer Success Manager.

| Nom | Type | Description |
| - | - | - |
| `variations` | `std::unordered_map<std::string, Variation>` | Une map d'objets `Variation`, avec les clés de variations comme clés. |

```cpp theme={null}
// Retrieve all variations of the rule as a map (key = variation key, value = Variation object)
const std::unordered_map<std::string, Variation>& variations = rule.variations;
```

#### Variation

`Variation` contient des informations sur la variation attribuée au visiteur, ou la variation par défaut lorsqu'aucune attribution spécifique n'existe.

| Nom | Type | Description |
| - | - | - |
| `name` | `std::string` | Le nom de la variation. |
| `key` | `std::string` | La clé unique identifiant la variation. |
| `id` | `std::optional<uint32_t>` | L'ID de la variation attribuée, ou `std::nullopt` pour une variation par défaut. |
| `experiment_id` | `std::optional<uint32_t>` | L'ID de l'expérience associée à la variation, ou `std::nullopt` pour une variation par défaut. |
| `variables` | `std::vector<Variable>` | Variables associées à la variation. Cette collection peut être vide lorsqu'aucune variable n'est attachée. |

<Note>
  * `Variation` décrit la variation attribuée ou par défaut, tandis que [`Variable`](#variable) contient les détails de chaque variable individuelle.
  * `id` et `experiment_id` peuvent être `std::nullopt`, ce qui indique une variation par défaut qui n'est pas liée à une attribution d'expérience spécifique.
</Note>

Méthodes utilitaires supplémentaires :

| Méthode | Type de retour | Description |
| - | - | - |
| `active()` | `bool` | Renvoie `false` pour la variation `off`. |
| `get_variable(key)` | `const Variable*` | Renvoie un pointeur vers la variable de la variation avec la clé donnée, ou `nullptr` si elle est introuvable. |

```cpp theme={null}
// Retrieving the variation name
const std::string& variation_name = variation.name;

// Retrieving the variation key
const std::string& variation_key = variation.key;

// Retrieving the variation id
std::optional<uint32_t> variation_id = variation.id;

// Retrieving the experiment id
std::optional<uint32_t> experiment_id = variation.experiment_id;

// Retrieving the variables vector
const std::vector<Variable>& variables = variation.variables;

// Checking if the variation is active (i.e., currently being served to visitors)
bool is_active = variation.active();

// Retrieving a variable by its key, returning `nullptr` if not found
if (const Variable* variable = variation.get_variable("title")) {
    // Use `variable`.
}
```

#### Variable

`Variable` contient des informations sur une variable associée à la variation attribuée.

| Nom | Type | Description |
| - | - | - |
| `key` | `std::string` | La clé unique identifiant la variable. |
| `kind` | `std::string` | Le type de la variable. Les valeurs possibles incluent `BOOLEAN`, `NUMBER`, `STRING`, `JSON`, `JS` et `CSS`. |
| `value` | [`JsonValue`](#jsonvalue) | La valeur de la variable. Selon `kind`, elle peut contenir un booléen, un nombre, une chaîne, une chaîne JSON, un extrait de code JavaScript ou un extrait de code CSS. |

```cpp theme={null}
// Retrieve the list of variables associated with the variation
const std::vector<Variable>& variables = variation.variables;

// Access the variable key
const std::string& variable_key = variable.key;

// Access the variable type (kind) for conditional handling
const std::string& kind = variable.kind;

// Extract the value as a number (returns `std::nullopt` if not a number)
std::optional<double> number = variable.value.as_number();

// Extract the value as a boolean (returns `std::nullopt` if not a boolean)
std::optional<bool> apply_discount = variable.value.as_bool();

// Extract the value as a string (returns `std::nullopt` if not a string-carrying kind)
std::optional<std::string> title = variable.value.as_string();
```

<a id="jsonvalue" />

##### JsonValue

`JsonValue` représente la valeur d'une variable de variation en C++. Le champ `kind` distingue les types portant une chaîne ; `value` est un `std::variant<bool, double, std::string>`.

| Kind | Type stocké | Description |
| - | - | - |
| `JsonValueKind::Boolean` | `bool` | Représente une valeur booléenne. |
| `JsonValueKind::Number` | `double` | Représente une valeur numérique. |
| `JsonValueKind::String` | `std::string` | Représente une valeur de type chaîne. |
| `JsonValueKind::JSON` | `std::string` | Représente une valeur encodée en JSON. |
| `JsonValueKind::JS` | `std::string` | Représente un extrait de code JavaScript. |
| `JsonValueKind::CSS` | `std::string` | Représente un extrait de code CSS. |

Les accesseurs typés renvoient `std::nullopt` lorsque la valeur est d'un autre type :

| Méthode | Type de retour | Description |
| - | - | - |
| `as_bool()` | `std::optional<bool>` | La valeur booléenne. |
| `as_number()` | `std::optional<double>` | La valeur numérique. |
| `as_string()` | `std::optional<std::string>` | La valeur de type chaîne pour chaque kind portant une chaîne (`String`, `JSON`, `JS` et `CSS`). |
