Skip to main content

C++

Last updated 10/07/2026
tip

Before you integrate the SDK, read Pre-integration preparation.

The SDK requires c++ 11 and g++ 5.1.0 or later.

Latest version: v2.0.0

Update time: 2023-11-30

Downloads: Source code

Note

This document applies to v2.0.0 and later. For earlier versions, see C++ SDK Integration Guide (V1)

1. Integrate the SDK​

Ⅰ. Build the source code to get the libthinkingdata.a file​
  1. The AE SDK depends on the rapidjson parsing library, so you need to download the rapidjson library locally.
  2. Download the C++ SDK source code, modify the CMakeLists.txt file in the SDK, and select the data consumer you want to build (for details, see the CMakeLists.txt file in the SDK source code). The following example uses the most common logconsumer:
cmake_minimum_required(VERSION 3.12)
project(ThinkingData)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 11)

message(STATUS "[${PROJECT_NAME}] current cmake version: ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}")
message(STATUS "[${PROJECT_NAME}] CMAKE_HOST_SYSTEM: ${CMAKE_HOST_SYSTEM} ")

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE release CACHE STRING "Build Type" FORCE)
endif()

message(STATUS "[${PROJECT_NAME}] Build type:${CMAKE_BUILD_TYPE}")

message(STATUS "[${PROJECT_NAME}] Debug configuration:${CMAKE_CXX_FLAGS_DEBUG}")

message(STATUS "[${PROJECT_NAME}] release configuration:${CMAKE_CXX_FLAGS_RELEASE}")

message(STATUS "[${PROJECT_NAME}] release configuration with debug info:${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")

message(STATUS "[${PROJECT_NAME}] minimal release configuration:${CMAKE_CXX_FLAGS_MINSIZEREL}")

include_directories(include)

#
# log consumer. Recommended for production environments
#
set(TE_LIB_NAME thinkingdata)
add_library(${TE_LIB_NAME} src/TDAnalytics.cpp src/TDUtils.cpp src/TDLoggerConsumer.cpp src/TDConsumer.cpp)
if(UNIX)
find_package(Threads REQUIRED)
target_link_libraries(${TE_LIB_NAME} Threads::Threads)
endif()
  1. The rapidjson library is a header-only .h library, so you add it to your project as header files.
    1. If your project doesn't include the rapidjson library yet, import the following header files:
include
├── rapidjson
├── TDAnalytics.h
├── TDBatchConsumer.h
├── TDConsumer.h
├── TDDebugConsumer.h
├── TDJsonParse.h
├── TDLoggerConsumer.h
├── TDNetwork.h
└── TDUtils.h
  1. If your project already includes the rapidjson library, import only the header files of the AE SDK. Then modify and confirm the contents of the TDJsonParse.h file, and check that the include paths of the rapidjson library in the file are correct:
#ifndef CPP_TD_JSON_PARSE_H
#define CPP_TD_JSON_PARSE_H

#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"

#endif // !CPP_TD_JSON_PARSE_H
Ⅱ. Install LogBus​

We recommend using SDK + LogBus to collect and report server-side data. To install LogBus, see the following document: LogBus user guide

2. Initialization​

Import the header files:

#include "../include/TDAnalytics.h"
#include "../include/TDLoggerConsumer.h"
#include "../include/TDDebugConsumer.h"
#include "../include/TDBatchConsumer.h"

using namespace thinkingDataAnalytics;

The following sample code initializes the SDK:

TDLoggerConsumer::Config config = TDLoggerConsumer::Config("LOG_DIRECTORY", 20, 500, TDLoggerConsumer::HOURLY);
config.fileNamePrefix = "te";
config.rotateMode = TDLoggerConsumer::HOURLY;

TDConsumer *consumer = new TDLoggerConsumer(config);
TDAnalytics te(*consumer, false);

LOG_DIRECTORY is the path of the local folder that data is written to. Set the folder that LogBus monitors to this path, and LogBus monitors and uploads the data.

