> ## 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 de C++

> Integre el SDK de C++ de Kameleoon para ejecutar experimentos y activar feature flags en servicios C++ y back-ends web.

Integrar el SDK en su aplicación es sencillo, y su huella (uso de memoria y de red) es reducida.

**Primeros pasos**: Para obtener ayuda para comenzar, consulte la [guía del desarrollador](#guía-del-desarrollador).

**Última versión**: `0.8.5`. Consulte el [changelog del SDK de C++](https://github.com/Kameleoon-new/client-cpp/blob/main/CHANGELOG.md) para ver las notas de la versión, o el [índice de changelogs de los SDKs](/es/developer-docs/sdks/versions) para todos los SDKs.

**Métodos del SDK**: Para la documentación de referencia completa del SDK de C++, consulte la sección [referencia](#referencia).

## Guía del desarrollador

Esta guía está diseñada para ayudarle a integrar rápidamente el SDK de C++ y empezar a evaluar feature flags en su aplicación C++.

### Primeros pasos

#### Instalar el cliente C++

El SDK de C++ es una biblioteca C++17 construida sobre el Kameleoon SDK Core, una biblioteca compartida nativa (`libkameleoon_ffi`) escrita en Rust que implementa el comportamiento del SDK. Su aplicación enlaza la biblioteca C++ de forma estática y carga la biblioteca core en tiempo de ejecución.

<Warning>
  El Kameleoon SDK Core se compila desde el código fuente para su plataforma y arquitectura de destino. Asegúrese de que **Rust** y **Cargo** estén instalados y disponibles en el `PATH` de su sistema, e instale `cbindgen`, que genera el encabezado C de la biblioteca core:

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

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

  Las versiones futuras proporcionarán bibliotecas core precompiladas para las plataformas más comunes a fin de simplificar la instalación. La compilación local seguirá estando disponible para los usuarios que prefieran compilar desde el código fuente.
</Warning>

Requisitos:

* Un compilador C++17 (GCC, Clang o MSVC) y CMake 3.16 o posterior.
* Rust 1.91 o posterior, Cargo y `cbindgen` para compilar la biblioteca SDK Core (`libkameleoon_ffi.so` en Linux, `libkameleoon_ffi.dylib` en macOS, `kameleoon_ffi.dll` con su biblioteca de importación `kameleoon_ffi.dll.lib` en Windows).

Clone el [repositorio del SDK de C++](https://github.com/Kameleoon-new/client-cpp) y compile la biblioteca core; a continuación, compile la biblioteca C++ contra ella:

```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
```

Para integrar el SDK en su propio proyecto CMake, añada el directorio `cpp/client` con `add_subdirectory()` y enlace el target `Kameleoon::CppClient`. Apunte `KAMELEOON_FFI_LIBRARY` a la biblioteca core que compiló; el encabezado C se genera con `cbindgen`, o puede pasar uno existente con `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` se carga en tiempo de ejecución: instálela en una ubicación estándar de bibliotecas o distribúyala junto a su ejecutable. En Linux y macOS, distribuirla junto al ejecutable requiere un RPATH de `$ORIGIN` o `@loader_path` (por ejemplo, `set_target_properties(my_app PROPERTIES INSTALL_RPATH "$ORIGIN")`). En Windows, copie `kameleoon_ffi.dll` junto a sus binarios.
  * Cuando crea un cliente, el SDK comprueba que la `libkameleoon_ffi` cargada coincide con la versión contra la que fue compilado y, en caso contrario, lanza una `KameleoonException` con `ErrorCode::Internal`. Actualice siempre la biblioteca C++ y la biblioteca core juntas.
  * Todos los tipos públicos del SDK residen en el espacio de nombres `kameleoon`. Incluya `kameleoon/kameleoon.hpp` para obtener toda la API pública.
</Note>

#### Configuración adicional

Cree un archivo de configuración JSON (por ejemplo, `client-cpp.json`) para proporcionar las credenciales y personalizar el comportamiento del SDK. También puede [descargar un archivo de configuración de ejemplo](/assets/developer-docs/sdks/web-sdks/client-configs/client-config.json).

El SDK de C++ puede configurarse con un archivo JSON cuya ruta se pasa a `KameleoonClientFactory::create()`, o rellenando directamente en el código una estructura `KameleoonClientConfig`.

La siguiente tabla muestra las propiedades disponibles que puede establecer:

| Clave (Código / Archivo de configuración) | Descripción | Valor predeterminado |
| - | - | - |
| `client_id` / `clientId` <Badge color="red" size="sm">obligatorio</Badge> | Necesario para autenticarse en el servicio Kameleoon. Para encontrar su `client_id`, consulte la documentación de [credenciales de API](/es/user-manual/account-and-team-management/users-and-teams/api-credentials). | |
| `client_secret` / `clientSecret` <Badge color="red" size="sm">obligatorio</Badge> | Necesario para autenticarse en el servicio Kameleoon. Para encontrar su `client_secret`, consulte la documentación de [credenciales de API](/es/user-manual/account-and-team-management/users-and-teams/api-credentials). | |
| `session_duration_minutes` / `sessionDurationMinutes` <Badge color="green" size="sm">opcional</Badge> | Intervalo de tiempo, en minutos, durante el cual el SDK mantiene a un visitante y sus datos asociados en memoria. | `30` minutos |
| `refresh_interval_minutes` / `refreshIntervalMinutes` <Badge color="green" size="sm">opcional</Badge> | Intervalo, en minutos, utilizado para actualizar la configuración de experimentos y feature flags activos. | `60` minutos |
| `default_timeout_millis` / `defaultTimeoutMillis` <Badge color="green" size="sm">opcional</Badge> | Tiempo de espera predeterminado, en milisegundos, para las solicitudes de red del SDK. | `10000` milisegundos |
| `tracking_interval_millis` / `trackingIntervalMillis` <Badge color="green" size="sm">opcional</Badge> | Intervalo, en milisegundos, utilizado para agrupar las solicitudes de seguimiento. Los valores se limitan al rango `[1000, 5000]`. | `1000` milisegundos |
| `environment` / `environment` <Badge color="green" size="sm">opcional</Badge> | Entorno desde el que debe utilizarse la configuración de feature flags. El valor puede ser `production`, `staging` o `development`. | `std::nullopt` (se trata como `production`) |
| `top_level_domain` / `topLevelDomain` <Badge color="green" size="sm">opcional</Badge> | El dominio de nivel superior actual de su sitio web. Utilice el formato `example.com`, sin protocolo ni subdominios. | `std::nullopt` |
| `proxy_host` / `proxyHost` <Badge color="green" size="sm">opcional</Badge> | Host proxy para las llamadas salientes del SDK. Formatos admitidos: `https://my.prox`, `https://my.prox:4545`, `socks5://192.168.1.1:9000`. | `std::nullopt` |
| `network_domain` / `networkDomain` <Badge color="green" size="sm">opcional</Badge> | Dominio personalizado utilizado por los SDKs para las solicitudes salientes, a menudo para hacer proxy. Debe ser un dominio válido (por ejemplo, example.com o sub.example.com). Los formatos no válidos se sustituyen por el valor por defecto de Kameleoon. | `std::nullopt` |

#### Inicializar el cliente Kameleoon

Una vez que haya instalado el SDK y configurado sus credenciales, cree un `KameleoonClient` mediante `KameleoonClientFactory`.

<Tabs>
  <Tab title="Archivo de configuración">
    ```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="Código">
    ```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>
  Los ejemplos de esta página utilizan los [designated initializers](https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers) de C++20 (`GetVariationOptions{.track = false}`) para rellenar las estructuras de configuración, opciones y datos del SDK. Con un compilador C++17, declare la estructura y establezca sus campos uno a uno.
</Note>

Un `KameleoonClient` es el objeto principal utilizado para evaluar feature flags, añadir datos de visitantes y enviar solicitudes de seguimiento.

<Warning>
  * Se recomienda utilizar `KameleoonClient` como un objeto singleton, ya que actúa como puente entre su aplicación y la plataforma Kameleoon. Expone todos los métodos y propiedades necesarios para ejecutar experimentos de forma eficiente. `KameleoonClient` es de tipo move-only: manténgalo en un solo lugar y páselo por referencia.
  * El SDK de C++ se inicializa de forma asíncrona. Debe llamar a [`initialize()`](#initialize) antes de depender de la evaluación de funcionalidades en código de producción.
  * Cada fallo del SDK se notifica como una [`KameleoonException`](#gestión-de-errores). Envuelva las llamadas al SDK en bloques `try`/`catch`.
</Warning>

#### Activación de un feature flag

##### Asignar un ID único a un usuario

Para asignar un ID único a un usuario, puede utilizar el método [`get_visitor_code()`](#get_visitor_code). Si no existe un **visitor code** (procedente de la cookie de los encabezados de la solicitud), el método genera un ID único aleatorio o utiliza un `default_visitor_code` que usted haya generado. A continuación, el ID se establece en una cookie de los encabezados de la respuesta.

Si utiliza Kameleoon en [modo híbrido](/es/developer-docs/feature-experimentation/get-started/hybrid-experimentation), llamar al método `get_visitor_code()` garantiza que el archivo de aplicación `engine.js` (anteriormente llamado `kameleoon.js`) y el SDK compartan el ID único (**visitor code**).

##### Recuperar la configuración de un flag

Para implementar un feature flag en su código, primero debe crear el feature flag en su cuenta de Kameleoon.

Para determinar el estado o la variación de un feature flag para un usuario específico, debe utilizar el método [`get_variation()`](#get_variation) o [`is_feature_active()`](#is_feature_active) para recuperar la configuración según la `feature_key`.

El método `get_variation()` gestiona tanto feature flags simples con estados ON/OFF como flags más complejos con múltiples variaciones. El método recupera la variación adecuada para el usuario comprobando las reglas de la funcionalidad, asignando la variación y devolviéndola según la `feature_key` y el `visitor_code`.

Puede utilizar el método `is_feature_active()` para recuperar la configuración de un feature flag simple que solo tiene un estado ON u OFF, a diferencia de feature flags más complejos con múltiples variaciones u opciones de segmentación.

Si su feature flag tiene variables asociadas (como comportamientos específicos vinculados a cada variación), `get_variation()` también le permite acceder al objeto [`Variation`](#variation), que proporciona detalles sobre la variación asignada y su experimento asociado. Este método comprueba si el feature flag segmenta al usuario, encuentra la variación asignada al visitante y la guarda en el almacenamiento. Cuando `track=true`, el SDK envía el evento de exposición al experimento especificado en la siguiente solicitud de seguimiento, que se activa automáticamente según el [`tracking_interval_millis`](#configuración-adicional) del SDK. El intervalo predeterminado es de 1000 milisegundos (1 segundo).

El método `get_variation()` le permite controlar si el SDK realiza el seguimiento del visitante. Si `track=false`, el SDK no envía eventos de exposición. Esta opción es útil si prefiere no realizar el seguimiento de datos a través del SDK y, en su lugar, confiar en el seguimiento del lado del cliente gestionado por el motor de Kameleoon, por ejemplo. Además, establecer `track=false` resulta útil al utilizar el método `get_variations()`, cuando es posible que solo necesite las variaciones de todos los flags sin activar ningún evento de seguimiento. Si desea saber más sobre cómo funciona el seguimiento, consulte [este artículo](/es/developer-docs/feature-experimentation/technical-reference/faq-global#when-does-the-sdk-send-a-tracking-request-for-analytics)

##### Añadir puntos de datos para segmentar a un usuario o filtrar / desglosar visitas en los informes

Para segmentar a un usuario, asegúrese de haber añadido los puntos de datos relevantes a su perfil antes de recuperar la variación de la funcionalidad o comprobar si el flag está activo. Utilice el método [`add_data()`](#add_data) para añadir estos puntos de datos al perfil del usuario.

Para recuperar puntos de datos recopilados en otros dispositivos o para acceder a datos pasados del usuario (recopilados del lado del cliente al utilizar Kameleoon en modo híbrido), utilice el método [`get_remote_visitor_data()`](#get_remote_visitor_data). Este método obtiene los datos de los servidores de forma asíncrona. Es importante llamar a `get_remote_visitor_data()` *antes* de recuperar la variación o comprobar si el feature flag está activo, porque el SDK podría necesitar estos datos para asignar un usuario a una variación determinada.

Para obtener más información sobre las condiciones de segmentación disponibles, consulte el [artículo detallado sobre el tema](/es/developer-docs/feature-experimentation/targeting-and-segmentation/native-segmentation).

Además, los puntos de datos que añada al perfil del visitante estarán disponibles al analizar sus experimentos, lo que le permitirá filtrar y desglosar sus resultados por factores como el dispositivo y el navegador. El modo híbrido de Kameleoon recopila automáticamente una variedad de puntos de datos del lado del cliente, lo que facilita el desglose de los resultados en función de estos puntos de datos recopilados previamente. Consulte la lista completa [aquí](/es/user-manual/experiment-analytics/analyze-results/results-page/results-page-settings#desglose-de-audiencia).

Si necesita realizar el seguimiento de puntos de datos adicionales más allá de los que se recopilan automáticamente, puede utilizar la funcionalidad de [Custom Data](#customdata) de Kameleoon. Los custom data le permiten capturar y analizar información específica relevante para sus experimentos. No olvide llamar al método [`flush()`](#flush) para enviar los datos recopilados a los servidores de Kameleoon para su análisis.

<Note>
  Para garantizar que sus resultados sean precisos, se recomienda filtrar los bots utilizando el tipo de datos [`UserAgent`](#useragent).
</Note>

##### Seguimiento de conversiones de objetivos

Cuando un usuario completa una acción deseada (como realizar una compra), se registra como una conversión. Para realizar el seguimiento de las conversiones, utilice el método [`track_conversion()`](#track_conversion) y proporcione los parámetros obligatorios `visitor_code` y `goal_id`.

El SDK envía la solicitud de seguimiento de la conversión junto con la siguiente solicitud de seguimiento programada, que se produce a intervalos regulares (definidos por [`tracking_interval_millis`](#configuración-adicional)). Si prefiere enviar la solicitud inmediatamente, utilice el método [`flush_instant()`](#flush).

##### Enviar eventos a soluciones de analítica

Para realizar el seguimiento de las conversiones y enviar eventos de exposición a su solución de analítica de clientes, primero debe implementar Kameleoon en [modo híbrido](/es/developer-docs/feature-experimentation/get-started/hybrid-experimentation/). Después, utilice el método [`get_engine_tracking_code()`](#get_engine_tracking_code).

El método `get_engine_tracking_code()` recupera el código de seguimiento único necesario para enviar eventos de exposición a su solución de analítica. El uso de este método le permite registrar eventos y enviarlos a la plataforma de analítica que desee.

### Gestión de errores

Cada error que lanza el SDK es una `KameleoonException`, por lo que un único manejador para ese tipo captura todos los fallos del SDK. Gestione un tipo de error específico cuando su aplicación necesite reaccionar a un fallo concreto, por ejemplo para recurrir a su comportamiento predeterminado cuando un feature flag no está en la configuración o el SDK aún no está inicializado. La sección de referencia de cada método enumera los errores que puede lanzar.

`KameleoonException` deriva de `std::runtime_error`. Llame a `code()` para obtener el `ErrorCode` que distingue los errores, y a `what()` para obtener el mensaje.

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

| Código de error | Descripción |
| - | - |
| `ErrorCode::Initialization` | El cliente no se pudo crear (site code vacío, configuración ausente o ilegible, credenciales vacías), el SDK aún no está inicializado, o no hubo ningún resultado de inicialización disponible antes de que expirara el tiempo de espera de `initialize()`. |
| `ErrorCode::FeatureNotFound` | Excepción que indica que la clave de funcionalidad solicitada no se encontró en la configuración interna del SDK. Esto normalmente significa que el feature flag no está activado en la aplicación de Kameleoon (pero el código que implementa la funcionalidad ya está desplegado en la aplicación). |
| `ErrorCode::FeatureExperimentNotFound` | Excepción que indica que el id del experimento solicitado no está en la configuración interna del SDK. Este comportamiento suele ser normal y significa que el experimento correspondiente a la regla aún no está activo del lado de Kameleoon. |
| `ErrorCode::FeatureVariationNotFound` | Excepción que indica que la clave (id) de la variación solicitada no está en la configuración interna del SDK. Este comportamiento suele ser normal y significa que el experimento correspondiente a la variación aún no está activo del lado de Kameleoon. |
| `ErrorCode::FeatureEnvironmentDisabled` | Excepción que indica que el feature flag está desactivado para el entorno actual del visitante (por ejemplo, production, staging o development). |
| `ErrorCode::FeatureRuleNotFound` | La regla solicitada no se encontró en la configuración del SDK. |
| `ErrorCode::FeatureEvaluationBlocked` | Excepción que indica que la evaluación de la funcionalidad está bloqueada. El motivo se describe en el mensaje de error. Esto suele ocurrir debido a las restricciones del RGPD cuando el visitante no ha dado su consentimiento legal. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |
| `ErrorCode::InvalidSimVarCookieFormat` | Indica que la cookie `kameleoonSimulationFFData` contiene JSON mal formado y que las variaciones simuladas no se pudieron analizar. |
| `ErrorCode::InvalidArgument` | Un argumento no es válido: una cadena no es UTF-8 válido, un valor de enum es desconocido, un tiempo de espera es cero o negativo, o una entrada supera la longitud admitida. |
| `ErrorCode::Network` | Una solicitud de red falló o el servidor respondió con un código de estado de error: la obtención de la configuración, una solicitud de datos remotos o de datos remotos del visitante, o una solicitud de audiencia de warehouse. También se devuelve cuando el cliente no se puede crear porque `proxy_host` no es válido. |
| `ErrorCode::Internal` | Un error interno inesperado del SDK, por ejemplo una discrepancia de versión de `libkameleoon_ffi`, un método llamado sobre un cliente del que se hizo move, o una clave de variación ausente en la configuración. |

<Note>
  Las cadenas que se pasan al SDK deben ser UTF-8 válido. Los callbacks que proporciona al SDK (las sobrescrituras de `CookieAccessor`, los manejadores de eventos y los loggers) no deben lanzar excepciones: cualquier excepción que escape de ellos se captura en el límite del SDK y se descarta.
</Note>

<Note>
  Los errores del SDK son un comportamiento esperado, no fallos del programa: un feature flag que aún no está activado, un SDK que todavía está cargando su configuración o un fallo de red son condiciones normales. Cuando la evaluación de una funcionalidad falla, registre el error y recurra a su comportamiento predeterminado para que el visitante siga teniendo una experiencia funcional.
</Note>

### Operaciones asíncronas

Las operaciones que dependen de la red ([`initialize()`](#initialize), [`flush_instant()`](#flush), [`get_remote_data()`](#get_remote_data), [`get_remote_visitor_data()`](#get_remote_visitor_data) y [`get_visitor_warehouse_audience()`](#get_visitor_warehouse_audience)) se ejecutan en el hilo de trabajo propio del SDK. Cada una está disponible en tres formas, de modo que pueda elegir la que mejor se adapte al hilo que realiza la llamada:

| Forma | Ejemplo | Cuándo utilizarla |
| - | - | - |
| Bloqueante | `client.initialize(timeout)` | El hilo puede esperar: arranque, apagado, trabajos por lotes, pruebas. |
| Completion | `client.initialize_async(timeout, on_done)` | Ejecuta un event loop (C++17). La llamada retorna inmediatamente y `on_done` recibe el resultado. |
| Awaitable | `co_await client.co_initialize(timeout)` | Escribe corrutinas de 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);
```

Un completion es un `Completion<void>` (`std::function<void(std::exception_ptr)>`), o un `Completion<T>` (`std::function<void(std::exception_ptr, T)>`) para las operaciones que devuelven un valor. El SDK lo invoca exactamente una vez. Puede omitir el completion para ejecutar la operación en modo fire-and-forget: los fallos solo aparecerán entonces en el log del SDK.

<Warning>
  Los completions y los manejadores de eventos suelen ejecutarse en el hilo de trabajo del SDK, pero un completion también puede ejecutarse en el hilo que realiza la llamada, antes de que la llamada `*_async` retorne: por ejemplo, cuando el SDK falla rápidamente (el cliente no está listo, el visitor code no es válido) o cuando se llama a `initialize_async()` sobre un cliente que ya está inicializado. No asuma que un completion se ejecuta en un hilo concreto ni después de que la llamada retorne, y no mantenga un lock a través de la llamada que el completion también adquiere. Los completions y los manejadores de eventos no deben bloquear, no deben lanzar excepciones y no deben llamar a la forma bloqueante de una operación del SDK: esta espera al mismo hilo de trabajo y se produce un interbloqueo. Entregue el resultado a su propio event loop y termine el trabajo allí.
</Warning>

<Note>
  C++20 no tiene un tipo de tarea de corrutina integrado, por lo que `co_await` solo funciona dentro de una corrutina cuyo promise type acepte el `Awaitable<T>` del SDK (`KAMELEOON_HAS_COROUTINES` se define en `kameleoon/async.hpp` cuando las corrutinas están disponibles). De forma predeterminada, la corrutina se reanuda en el hilo de trabajo del SDK; llame a `.via(executor)` sobre el awaitable para reanudarla en su propio event loop. Los frameworks con sus propios tipos de corrutinas, como Boost.Asio, necesitan un pequeño adaptador alrededor de la forma completion; consulte el ejemplo de servidor incluido con el SDK.
</Note>

Los métodos de evaluación (`get_visitor_code()`, `get_variation()`, `get_variations()`, `is_feature_active()`, `add_data()`, `track_conversion()` y `flush()`) son llamadas síncronas en memoria y no necesitan nada de esto.

### Uso de una clave de bucketing personalizada

De forma predeterminada, Kameleoon utiliza un ID de visitante único y anónimo (`visitor_code`) para asignar a los usuarios a las variaciones de los feature flags. Este ID normalmente se genera y se almacena en el dispositivo del usuario (en una cookie del navegador para los SDKs del lado del cliente y del lado del servidor, y en almacenamiento persistente para los SDKs móviles). Sin embargo, en determinados escenarios puede necesitar garantizar que todos los usuarios de la misma organización vean la misma variante de un feature flag.

La opción de **clave de bucketing personalizada** le permite anular este comportamiento predeterminado proporcionando su propio identificador personalizado para el bucketing. Esta anulación garantiza que la lógica de asignación de Kameleoon utilice la clave que usted especifique en lugar del `visitor_code` predeterminado.

#### Casos de uso

Utilizar una clave de bucketing personalizada es esencial para mantener la coherencia y la precisión en las asignaciones de sus feature flags, especialmente en estas situaciones:

* **Experimentos a nivel de cuenta u organización:** Para productos B2B o escenarios en los que desea asignar a todos los usuarios de la misma organización a la misma variación, puede utilizar un identificador como un `account_id`. Las claves de bucketing personalizadas son cruciales para las pruebas A/B de funcionalidades que afectan a todo un equipo o empresa.

Al implementar una clave de bucketing personalizada, garantiza una mayor coherencia y precisión en sus experimentos, lo que conduce a resultados más fiables y a una mejor experiencia de usuario.

#### Detalles técnicos

Cuando configura una clave de bucketing personalizada para un feature flag, proporciona a Kameleoon un identificador específico procedente de los datos de su aplicación:

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

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

* **Proporcionar la clave personalizada:** Proporciona su identificador personalizado al SDK de Kameleoon mediante el método [`add_data()`](#add_data). En este método, pasará la clave de bucketing personalizada elegida como un objeto [`CustomData`](#customdata). Aquí, `new_visitor_code` hace referencia al identificador que desea utilizar para su bucketing (por ejemplo, el nuevo `user_id` o `account_id`).

<Warning>
  Para que la clave de bucketing personalizada funcione correctamente, también debe definirla y configurarla para el feature flag durante el proceso de creación o edición del flag. Sin esta configuración correspondiente, el bucketing del SDK no aplicará su clave personalizada. Para obtener instrucciones detalladas sobre cómo configurarlo en Kameleoon, consulte este [artículo](/es/user-manual/experimentation/feature-experimentation/create-and-manage-flags/create-a-feature-flag#configuración-avanzada-de-flags).
</Warning>

* **Lógica de bucketing:** Una vez que proporciona una clave de bucketing personalizada mediante el método `add_data()`, todos los cálculos de hash para asignar usuarios a variaciones utilizan este `new_visitor_code` (su clave personalizada) en lugar del `visitor_code` predeterminado. El uso del `new_visitor_code` significa que la decisión de bucketing depende de su identificador personalizado, lo que garantiza asignaciones coherentes en los distintos contextos donde ese identificador esté presente.
* **Seguimiento de datos y analítica:** Es crucial tener en cuenta que, aunque el `new_visitor_code` (su clave personalizada) se utiliza para las decisiones de bucketing, el SDK envía **todos los datos posteriores (eventos de seguimiento y conversiones, por ejemplo) y los asocia con el `visitor_code` *original*.** Esta separación garantiza que su analítica refleje con precisión los recorridos e interacciones individuales de los usuarios dentro del contexto más amplio de su experimento, incluso cuando realiza el bucketing a un nivel superior (como una cuenta) o entre varios dispositivos/sesiones. Los datos originales de sus visitantes permanecen intactos para disponer de informes completos.

#### Requisitos técnicos

Para utilizar eficazmente una clave de bucketing personalizada:

* La clave debe ser una `std::string`.
* Debe ser única para la entidad sobre la que desea hacer bucketing (por ejemplo, si utiliza un `user_id`, el ID de cada usuario debe ser único).
* La clave debe estar disponible para el SDK en el momento exacto en que evalúa la decisión del feature flag para ese usuario o solicitud.

### Condiciones de segmentación

Los SDKs de Kameleoon admiten una variedad de condiciones de segmentación predefinidas que puede utilizar para segmentar a los usuarios en sus campañas. Para ver la lista de condiciones que admite este SDK, consulte [utilizar el historial de visitas para segmentar a los usuarios](/es/developer-docs/feature-experimentation/targeting-and-segmentation/native-segmentation).

También puede utilizar sus propios [datos externos para segmentar a los usuarios](/es/developer-docs/apis/data-api-rest/tutorials/storing-and-retrieving-external-data-to-target-users).

### Experimentación cross-device

Para dar soporte a los visitantes que acceden a una aplicación desde varios dispositivos, Kameleoon permite sincronizar los datos de visitante recopilados previamente en cada uno de los dispositivos del visitante y reconciliar su historial de visitas entre dispositivos mediante la experimentación cross-device. Encontrará casos prácticos e información detallada sobre cómo Kameleoon gestiona los datos entre dispositivos en el [artículo sobre experimentación cross-device](/es/developer-docs/cross-device-experimentation).

#### Sincronizar custom data entre dispositivos

Aunque la sincronización de mapeo personalizado alinea los datos de los visitantes entre dispositivos, no siempre es necesaria. A continuación se muestran dos escenarios en los que la sincronización de mapeo personalizado no es necesaria:

**Mismo ID de usuario en todos los dispositivos**
Si utiliza el mismo ID de usuario de forma coherente en todos los dispositivos, el SDK gestiona la sincronización automáticamente sin una sincronización de mapeo personalizado. Basta con llamar al método `get_remote_visitor_data()` cuando desee sincronizar los datos recopilados entre varios dispositivos.

**Instancias multiservidor con IDs coherentes**
En configuraciones complejas con varios servidores (por ejemplo, instancias de servidor distribuidas), donde el mismo ID de usuario está disponible en todos los servidores, la sincronización entre servidores (con `get_remote_visitor_data()`) es suficiente sin una sincronización de mapeo personalizado adicional.

Los clientes que necesiten datos adicionales pueden consultar la descripción del método [`get_remote_visitor_data()`](#get_remote_visitor_data) para obtener más orientación. En el siguiente código, se asume que utiliza el mismo identificador único (en este caso, el `visitor_code`, también conocido como `userId`) de forma coherente entre los dos dispositivos para una recuperación precisa de los datos.

<Note>
  Si desea sincronizar los datos recopilados en tiempo real, debe elegir el ámbito **Visitor** para sus 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.
```

#### Uso de custom data para la fusión de sesiones

La [experimentación cross-device](/es/developer-docs/cross-device-experimentation) permite combinar el historial de un visitante en cada uno de sus dispositivos (reconciliación del historial). La reconciliación del historial permite fusionar diferentes sesiones del visitante en una sola. Para reconciliar el historial de visitas, utilice [`CustomData`](#customdata) para proporcionar un identificador único para el visitante. Para obtener más información, consulte la [documentación específica](/es/developer-docs/cross-device-experimentation/#activar-la-reconciliación-de-historial-entre-dispositivos).

Después de habilitar la reconciliación cross-device, llamar a [`get_remote_visitor_data()`](#get_remote_visitor_data) con el parámetro `userId` recupera todos los datos conocidos de un usuario determinado.

Las sesiones con el mismo identificador siempre ven la misma variación en un experimento. En la vista Visitor de las páginas de resultados de su experimento, estas sesiones aparecerán como un único visitante.

La configuración del SDK garantiza que las sesiones asociadas siempre vean la misma variación del experimento. Sin embargo, existen algunas limitaciones en cuanto a la asignación de variaciones cross-device. La [documentación de experimentación cross-device](/es/developer-docs/cross-device-experimentation#puntos-críticos-e-información-práctica) describe estas limitaciones.

Siga la guía de [activación de la reconciliación del historial cross-device](#experimentación-cross-device) para configurar sus custom data en la plataforma Kameleoon.

Después, puede utilizar el SDK con normalidad. Los siguientes métodos pueden resultar útiles en el contexto de la fusión de sesiones:

* `get_remote_visitor_data()` con el dato `UniqueIdentifier(true)` añadido - para recuperar los datos de todos los visitantes vinculados.
* [`track_conversion()`](#track_conversion) o [`flush()`](#flush) con el dato `UniqueIdentifier(true)` añadido - para realizar el seguimiento de datos de un visitante específico que está asociado con otro visitante.

<Tip>
  Dado que los custom data que utiliza como identificador requieren el **ámbito Visitor**, debe utilizar la [sincronización de custom data cross-device](/es/developer-docs/cross-device-experimentation) para recuperar el identificador con el método [`get_remote_visitor_data()`](#get_remote_visitor_data) en cada dispositivo.
</Tip>

A continuación se muestra un ejemplo de cómo utilizar custom data para la fusión de sesiones.

```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);
```

En este ejemplo, la aplicación tiene una página de inicio de sesión. Como el ID de usuario es desconocido en el momento del inicio de sesión, la aplicación utiliza un identificador de visitante anónimo generado por el método [`get_visitor_code()`](#get_visitor_code). Después de que el usuario inicie sesión, la aplicación asocia el visitante anónimo con el ID de usuario y lo utiliza como identificador único del visitante.

### Registro de eventos

El SDK genera logs para reflejar diversos procesos e incidencias internos.

#### Niveles de log

El SDK admite la configuración del logging limitándolo por nivel de log.

```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);
```

#### Gestión personalizada de los logs

De forma predeterminada, el SDK escribe sus logs en la salida de consola. Este comportamiento puede sobrescribirse.

<Note>
  El SDK limita el logging por nivel de log de forma independiente de la lógica de gestión de logs.
</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({});
```

## Referencia

Esta es la documentación de referencia completa del SDK de C++.

### Inicialización

#### create()

Para utilizar el SDK, cree un `KameleoonClient` con `KameleoonClientFactory::create()`, ya sea a partir de una estructura `KameleoonClientConfig` o de un archivo de configuración JSON.

Los clientes se almacenan en caché por site code y entorno: las llamadas repetidas a `create()` con el mismo site code y entorno devuelven clientes sobre la misma instancia subyacente del SDK, y prevalece la configuración de la primera llamada.

<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);
    ```

    ##### Parámetros

    | Nombre | Tipo | Descripción |
    | - | - | - |
    | `site_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Clave única del proyecto de Kameleoon utilizado por el SDK. |
    | `config` <Badge color="red" size="sm">obligatorio</Badge> | `KameleoonClientConfig` | Estructura de configuración del 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");
    ```

    ##### Parámetros

    | Nombre | Tipo | Descripción |
    | - | - | - |
    | `site_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Clave única del proyecto de Kameleoon utilizado por el SDK. |
    | `config_path` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Ruta al archivo de configuración JSON. |
  </Tab>
</Tabs>

##### Valor devuelto

| Tipo | Descripción |
| - | - |
| `KameleoonClient` | Una instancia del cliente. El cliente no está listo para evaluar feature flags hasta que [`initialize()`](#initialize) se haya completado. |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | El site code está vacío, `client_id` o `client_secret` está vacío, o el archivo de configuración no se puede leer o analizar. El mensaje de error indica la causa exacta. |
| `ErrorCode::Internal` | La biblioteca `libkameleoon_ffi` cargada no coincide con la versión contra la que se compiló el SDK. |

#### initialize()

Utilice `initialize()` cuando su aplicación deba esperar a que el cliente Kameleoon termine la inicialización antes de evaluar feature flags.

La llamada devuelve el resultado de la obtención de la configuración: se completa correctamente cuando el cliente termina de inicializarse, y falla si la obtención inicial de la configuración falla antes de que el cliente esté listo. Los reintentos en segundo plano continúan después de ese primer fallo. Una vez que un reintento tiene éxito, las llamadas posteriores devuelven un resultado satisfactorio. Si no hay ningún resultado de inicialización disponible antes de que expire el tiempo de espera, la llamada falla. Si no proporciona un valor de `timeout`, el SDK utiliza el tiempo de espera predeterminado de [`default_timeout_millis`](#configuración-adicional).

<Tip>
  Llame a `initialize()` una vez al arrancar la aplicación para esperar hasta que el SDK haya cargado su configuración o expire el tiempo de espera. En cada solicitud entrante, utilice [`is_ready()`](#is_ready) como protección no bloqueante antes de evaluar feature flags. Incluso si `initialize()` falla, el SDK sigue reintentando la obtención de la configuración en segundo plano, por lo que `is_ready()` empieza a devolver `true` cuando un reintento tiene éxito.
</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));
```

##### Parámetros

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `timeout` <Badge color="green" size="sm">opcional</Badge> | `std::optional<std::chrono::milliseconds>` | Tiempo máximo de espera de un resultado de inicialización. | `default_timeout_millis` |

##### Valor devuelto

| Tipo | Descripción |
| - | - |
| `void` | Retorna una vez que el SDK está listo. Lanza una `KameleoonException` si la obtención inicial de la configuración falla o si no hay ningún resultado de inicialización disponible antes de que expire el tiempo de espera. |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | No hubo ningún resultado de inicialización disponible antes de que expirara el tiempo de espera. |
| `ErrorCode::Network` | La obtención inicial de la configuración falló debido a un error de red o a un estado HTTP inesperado. El SDK sigue reintentando en segundo plano, por lo que una llamada posterior tiene éxito cuando lo tiene un reintento. |
| `ErrorCode::InvalidArgument` | El `timeout` proporcionado es cero o negativo. |

#### is\_ready()

`is_ready()` comprueba si el SDK está listo para su uso, lo que significa que su configuración se ha cargado correctamente. A diferencia de [`initialize()`](#initialize), este método retorna inmediatamente sin bloquear ni lanzar excepciones.

<Tip>
  * Una vez que el SDK está listo, permanece listo. Si una actualización posterior de la configuración falla, el SDK sigue utilizando la configuración descargada previamente y no vuelve a un estado de no listo.
  * Llame a `initialize()` una vez al arrancar la aplicación para esperar hasta que el SDK haya cargado su configuración o expire el tiempo de espera. En cada solicitud entrante, utilice [`is_ready()`](#is_ready) como protección no bloqueante antes de evaluar feature flags. Incluso si `initialize()` falla, el SDK sigue reintentando la obtención de la configuración en segundo plano, por lo que `is_ready()` empieza a devolver `true` cuando un reintento tiene éxito.
</Tip>

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

##### Valor devuelto

| Tipo | Descripción |
| - | - |
| `bool` | `true` si el SDK se ha inicializado correctamente; `false` en caso contrario (incluso mientras la inicialización todavía está pendiente o ha fallado). |

#### forget()

Elimina el cliente SDK en caché asociado al `site_code` especificado, de modo que la siguiente llamada a `create()` con el mismo site code y entorno cree uno nuevo.

`forget()` solo elimina la referencia de la factoría. Cada `KameleoonClient` creado para ese site code mantiene viva la instancia subyacente del SDK (y su hilo de trabajo, polling y seguimiento) hasta que se destruye, y las operaciones asíncronas pendientes la mantienen viva hasta que sus completions terminan. Para liberar los recursos en segundo plano, llame a `forget()` y destruya todas las instancias de `KameleoonClient` de ese 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");
```

##### Parámetros

| Nombre | Tipo | Descripción |
| - | - | - |
| `site_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del proyecto de Kameleoon. |
| `environment` <Badge color="green" size="sm">opcional</Badge> | `std::string` | Entorno con el que se creó el cliente. Un cliente creado con un `environment` solo se elimina cuando aquí se pasa el mismo valor. |

### Feature flags y variaciones

#### is\_feature\_active()

* 📨 *Envía datos de seguimiento a Kameleoon (según la opción `track`)*

Determina si un feature flag está activo para un usuario determinado.

Si el visitante aún no ha sido evaluado para este feature flag, el SDK evalúa las reglas de segmentación y devuelve el resultado. Si el visitante ya tiene una evaluación almacenada para la funcionalidad, el SDK reutiliza el resultado existente para garantizar la coherencia.

<Note>
  Kameleoon utiliza el seguimiento para contar sesiones y visitantes cuando llama a determinados métodos, como `is_feature_active()`, `get_variation()` o `get_variations()`.

  Utilice el valor predeterminado `true` para el parámetro `track` cuando exponga a los visitantes a una variación y necesite contarlos. Establezca el parámetro `track` en `false` solo si llama a estos métodos antes de exponer a los visitantes.

  Por ejemplo, si llama a `get_variations()` para recuperar todas las variaciones antes de exponer a los visitantes, establezca el parámetro `track` en `false`. Esta configuración evita que Kameleoon cuente prematuramente una sesión. Después puede activar el seguimiento más adelante, cuando exponga explícitamente al visitante.

  Kameleoon envía los datos de seguimiento cada segundo de forma predeterminada. Puede configurar este intervalo hasta 5 segundos mediante la opción de configuración del intervalo de seguimiento. Kameleoon agrupa los eventos de seguimiento en una única sesión siempre que el intervalo entre eventos sea inferior a 30 minutos. Si transcurren más de 30 minutos entre eventos de seguimiento, Kameleoon cuenta los eventos como sesiones separadas. Una visita aparece en sus informes 30 minutos después del último evento registrado en la sesión.
</Note>

<Warning>
  El método `is_feature_active()` evalúa la variante servida, no el estado del flag maestro. Si excluye reglas, el método utiliza el estado predeterminado **Then, for everyone else serve**. Si selecciona **Off** para este estado predeterminado, el método siempre devuelve `false`, incluso cuando el feature flag maestro está en **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});
```

##### Parámetros

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del usuario. | |
| `feature_key` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Clave de la funcionalidad que se evalúa para el usuario. | |
| `options` <Badge color="green" size="sm">opcional</Badge> | `IsFeatureActiveOptions` | Estructura de opciones con un único campo `track` (`bool`) que activa o desactiva el seguimiento de la evaluación de la funcionalidad. | `track = true` |

##### Valor devuelto

| Tipo | Descripción |
| - | - |
| `bool` | Indica si el feature flag está activo para el `visitor_code` especificado. |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::FeatureNotFound` | Excepción que indica que la clave de funcionalidad solicitada no se encontró en la configuración interna del SDK. Esto normalmente significa que el feature flag no está activado en la aplicación de Kameleoon (pero el código que implementa la funcionalidad ya está desplegado en la aplicación). |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |

#### get\_variation()

* 📨 *Envía datos de seguimiento a Kameleoon (según el parámetro `track`)*

Recupera la [`Variation`](#variation) asignada a un visitante determinado para un feature flag específico.

Este método toma un `visitor_code` y una `feature_key` como argumentos obligatorios. El argumento `track` es opcional y su valor predeterminado es `true`.

Devuelve la `Variation` asignada al visitante. Si el visitante no está asociado a ninguna regla del feature flag, el método devuelve la `Variation` predeterminada para el feature flag dado.

Asegúrese de que su código incluye una gestión de errores adecuada para manejar posibles excepciones.

<Note>
  La variación predeterminada hace referencia a la variación asignada a un visitante cuando no coincide con ninguna regla de entrega predefinida de un feature flag. En otras palabras, es la variación de respaldo que se aplica a todos los usuarios que no están segmentados por reglas específicas. Se representa como la variación de la sección "Then, for everyone else..." en la interfaz de administración.
</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});
```

##### Parámetros

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del visitante. | |
| `feature_key` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Clave de la funcionalidad que desea exponer a un visitante. | |
| `track` <Badge color="green" size="sm">opcional</Badge> | `bool` | Parámetro opcional para activar o desactivar el seguimiento de la evaluación de la funcionalidad. | `true` |

<Note>
  El parámetro opcional `track` se pasa como el campo `track` de una estructura `GetVariationOptions`.
</Note>

##### Valor devuelto

| Tipo | Descripción |
| - | - |
| `Variation` | Una [`Variation`](#variation) asignada a un visitante determinado para un feature flag específico. |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |
| `ErrorCode::FeatureNotFound` | Excepción que indica que la clave de funcionalidad solicitada no se encontró en la configuración interna del SDK. Esto normalmente significa que el feature flag no está activado en la aplicación de Kameleoon (pero el código que implementa la funcionalidad ya está desplegado en la aplicación). |
| `ErrorCode::FeatureEnvironmentDisabled` | Excepción que indica que el feature flag está desactivado para el entorno actual del visitante (por ejemplo, production, staging o development). |
| `ErrorCode::FeatureEvaluationBlocked` | Excepción que indica que la evaluación de la funcionalidad está bloqueada. El motivo se describe en el mensaje de error. Esto suele ocurrir debido a las restricciones del RGPD cuando el visitante no ha dado su consentimiento legal. |

#### get\_variations()

* 📨 *Envía datos de seguimiento a Kameleoon (según el parámetro `track`)*

Recupera un mapa de objetos [`Variation`](#variation) asignados a un visitante determinado en todos los feature flags.

Este método itera sobre todos los feature flags disponibles y devuelve la `Variation` asignada para cada flag asociado al visitante especificado. Toma `visitor_code` como argumento obligatorio, mientras que `only_active` y `track` son opcionales.

* Si establece `only_active` en `true`, el método `get_variations()` devuelve las variaciones de los feature flags solo si el visitante no está asignado a la variación `off`.
* El parámetro `track` controla si el método realiza el seguimiento de las asignaciones de variaciones. De forma predeterminada, es `true`. Si es `false`, el método no realiza el seguimiento de las asignaciones de variaciones.

El mapa devuelto está formado por las claves de los feature flags como claves y su `Variation` correspondiente como valores. Si el SDK no asigna ninguna variación para un feature flag, el método devuelve la `Variation` predeterminada de ese flag.

Implemente una gestión de errores adecuada para manejar posibles excepciones.

<Note>
  La variación predeterminada hace referencia a la variación asignada a un visitante cuando no coincide con ninguna regla de entrega predefinida de un feature flag. En otras palabras, es la variación de respaldo que se aplica a todos los usuarios que no están segmentados por reglas específicas. Se representa como la variación de la sección "Then, for everyone else..." en la interfaz de administración.
</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});
```

##### Parámetros

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del visitante. | |
| `only_active` <Badge color="green" size="sm">opcional</Badge> | `bool` | Parámetro opcional que indica si se devuelven las variaciones de los feature flags activos (`true`) o de todos (`false`). | `false` |
| `track` <Badge color="green" size="sm">opcional</Badge> | `bool` | Parámetro opcional para activar o desactivar el seguimiento de la evaluación de la funcionalidad. | `true` |

<Note>
  Los parámetros opcionales `only_active` y `track` se pasan como los campos de una estructura `GetVariationsOptions`.
</Note>

##### Valor devuelto

| Tipo | Descripción |
| - | - |
| `std::unordered_map<std::string, Variation>` | Mapa que contiene los objetos [`Variation`](#variation) asignados de los feature flags utilizando las claves de las funcionalidades correspondientes. |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |

#### set\_forced\_variation()

Este método le permite asignar mediante programación una [`Variation`](#variation) específica a un usuario, omitiendo el proceso de evaluación estándar. El método es especialmente valioso para experimentos controlados donde la lógica de evaluación habitual no es necesaria o debe omitirse. También puede ser útil en escenarios como la depuración o las pruebas personalizadas.

Cuando establece una variación **forzada**, esta anula la lógica de evaluación en tiempo real de Kameleoon. El SDK omite procesos como la segmentación, las condiciones de segmentación y los cálculos algorítmicos. Para conservar la segmentación y las condiciones de segmentación durante un experimento, establezca `force_targeting=false` en su lugar.

<Info>
  Las variaciones **simuladas** siempre tienen prioridad en el orden de ejecución. Si comienza el cálculo de una variación **simulada**, el SDK la procesa y la completa totalmente primero.
</Info>

Kameleoon trata una variación forzada igual que una variación evaluada. Se registra en la analítica y se almacena en el contexto del usuario como cualquier variación evaluada estándar, lo que garantiza la coherencia en los informes.

El método puede lanzar excepciones en determinadas condiciones (por ejemplo, parámetros no válidos, contexto de usuario o problemas internos). Una gestión adecuada de las excepciones es esencial para garantizar que su aplicación permanezca estable y resiliente.

<Warning>
  Es importante distinguir las variaciones **forzadas** de las variaciones **[simuladas](#get_visitor_code)**:

  * **Variaciones forzadas**: Son específicas de un experimento individual.
  * **Variaciones simuladas**: Afectan al resultado global del **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});
```

##### Parámetros

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del visitante. | |
| `experiment_id` <Badge color="red" size="sm">obligatorio</Badge> | `uint32_t` | **Id del experimento** que el SDK segmenta y selecciona durante el proceso de evaluación. | |
| `variation_key` <Badge color="red" size="sm">obligatorio</Badge> | `std::optional<std::string>` | **Clave de la variación** correspondiente a una `Variation` que el SDK fuerza como valor devuelto para el experimento. Si el valor es `std::nullopt`, la variación forzada se restablecerá. | |
| `force_targeting` <Badge color="green" size="sm">opcional</Badge> | `bool` | Indica si el SDK fuerza y omite la segmentación para el experimento (`true`) o la aplica como en el proceso de evaluación estándar (`false`). | `true` |

<Note>
  El parámetro opcional `force_targeting` se pasa como el campo `force_targeting` de una estructura `SetForcedVariationOptions`.
</Note>

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |
| `ErrorCode::FeatureExperimentNotFound` | Excepción que indica que el id del experimento solicitado no está en la configuración interna del SDK. Este comportamiento suele ser normal y significa que el experimento correspondiente a la regla aún no está activo del lado de Kameleoon. |
| `ErrorCode::FeatureVariationNotFound` | Excepción que indica que la clave (id) de la variación solicitada no está en la configuración interna del SDK. Este comportamiento suele ser normal y significa que el experimento correspondiente a la variación aún no está activo del lado de Kameleoon. |

#### evaluate\_audiences()

* 📨 *Envía datos de seguimiento a Kameleoon*

Este método evalúa a los visitantes con respecto a todos los segmentos disponibles de Audiences Explorer y realiza el seguimiento de los que coinciden.

Llame a `evaluate_audiences()` **después de establecer o actualizar todos los datos relevantes del visitante**, y **justo antes** de obtener la variación de una funcionalidad o comprobar un feature flag. Este enfoque garantiza que Kameleoon evalúe al visitante con los datos más actuales disponibles, lo que permite una asignación de audiencias precisa basada en todos los criterios.

Después de llamar a este método, puede realizar un análisis detallado del rendimiento de los segmentos en Audiences Explorer.

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

##### Parámetros

| Nombre | Tipo | Descripción |
| - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del visitante. |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |

<Info>
  En la mayoría de los casos, solo necesita gestionar el error básico, `KameleoonException`, como muestra el ejemplo. Sin embargo, si distintos tipos de errores requieren una respuesta, gestione cada uno por separado según los requisitos específicos. Además, para una mayor fiabilidad, puede gestionar los errores generales del lenguaje incluyendo `std::exception`.
</Info>

#### get\_datafile()

<Tip>
  Para evaluar todos los feature flags, utilice [`get_variations()`](#get_variations). Este método es más eficiente que llamar a `DataFile` e iterar por los flags con [`get_variation()`](#get_variation).
</Tip>

Devuelve la configuración actual del SDK como un objeto [`DataFile`](#datafile).

El `DataFile` devuelto es una copia de la configuración actual: no cambia cuando el SDK actualiza su configuración.

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

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

##### Valor devuelto

| Tipo | Descripción |
| - | - |
| `DataFile` | El [`DataFile`](#datafile) que contiene la configuración del SDK |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |

### Datos del visitante

#### get\_visitor\_code()

Utilice `get_visitor_code()` para obtener el `visitor_code` de Kameleoon del visitante actual. El método funciona con cualquier almacén de cookies que implemente la interfaz `CookieAccessor`.

La lógica de implementación es la siguiente:

1. El SDK comprueba si ya hay una cookie `kameleoonVisitorCode` disponible a través del accessor proporcionado.
2. Si la cookie no existe, el SDK utiliza `default_visitor_code` si usted proporciona uno.
3. En caso contrario, el SDK genera un nuevo visitor code y lo almacena a través del accessor.

Para obtener más información, consulte [Experimentación híbrida](/es/developer-docs/feature-experimentation/get-started/hybrid-experimentation/).

<Warning>
  Si proporciona su propio `visitor_code`, su unicidad debe garantizarse por su parte. Tenga en cuenta también que la longitud del `visitor_code` está limitada a `255` caracteres.
</Warning>

<Info>
  El método `get_visitor_code()` le permite establecer variaciones **simuladas** para un visitante. Cuando las cookies (de una **solicitud** o un **documento**) contienen la clave `kameleoonSimulationFFData`, el método lee la cookie y almacena las variaciones simuladas para ese visitante; su valor devuelto no cambia. Las evaluaciones de funcionalidades posteriores para el visitante, como [`get_variation()`](#get_variation) e [`is_feature_active()`](#is_feature_active), omiten entonces el proceso de evaluación estándar y devuelven la [`Variation`](#variation) simulada según los datos proporcionados.

  Puede aplicar simulaciones de dos maneras:

  * **Automáticamente (recomendado):** Si utiliza Kameleoon Web Experimentation o el SDK en [modo híbrido](/es/developer-docs/feature-experimentation/get-started/hybrid-experimentation#vincular-feature-experiments-con-código-de-tracking-en-el-frontend), Kameleoon crea la cookie automáticamente cuando simula la visualización de una variante mediante el [panel de simulación](/es/user-manual/experimentation/feature-experimentation/using-the-rollout-planner/validation-and-rollback/using-simulation-mode).
  * **Manualmente:** Establezca la cookie `kameleoonSimulationFFData` manualmente.

  Es importante distinguir las variaciones **simuladas** de las variaciones **[forzadas](#set_forced_variation)**:

  * **Variaciones simuladas**: Afectan al resultado global del **feature flag**.
  * **Variaciones forzadas**: Son específicas de un experimento individual.

  ⚙️ **Configuración manual**

  Asegúrese de que la cookie `kameleoonSimulationFFData` sigue este formato:

  * `kameleoonSimulationFFData={"featureKey":{"expId":10,"varId":20}}`: Simula la variación con `varId` del experimento `expId` para la `featureKey` dada.
  * `kameleoonSimulationFFData={"featureKey":{"expId":0}}`: Simula la variación predeterminada (definida en la sección **Then, for everyone else in Production, serve**) para la `featureKey` dada.

  ⚠️ Para garantizar que el valor de la cookie funcione correctamente, codifíquelo como componente URI utilizando un método como [`encodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent).
</Info>

##### Interfaz `CookieAccessor`

Implemente `kameleoon::CookieAccessor` para conectar las lecturas y escrituras de cookies del SDK con su framework HTTP:

| Método | Descripción |
| - | - |
| `std::optional<std::string> get(const std::string& key)` | Devuelve el valor de la cookie para `key`, o `std::nullopt` cuando la cookie no existe. |
| `void set(const std::string& key, const std::string& value, uint32_t max_age, std::optional<std::string> top_level_domain)` | Almacena la cookie en la respuesta, con el `max_age` (en segundos) y, cuando está presente, el `top_level_domain` como dominio de la cookie. |

<Note>
  * `get()` debe devolver una cookie ya escrita mediante `set()` en la respuesta con preferencia sobre la cookie de la solicitud con el mismo nombre. El SDK no mantiene ningún estado de cookies entre llamadas, por lo que esto es lo que hace que una segunda llamada a `get_visitor_code()` dentro de la misma solicitud devuelva el código escrito por la primera en lugar de generar uno nuevo.
  * Las sobrescrituras se invocan desde el interior del SDK y no deben lanzar excepciones. Una excepción que escape de `get()` se trata como una cookie ausente. Los valores de las cookies deben ser UTF-8 válido.
</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>

##### Parámetros

| Nombre | Tipo | Descripción |
| - | - | - |
| `cookies` <Badge color="red" size="sm">obligatorio</Badge> | `CookieAccessor&` | Accessor de cookies utilizado para leer y almacenar la cookie del visitante. |
| `default_visitor_code` <Badge color="green" size="sm">opcional</Badge> | `std::optional<std::string>` | Visitor code que se utiliza cuando no hay ninguna cookie presente. |

##### Valor devuelto

| Tipo | Descripción |
| - | - |
| `std::string` | Cadena que representa un visitor code único utilizado en el SDK. |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |
| `ErrorCode::InvalidSimVarCookieFormat` | Indica que la cookie `kameleoonSimulationFFData` contiene JSON mal formado y que las variaciones simuladas no se pudieron analizar. |

#### add\_data()

El método `add_data()` añade [datos de segmentación](#tipos-de-datos) al almacenamiento para que otros métodos puedan utilizar los datos a la hora de decidir si segmentar o no al visitante actual.

El método `add_data()` no devuelve ningún valor y no interactúa por sí mismo con los servidores backend de Kameleoon. En su lugar, el SDK guarda todos los datos declarados para su transmisión futura mediante el método [`flush()`](#flush). Este enfoque reduce el número de llamadas al servidor, ya que los datos normalmente se agrupan en una única llamada al servidor activada por `flush()`.

El método [`track_conversion()`](#track_conversion) también envía cualquier dato asociado previamente, igual que `flush()`. Lo mismo ocurre con los métodos [`get_variation()`](#get_variation) y [`get_variations()`](#get_variations) si se activa una regla de experimentación.

<Tip>
  Cada visitante solo puede tener una instancia de datos asociados para la mayoría de los tipos de datos. Sin embargo, [`CustomData`](#customdata) es una excepción. Los visitantes pueden tener una instancia de `CustomData` asociada por índice.
</Tip>

El parámetro `data` es un `std::vector<Data>`, donde `Data` es un `std::variant` de todos los [tipos de datos](#tipos-de-datos). Cada tipo de dato se convierte implícitamente a `Data`, por lo que puede pasar una lista entre llaves de objetos de datos.

```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);
```

##### Parámetros

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del visitante. | |
| `data` <Badge color="red" size="sm">obligatorio</Badge> | `const std::vector<Data>&` | Colección de tipos de datos de Kameleoon. | |
| `track` <Badge color="green" size="sm">opcional</Badge> | `bool` | Especifica si los datos añadidos son aptos para el seguimiento. Cuando se establece en `false`, el SDK almacena los datos localmente, los utiliza únicamente para la evaluación de la segmentación y no los envía a la Data API de Kameleoon. | `true` |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |
| `ErrorCode::InvalidArgument` | Una cadena no es UTF-8 válido o un valor de enum es desconocido. |

#### flush()

* *📨 Envía datos de seguimiento a Kameleoon*

El método `flush()` agrega todos los datos de Kameleoon asociados a un visitante y envía una solicitud de seguimiento al servidor. Esta solicitud incluye cualquier dato añadido previamente mediante el método [`add_data`](#add_data) que aún no se haya transmitido a través de otros mecanismos de seguimiento (consulte los métodos mencionados para más detalles). La operación `flush()` es no bloqueante, ya que la llamada al servidor se realiza de forma asíncrona.

Este método proporciona control sobre cuándo se transmiten los datos vinculados a un `visitor_code` específico. Por ejemplo, si se llama a `add_data()` varias veces, enviar una solicitud después de cada invocación sería ineficiente. En su lugar, puede agrupar estas actualizaciones y llamar a `flush()` una sola vez para enviar todos los datos acumulados en una única solicitud.

El método `flush()` utiliza el `visitor_code` proporcionado como identificador único del visitante.

<Tip>
  * `flush()`: Pone en cola una operación de flush según el intervalo de seguimiento configurado.
  * `flush_instant()`: Envía los datos de seguimiento inmediatamente sin esperar al intervalo.
</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);
```

##### Parámetros

| Nombre | Tipo | Descripción |
| - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del visitante. |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |

#### get\_remote\_data()

El método `get_remote_data()` le permite recuperar datos remotos almacenados en los servidores de Kameleoon para la `key` especificada. En la mayoría de las configuraciones, estos datos se escriben a través de la Data API de Kameleoon y su servicio C++ puede recuperarlos más tarde siempre que necesite contexto adicional de la aplicación.

Este método es útil cuando desea mantener información estructurada en la infraestructura remota de Kameleoon y reutilizarla desde su back-end sin mantener un mecanismo de recuperación independiente.

```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");
```

##### Parámetros

| Nombre | Tipo | Descripción |
| - | - | - |
| `key` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Clave asociada a los datos remotos que desea recuperar. |

##### Valor devuelto

| Tipo | Descripción |
| - | - |
| `std::string` | Contenido asociado a la `key` especificada. En la mayoría de los casos, el contenido es JSON serializado como cadena. El contenido es una cadena de bytes y puede contener bytes arbitrarios. |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::Network` | Se lanza cuando la solicitud de datos remotos falla o el servidor responde con un código de estado de error. |

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

`get_remote_visitor_data()` recupera los datos de visita de Kameleoon para el `visitor_code` proporcionado. El método añade los datos al almacenamiento local del visitante para que otros métodos del SDK puedan utilizarlos en las decisiones de segmentación.

Los datos obtenidos con este método son especialmente útiles cuando desea:

* utilizar datos recopilados desde otros dispositivos.
* acceder al historial de un visitante, como las páginas vistas en visitas anteriores.
* utilizar datos que solo están disponibles del lado del cliente, como variables del datalayer y conversiones de objetivos del front-end.

Lea [este artículo](/es/developer-docs/feature-experimentation/targeting-and-segmentation/native-segmentation) para comprender mejor los posibles casos de uso.

<Warning>
  De forma predeterminada, `get_remote_visitor_data()` recupera automáticamente los últimos custom data almacenados con `scope=Visitor` y los asocia al visitante sin necesidad de llamar a [`add_data()`](#add_data). Esto es especialmente útil para [sincronizar custom data entre varios dispositivos](/es/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);
```

##### Parámetros

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Visitor code cuyos datos deben recuperarse. | |
| `filter` <Badge color="green" size="sm">opcional</Badge> | `RemoteVisitorDataFilter` | Filtro que describe qué datos remotos del visitante deben recuperarse. | `RemoteVisitorDataFilter{}` |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |
| `ErrorCode::Network` | Se lanza cuando la solicitud de datos remotos del visitante falla, no se puede analizar, o el servidor responde con un código de estado de error. |

##### Uso de parámetros en get\_remote\_visitor\_data()

El método `get_remote_visitor_data()` le permite controlar qué datos se recuperan para un visitante. El mismo enfoque de filtrado funciona para objetivos, experimentos, variaciones y otros datos del visitante.

Por ejemplo, si desea segmentar a los usuarios que convirtieron en un objetivo durante sus últimas cinco visitas, puede establecer `previous_visit_amount` en `5` y `conversions` en `true`.

La flexibilidad que muestra este ejemplo no se limita a los datos de objetivos. Puede utilizar el filtro para recuperar muchos comportamientos diferentes del visitante y ponerlos a disposición de la lógica de segmentación e informes de su aplicación C++.

##### Campos de `RemoteVisitorDataFilter`

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `previous_visit_amount` | `uint32_t` | Número de visitas anteriores de las que se recuperan datos. | `1` |
| `current_visit` | `bool` | Si es `true`, se recuperarán los datos de la visita actual. | `true` |
| `custom_data` | `bool` | Si es `true`, se recuperarán los custom data. | `true` |
| `visitor_code` | `bool` | Si es `true`, se reutilizará el visitor code más reciente. | `true` |
| `page_views` | `bool` | Si es `true`, se recuperarán los datos de páginas vistas. | `false` |
| `geolocation` | `bool` | Si es `true`, se recuperarán los datos de geolocalización. | `false` |
| `device` | `bool` | Si es `true`, se recuperarán los datos del dispositivo. | `false` |
| `browser` | `bool` | Si es `true`, se recuperarán los datos del navegador. | `false` |
| `operating_system` | `bool` | Si es `true`, se recuperarán los datos del sistema operativo. | `false` |
| `conversions` | `bool` | Si es `true`, se recuperarán los datos de conversiones. | `false` |
| `experiments` | `bool` | Si es `true`, se recuperarán los datos de experimentos. | `false` |
| `kcs` | `bool` | Si es `true`, se recuperarán los datos del Kameleoon Conversion Score. | `false` |
| `personalizations` | `bool` | Si es `true`, se recuperarán los datos de personalizaciones. | `false` |
| `cbs` | `bool` | Si es `true`, el SDK recupera los datos de puntuación del Contextual Bandit. | `false` |

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

Este método recupera los datos de audiencia asociados a un visitante en su integración de warehouse utilizando el `visitor_code` especificado y, opcionalmente, una `warehouse_key`. La `warehouse_key` suele ser su ID de usuario interno. El parámetro `custom_data_index` corresponde al custom data de Kameleoon que Kameleoon utiliza para segmentar a sus visitantes.

Cuando la llamada tiene éxito, el SDK convierte la lista de audiencias devuelta en [`CustomData`](#customdata), la añade al visitante localmente y la pone a disposición con fines de segmentación. Para obtener más contexto, consulte la [documentación de segmentación por warehouse](/es/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");
```

##### Parámetros

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Visitante cuyas audiencias de warehouse deben recuperarse. | |
| `custom_data_index` <Badge color="red" size="sm">obligatorio</Badge> | `uint32_t` | Índice del custom data configurado en Kameleoon para la segmentación por audiencias de warehouse. | |
| `warehouse_key` <Badge color="green" size="sm">opcional</Badge> | `std::optional<std::string>` | Clave externa del warehouse, normalmente su ID de usuario interno. Cuando se omite, el SDK utiliza `visitor_code`. | `std::nullopt` |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |
| `ErrorCode::Network` | Se lanza cuando la solicitud de audiencias de warehouse falla, no se puede analizar, o el servidor responde con un código de estado de error. |

#### set\_legal\_consent()

Debe utilizar este método para especificar si el visitante ha dado su consentimiento legal para el uso de datos personales. Establecer `consent` en `false` limita los tipos de datos que pueden incluirse en las solicitudes de seguimiento. Esto le ayuda a cumplir los requisitos legales y normativos mientras gestiona de forma responsable los datos de los visitantes. Para obtener más información, consulte la [política de gestión del consentimiento](/es/user-manual/project-management/consent-management-policy).

Si pasa un `CookieAccessor`, el SDK también actualiza las cookies del visitante según el estado del consentimiento.

```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);
```

##### Parámetros

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del usuario. | |
| `consent` <Badge color="red" size="sm">obligatorio</Badge> | `bool` | `true` indica que el visitante ha dado su consentimiento legal, `false` indica que el visitante nunca ha dado su consentimiento legal o lo ha retirado. | |
| `cookies` <Badge color="green" size="sm">opcional</Badge> | `CookieAccessor*` | Accessor de cookies opcional utilizado para actualizar las cookies. | `nullptr` |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |

##### Comportamiento al revocar el consentimiento

Cuando llama a `set_legal_consent()` con `consent=false`, el SDK no elimina la cookie `kameleoonVisitorCode`. En su lugar, deja de ampliar la fecha de expiración de la cookie, permitiendo que la cookie persista hasta que expire de forma natural.

Si sus requisitos de cumplimiento exigen la eliminación inmediata del archivo de la cookie al darse de baja, debe eliminarlo manualmente utilizando los métodos nativos de gestión de cookies de su framework. El SDK no eliminará el archivo automáticamente.

### Objetivos y analítica de terceros

#### track\_conversion()

* 📨 *Envía datos de seguimiento a Kameleoon*

Utilice este método para realizar el seguimiento de una conversión para un [objetivo](/es/user-manual/assets/goals/create-a-goal) y un usuario específicos. Este método requiere `visitor_code` y `goal_id`. Además, este método también acepta los argumentos opcionales `revenue`, `negative` y `metadata`. El `visitor_code` suele ser idéntico al que utilizó al activar el experimento.

<Tip>
  Este método es no bloqueante porque el SDK realiza la llamada al servidor de forma asíncrona.
</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"})}});
```

##### Parámetros

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del visitante. | |
| `goal_id` <Badge color="red" size="sm">obligatorio</Badge> | `uint32_t` | ID del objetivo. | |
| `revenue` <Badge color="green" size="sm">opcional</Badge> | `float` | Ingresos de la conversión. | `0` |
| `negative` <Badge color="green" size="sm">opcional</Badge> | `bool` | Define si los ingresos son positivos o negativos. | `false` |
| `metadata` <Badge color="green" size="sm">opcional</Badge> | `std::vector<CustomData>` | Metadatos de la conversión. [Deben definirse previamente en la aplicación de Kameleoon](/es/user-manual/assets/goals/create-a-goal#metadatos). | `{}` |

<Note>
  Los parámetros opcionales `revenue`, `negative` y `metadata` se pasan como los campos de una estructura `TrackConversionOptions`.
</Note>

<Note>
  Los valores de metadata son accesibles mediante las [exportaciones de datos sin procesar](/es/user-manual/experiment-analytics/analyze-results/results-page/results-page-actions#exportar) y [la página de resultados](/es/user-manual/experiment-analytics/analyze-results/data-and-metrics/goal-metadata).

  Si proporciona el parámetro `metadata`, Kameleoon utiliza estos valores especificados para la conversión actual en lugar de los que recopiló previamente con el método [`add_data()`](#add_data). Si omite el parámetro, Kameleoon utiliza los últimos valores registrados de esos [`CustomData`](#customdata) antes de la conversión y dentro de la misma visita.

  Kameleoon solo tendrá en cuenta los valores de metadata que se pasen explícitamente como parámetros al método `track_conversion()`.

  En el siguiente ejemplo, Kameleoon asociará la conversión únicamente con el valor de custom data proporcionado explícitamente como parámetro (aquí: el índice 5 con el valor '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>

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |

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

Kameleoon se integra con varias soluciones de analítica, como Mixpanel, Google Analytics 4 y Segment. Para realizar correctamente el seguimiento de los experimentos del lado del servidor, llame al método `get_engine_tracking_code()` después de que el visitante active un experimento. El SDK devuelve comandos de cola de JavaScript para los experimentos que el visitante activó durante los 5 segundos anteriores. Cuando inserta este código en la página, Engine.js procesa los comandos y envía los eventos de exposición a través de la integración de analítica activa.

Consulte [experimentación híbrida](/es/developer-docs/feature-experimentation/get-started/hybrid-experimentation) para obtener más información sobre la implementación de este método.

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

<Note>
  * Para utilizar esta funcionalidad, implemente tanto el SDK de C++ como [Engine.js](/es/developer-docs/web-experimentation/implementation-and-deployment/standard-implementation) de Kameleoon. Dado que este flujo utiliza Engine.js solo para el seguimiento, puede instalar la etiqueta asíncrona antes de la etiqueta de cierre `</body>`.
  * Si solo desea realizar el seguimiento de los experimentos en Kameleoon y no necesita enviar eventos de exposición a herramientas de analítica de terceros, utilice el [SDK de JavaScript / TypeScript](/es/developer-docs/sdks/web-sdks/js-sdk). Esta opción funciona bien para las [plataformas serverless de edge compute](/es/developer-docs/feature-experimentation/implementation-and-deployment/serverless-edge-compute-starter-kits). El SDK de JavaScript / TypeScript realiza automáticamente el seguimiento de las variaciones cuando llama a [`getVisitorCode`](/es/developer-docs/sdks/web-sdks/js-sdk#getvisitorcode), siempre que añada las asignaciones de experimentos correspondientes a `window.kameleoonQueue`.
  * Puede insertar el código de seguimiento devuelto directamente en una etiqueta 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>
  ```

  En este ejemplo, `123456` y `234567` son IDs de experimentos, y `7890` y `8901` son IDs de variaciones. En su implementación, el SDK genera estos valores en el código de seguimiento devuelto.
</Note>

##### Parámetros

| Nombre | Tipo | Descripción |
| - | - | - |
| `visitor_code` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | Identificador único del visitante. |

##### Valor devuelto

| Tipo | Descripción |
| - | - |
| `std::string` | Código JavaScript que se debe insertar en la página. |

##### Excepciones

| Tipo | Descripción |
| - | - |
| `ErrorCode::Initialization` | Indica que el SDK aún no está completamente inicializado. |
| `ErrorCode::VisitorCodeInvalid` | Excepción que indica que el visitor code proporcionado no es válido. Está vacío o tiene más de 255 caracteres. |

### Eventos

#### set\_event\_handler()

Utilice este método para registrar un manejador de eventos del SDK. El SDK llama al manejador cuando se produce el evento seleccionado. El cliente mantiene como máximo un manejador por tipo de evento: registrar un nuevo manejador para el mismo tipo de evento sustituye al anterior.

El constructor de `EventHandler` que utilice (`EventHandler::datafile_update()` o `EventHandler::http_request()`) selecciona el tipo de evento, por lo que un manejador y los eventos que recibe no pueden desincronizarse. Pasar un `std::function` vacío (`{}`) elimina el manejador actual para el tipo de evento seleccionado.

<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` contiene información sobre una actualización del archivo de datos del SDK.

      | Nombre | Tipo | Descripción |
      | - | - | - |
      | `source` | `DataFileUpdateSource` | La fuente de la actualización. [`DataFileUpdateSource::Polling`](/es/developer-docs/feature-experimentation/technical-reference/technical-considerations#polling-predeterminado) indica una actualización programada del archivo de datos, y [`DataFileUpdateSource::Streaming`](/es/developer-docs/feature-experimentation/technical-reference/technical-considerations#streaming-opción-premium) indica una actualización en tiempo real recibida mediante el modo streaming. |
      | `date_modified` | `uint64_t` | La fecha de modificación del archivo de datos actualizado, en milisegundos. |
    </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` es un `std::variant<HttpRequestSucceeded, HttpRequestFailed>`. El SDK notifica el evento una vez por cada intento real de solicitud HTTP, incluidos los reintentos. Utilice `std::get_if` o `std::visit` para distinguir una solicitud exitosa de una fallida.

      | Tipo | Descripción |
      | - | - |
      | `HttpRequestSucceeded` | Describe una solicitud HTTP del SDK que se completó correctamente. Siempre incluye `http_status`. |
      | `HttpRequestFailed` | Describe una solicitud HTTP del SDK que falló debido a un estado HTTP, un error o una cancelación. Siempre incluye `failure`. |

      <Accordion title="Campos de datos del evento y detalles del fallo">
        ##### Campos de datos del evento

        | Nombre | Tipo | Descripción |
        | - | - | - |
        | `request_type` | `RequestType` | El tipo de solicitud del SDK. Los valores posibles son `RequestType::DataFile`, `RequestType::Tracking`, `RequestType::RemoteVisitorData`, `RequestType::RemoteData` y `RequestType::AccessToken`. |
        | `http_status` | `uint16_t` | El código de estado HTTP devuelto por la solicitud. Presente solo en `HttpRequestSucceeded`. |
        | `failure` | `HttpRequestFailure` | Detalles sobre el motivo por el que falló la solicitud. Presente solo en `HttpRequestFailed`. |
        | `duration` | `std::chrono::milliseconds` | La duración de la solicitud. |

        ##### HttpRequestFailure

        `HttpRequestFailure` contiene detalles sobre una solicitud HTTP del SDK fallida.

        | Nombre | Tipo | Descripción |
        | - | - | - |
        | `reason` | `HttpRequestFailureReason` | El motivo del fallo. Los valores posibles son `HttpRequestFailureReason::HttpStatus`, `HttpRequestFailureReason::Error` y `HttpRequestFailureReason::Cancelled`. |
        | `http_status` | `std::optional<uint16_t>` | El código de estado HTTP para los fallos causados por una respuesta HTTP no satisfactoria. Este valor es `std::nullopt` para los fallos por excepción y por cancelación. |
        | `cause` | `std::optional<std::string>` | La excepción (error) que provocó el fallo de la solicitud. Este valor es `std::nullopt` cuando la solicitud falló debido a un estado HTTP o una cancelación. |
      </Accordion>
    </Tip>
  </Tab>
</Tabs>

<Note>
  Los manejadores se llaman de forma síncrona en el único hilo de trabajo del SDK, por lo que no deben bloquear: el tiempo que se pasa en un manejador retrasa el polling del archivo de datos y los envíos de seguimiento. Deben ser thread-safe y no deben lanzar excepciones: una excepción que escape de un manejador se captura y se descarta, y nunca afecta al comportamiento del SDK. No llame a operaciones bloqueantes del SDK desde un manejador; utilice las formas `*_async` y termine el trabajo en un hilo de la aplicación.

  Una invocación ya en curso puede terminar después de que elimine el manejador o destruya el cliente, y el manejador (con sus capturas) se destruye en un hilo del SDK una vez que ya no se utiliza. Mantenga los objetos capturados vivos y thread-safe en consecuencia. Un manejador puede eliminarse o sustituirse a sí mismo.

  Todas las instancias de `KameleoonClient` creadas para el mismo site code y entorno comparten un manejador por tipo de evento: prevalece el último manejador establecido, y destruir cualquiera de esas instancias lo elimina. Mantenga una única instancia de cliente por site code y entorno.
</Note>

##### Parámetros

| Nombre | Tipo | Descripción |
| - | - | - |
| `handler` <Badge color="red" size="sm">obligatorio</Badge> | `EventHandler` | El manejador que se registra, construido con `EventHandler::datafile_update()` a partir de un `DataFileUpdateHandler` (`std::function<void(const DataFileUpdateEvent&)>`), o con `EventHandler::http_request()` a partir de un `HttpRequestHandler` (`std::function<void(const HttpRequestEvent&)>`). Pase un `std::function` vacío para eliminar el manejador actual de ese tipo de evento. |

### Tipos de datos

Esta sección enumera los tipos de datos de C++ declarados por el SDK en el espacio de nombres `kameleoon` (`kameleoon/data/*.hpp`). Todos ellos son estructuras simples que se pasan a [`add_data()`](#add_data).

#### ApplicationVersion

`ApplicationVersion` representa el número de versión semántica de su aplicación.

<Tip>
  Un **visitante** solo puede tener una `ApplicationVersion`. Añadir una segunda instancia sobrescribirá la primera.
</Tip>

| Nombre | Tipo | Descripción |
| - | - | - |
| `value` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | La versión de la aplicación. Este campo debe seguir el versionado semántico. Los formatos aceptados son `major`, `major.minor` o `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

El conjunto de datos `Browser` almacenado aquí puede utilizarse para filtrar los informes de experimentos y personalizaciones por cualquier valor asociado a él.

| Nombre | Tipo | Descripción |
| - | - | - |
| `type` <Badge color="red" size="sm">obligatorio</Badge> | `BrowserType` | Lista de navegadores: `BrowserType::Chrome`, `BrowserType::InternetExplorer`, `BrowserType::Firefox`, `BrowserType::Safari`, `BrowserType::Opera`, `BrowserType::Other`. |
| `version` <Badge color="green" size="sm">opcional</Badge> | `std::optional<float>` | Versión del navegador; el número de coma flotante representa la versión mayor y menor del navegador |

```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

El conjunto de datos `Conversion` almacenado aquí puede utilizarse para filtrar los informes de experimentos y personalizaciones por cualquier objetivo asociado a él.

<Tip>
  * Cada visitante puede tener varios objetos `Conversion`.
  * Puede encontrar el `goal_id` en la aplicación de Kameleoon.
</Tip>

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `goal_id` <Badge color="red" size="sm">obligatorio</Badge> | `uint32_t` | ID del objetivo. | |
| `revenue` <Badge color="green" size="sm">opcional</Badge> | `float` | Ingresos de la conversión | `0` |
| `negative` <Badge color="green" size="sm">opcional</Badge> | `bool` | Define si los ingresos son positivos o negativos. | `false` |
| `metadata` <Badge color="green" size="sm">opcional</Badge> | `std::vector<CustomData>` | Metadatos de la conversión. | `{}` |

```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` contiene información sobre las cookies almacenadas en el dispositivo del visitante.

| Nombre | Tipo | Descripción |
| - | - | - |
| `cookies` | `std::unordered_map<std::string, std::string>` | Un mapa de cadenas que contiene las claves y los valores de las cookies. |

<Tip>
  Cada visitante solo puede tener una `Cookie`. Añadir una segunda `Cookie` sobrescribe la primera.
</Tip>

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

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

#### CustomData

`CustomData` permite asociar cualquier tipo de datos a cada visitante, lo que lo convierte en una herramienta eficaz para las condiciones de segmentación en los [segmentos](/es/user-manual/assets/segments/create-a-segment/). Además, puede utilizarse como filtro o desglose en los informes de experimentos. Para obtener más información sobre los custom data, consulte este [artículo](/es/developer-docs/custom-data).

Defina los tipos de custom data en la aplicación de Kameleoon o en la Data API y utilícelos desde el SDK.

`CustomData` tiene dos constructores: uno identifica el custom data por su `id` (índice) y el otro por su `name`.

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `id`/`name` <Badge color="red" size="sm">obligatorio</Badge> | `uint32_t`/`std::string` | Índice o nombre del custom data. **Debe proporcionarse `id` o `name`** para identificar los datos. | |
| `values` <Badge color="red" size="sm">obligatorio</Badge> | `std::vector<std::string>` | Valores del custom data que se van a almacenar. | |
| `overwrite` <Badge color="green" size="sm">opcional</Badge> | `bool` | Indicador para controlar explícitamente cómo se almacenan los valores y cómo aparecen en los informes. [Más información](/es/developer-docs/custom-data#lógica-por-defecto-cuando-el-parámetro-overwrite-es-false-o-se-omite) | `true` |

<Note>
  * Cada visitante solo puede tener un `CustomData` por cada `id` (`name`) único. Añadir otro `CustomData` con el mismo `id` (`name`) sustituirá al existente.

  * El 'índice' del custom data puede encontrarse en el [panel de Custom Data](/es/user-manual/assets/custom-data/manage-custom-data), en la columna "INDEX".

  * Para evitar que el SDK envíe los datos con el índice seleccionado a los servidores de Kameleoon por motivos de privacidad, active la opción: **Use this data only locally for targeting purposes** al crear el custom data.

  * Añadir una instancia de `CustomData` creada con un nombre cuando la instancia del SDK no está inicializada o el nombre no está registrado hará que los datos se ignoren.
</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

Puede utilizar los datos del dispositivo para filtrar los informes de experimentos y personalizaciones por cualquier valor asociado.

| Nombre | Tipo | Descripción |
| - | - | - |
| `type` | `DeviceType` | Tipo de dispositivo. Los valores posibles son `DeviceType::Phone`, `DeviceType::Tablet` y `DeviceType::Desktop`. |

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

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

#### Geolocation

`Geolocation` contiene los detalles de geolocalización del visitante.

| Nombre | Tipo | Descripción |
| - | - | - |
| `country` <Badge color="red" size="sm">obligatorio</Badge> | `std::string` | El país del visitante. |
| `region` <Badge color="green" size="sm">opcional</Badge> | <nobr>`std::optional<std::string>`</nobr> | La región del visitante. |
| `city` <Badge color="green" size="sm">opcional</Badge> | <nobr>`std::optional<std::string>`</nobr> | La ciudad del visitante. |
| `postal_code` <Badge color="green" size="sm">opcional</Badge> | <nobr>`std::optional<std::string>`</nobr> | El código postal del visitante. |
| `latitude` <Badge color="green" size="sm">opcional</Badge> | `std::optional<float>` | La coordenada de latitud que representa la ubicación del visitante. El número de la coordenada representa grados decimales. |
| `longitude` <Badge color="green" size="sm">opcional</Badge> | `std::optional<float>` | La coordenada de longitud que representa la ubicación del visitante. El número de la coordenada representa grados decimales. |

<Tip>
  * Cada visitante solo puede tener una `Geolocation`. Añadir una segunda `Geolocation` sobrescribe la primera.
</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` contiene información sobre el sistema operativo del dispositivo del visitante.

| Nombre | Tipo | Descripción |
| - | - | - |
| `type` | `OperatingSystemType` | Familia del sistema operativo. Los valores posibles son `OperatingSystemType::Windows`, `OperatingSystemType::Mac`, `OperatingSystemType::IOS`, `OperatingSystemType::Linux`, `OperatingSystemType::Android` y `OperatingSystemType::WindowsPhone`. |

<Tip>
  Cada visitante solo puede tener un `OperatingSystem`. Añadir un segundo `OperatingSystem` sobrescribe el primero.
</Tip>

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

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

#### PageView

Almacena eventos de páginas vistas.

| Nombre | Tipo | Descripción | Valor por defecto |
| - | - | - | - |
| `url` | `std::string` | URL de la página vista. | |
| `title` | `std::optional<std::string>` | Título de la página vista. | `std::nullopt` |
| `referrers` | `std::vector<int32_t>` | Índices de referrer de las páginas vistas anteriormente. | `{}` |

<Note>
  El índice del referrer está disponible en la aplicación de Kameleoon en la página de [configuración del canal de adquisición](/es/user-manual/assets/advanced-targeting-tools/create-an-acquisition-channel). Tenga cuidado: el índice empieza en `0`, por lo que el primer canal de adquisición que cree tiene el ID `0`, no `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 no añade `UniqueIdentifier` para un visitante, el `visitor_code` se utiliza como identificador único del visitante, lo cual es útil para la [experimentación cross-device](/es/developer-docs/cross-device-experimentation/). Cuando añade `UniqueIdentifier{true}`, el SDK vincula los datos enviados con el visitante asociado al identificador especificado.

Esto puede ser útil en situaciones en las que no puede acceder al `visitor_code` anónimo asignado originalmente a un visitante, pero sí tiene acceso a un identificador interno conectado a ese visitante mediante la fusión de sesiones.

| Nombre | Tipo | Descripción |
| - | - | - |
| `value` | `bool` | Indica si el `visitor_code` actual debe tratarse como un identificador único. |

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

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

#### UserAgent

Los experimentos del lado del servidor tienen más probabilidades de verse afectados por el tráfico de bots que los experimentos del lado del cliente. Kameleoon utiliza la lista IAB/ABC International Spiders and Bots List para reconocer los bots y spiders conocidos, y también utiliza el campo `UserAgent` para filtrar otro tráfico no deseado que podría distorsionar sus métricas de conversión. Para obtener más información, consulte el artículo de ayuda sobre el [filtrado de bots](/es/user-manual/experiment-analytics/troubleshooting/data-discrepancies#how-does-kameleoon-filter-bot-traffic-from-my-results).

Si utiliza bots internos, envíe el valor de user-agent `curl/8.0` para excluirlos de la analítica.

| Nombre | Tipo | Descripción |
| - | - | - |
| `value` | `std::string` | Valor de User-Agent enviado con las solicitudes de seguimiento. |

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

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

### Tipos devueltos

#### DataFile

El `DataFile` contiene los detalles de la configuración del SDK.

Puede ampliarse con información adicional si los clientes lo requieren. Si necesita más detalles, póngase en contacto con su Customer Success Manager.

| Nombre | Tipo | Descripción |
| - | - | - |
| `feature_flags` | `std::unordered_map<std::string, FeatureFlag>` | Un mapa de objetos [`FeatureFlag`](#featureflag), indexado por las claves de los feature flags. |
| `date_modified` | `uint64_t` | La marca de tiempo (en milisegundos) que indica cuándo se modificó por última vez el `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

El `FeatureFlag` representa un conjunto de propiedades que definen el propio feature flag (por ejemplo, sus [`Variations`](#variation), [`Rules`](#rule), el estado del entorno y otros detalles relacionados).

Puede ampliarse con información adicional si los clientes lo requieren. Si necesita más detalles, póngase en contacto con su Customer Success Manager.

| Nombre | Tipo | Descripción |
| - | - | - |
| `environment_enabled` | `bool` | Indica si el feature flag está activado en el entorno actual. |
| `default_variation_key` | `std::string` | La clave de la variación predeterminada asociada al feature flag. |
| `variations` | `std::unordered_map<std::string, Variation>` | Un mapa de objetos `Variation`, indexado por las claves de las variaciones. |
| `rules` | `std::vector<Rule>` | Una lista de objetos `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` representa un conjunto de propiedades que definen la propia regla (por ejemplo, sus [`Variations`](#variation)).

Puede ampliarse con información adicional si los clientes lo requieren. Si necesita más detalles, póngase en contacto con su Customer Success Manager.

| Nombre | Tipo | Descripción |
| - | - | - |
| `variations` | `std::unordered_map<std::string, Variation>` | Un mapa de objetos `Variation`, indexado por las claves de las variaciones. |

```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` contiene información sobre la variación asignada al visitante, o la variación predeterminada cuando no existe una asignación específica.

| Nombre | Tipo | Descripción |
| - | - | - |
| `name` | `std::string` | El nombre de la variación. |
| `key` | `std::string` | La clave única que identifica la variación. |
| `id` | `std::optional<uint32_t>` | El ID de la variación asignada, o `std::nullopt` para una variación predeterminada. |
| `experiment_id` | `std::optional<uint32_t>` | El ID del experimento asociado a la variación, o `std::nullopt` para una variación predeterminada. |
| `variables` | `std::vector<Variable>` | Variables asociadas a la variación. Esta colección puede estar vacía cuando no hay variables adjuntas. |

<Note>
  * `Variation` describe la variación asignada o predeterminada, mientras que [`Variable`](#variable) contiene los detalles de cada variable individual.
  * `id` y `experiment_id` pueden ser `std::nullopt`, lo que indica una variación predeterminada que no está vinculada a una asignación de experimento específica.
</Note>

Métodos auxiliares adicionales:

| Método | Tipo de retorno | Descripción |
| - | - | - |
| `active()` | `bool` | Devuelve `false` para la variación `off`. |
| `get_variable(key)` | `const Variable*` | Devuelve un puntero a la variable de la variación con la clave dada, o `nullptr` si no se encuentra. |

```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` contiene información sobre una variable asociada a la variación asignada.

| Nombre | Tipo | Descripción |
| - | - | - |
| `key` | `std::string` | La clave única que identifica la variable. |
| `kind` | `std::string` | El tipo de la variable. Los valores posibles incluyen `BOOLEAN`, `NUMBER`, `STRING`, `JSON`, `JS` y `CSS`. |
| `value` | [`JsonValue`](#jsonvalue) | El valor de la variable. Según `kind`, puede contener un booleano, un número, una cadena, una cadena JSON, un fragmento de JavaScript o un fragmento de 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` representa el valor de una variable de variación en C++. El campo `kind` distingue los tipos que contienen cadenas; `value` es un `std::variant<bool, double, std::string>`.

| Kind | Tipo almacenado | Descripción |
| - | - | - |
| `JsonValueKind::Boolean` | `bool` | Representa un valor booleano. |
| `JsonValueKind::Number` | `double` | Representa un valor numérico. |
| `JsonValueKind::String` | `std::string` | Representa un valor de cadena. |
| `JsonValueKind::JSON` | `std::string` | Representa un valor codificado en JSON. |
| `JsonValueKind::JS` | `std::string` | Representa un fragmento de código JavaScript. |
| `JsonValueKind::CSS` | `std::string` | Representa un fragmento de código CSS. |

Los accesores tipados devuelven `std::nullopt` cuando el valor es de otro tipo:

| Método | Tipo de retorno | Descripción |
| - | - | - |
| `as_bool()` | `std::optional<bool>` | El valor booleano. |
| `as_number()` | `std::optional<double>` | El valor numérico. |
| `as_string()` | `std::optional<std::string>` | El valor de cadena para todos los tipos que contienen cadenas (`String`, `JSON`, `JS` y `CSS`). |