3. Common features​

To make sure that the distinct ID and account ID can be bound correctly, if your game uses both the distinct ID and the account ID, we strongly recommend that you upload both IDs. Otherwise, accounts may fail to match and users may be counted more than once. For details on ID binding rules, see User identification rules.

3.1 Send events​

You can call track to upload events. We recommend setting event properties and the conditions for sending events based on the document you prepared earlier. The following sample code sends an event:

TDPropertiesNode event_properties;
event_properties.SetString("name1", "XZ_debug");
event_properties.SetString("name2", "logbugs");
event_properties.SetString("name3", "name3");
event_properties.SetString("#uuid", "1234567890");
event_properties.SetNumber("test_number_int", 3);
event_properties.SetNumber("test_number_double", 3.14);
event_properties.SetBool("test_bool", true);
std::string test_string = "test_string";
event_properties.SetString("test_stl_string1", test_string);
event_properties.SetDateTime("test_time1", time(nullptr), 0);
timeb t = {};
ftime(&t);
event_properties.SetDateTime("#time", t.time, t.millitm);
std::vector<std::string> test_list;
test_list.emplace_back("item11");
test_list.emplace_back("item21");
event_properties.SetList("test_list1", test_list);

// track event
te.track("accountId", "distinctId", "eventName", event_properties);
  • The event name is of the string type. It must start with a letter, can contain digits, letters, and underscores "_", and can be up to 50 characters long.
  • Key is the name of the property and is of string type. It must start with a letter, can contain digits, letters, and underscores "_", can be up to 50 characters long, and is case-insensitive. AE converts it to lowercase
  • Value is the value of the property. Supported types are string, number, Boolean, time, object, object group, and array

User properties have the same requirements as event properties

3.2 Set user properties​

For general user properties, you can call user_set to set them. Properties uploaded through this API overwrite the original values. If the user property doesn't exist yet, it is created with the same type as the value passed in. The following example sets the username:

// user_set
TDPropertiesNode userSet_properties;
userSet_properties.SetString("userName", "test");
// Upload user properties
te.user_set("accountId", "distinctId", userSet_properties);

3.3 Send data​

When you use TDLoggerConsumer, collected events are first converted to JSON strings and added to a cache array. Data is written to disk only when the number of elements in the array exceeds the configured capacity. The default capacity is 20 records.

In some business scenarios, if you want data to be reported to the AE server immediately, you can call flush(). Note that calling flush() frequently degrades service performance.

te.flush();

3.4 Shut down the SDK​

te.close();

Shuts down and exits the SDK. Call this API before you shut down the server to avoid losing data in the cache

4. Best practices​

The following sample code includes all of the operations above. We recommend using them in the following order:

// Import the header files (paths differ across platforms and IDEs; adjust them as needed)
#include "../include/TDAnalytics.h"
#include "../include/TDLoggerConsumer.h"

using namespace thinkingDataAnalytics;

TDLoggerConsumer::Config config = TDLoggerConsumer::Config("LOG_DIRECTORY", 20, 500, TDLoggerConsumer::HOURLY);
config.fileNamePrefix = "te";
config.rotateMode = TDLoggerConsumer::HOURLY;

TDConsumer *consumer = new TDLoggerConsumer(config);
TDAnalytics te(*consumer, false);

//Upload an event
TDPropertiesNode event_properties;
event_properties.SetString("name1", "XZ_debug");
event_properties.SetNumber("test_number_int", 3);
event_properties.SetBool("test_bool", true);
te.track("accountId", "distinctId", "eventName", event_properties);

//Upload user properties
TDPropertiesNode userSet_properties;
userSet_properties.SetString("userName", "test");
te.user_set("accountId", "distinctId", userSet_properties);

// Calling flush writes data to the file immediately. In production, avoid calling flush frequently, which can cause IO or network overhead
// Usually you don't need to call it manually
te.flush();
Was this page helpful?