Skip to main content

Advanced guide

Last updated 10/03/2026

1. Send events​

After the SDK is initialized, you can start tracking data to collect user behavior. In most cases, regular events meet business needs. You can also use first events, updatable events, and other event types based on your actual business scenarios.

1.1 Regular events​

You can call td_track to upload events. We recommend setting event properties and the conditions for sending events according to the document you prepared earlier. The following example tracks a user purchasing a product:

// Set event properties
TDProperties *properties = td_init_properties();
TD_ASSERT(TD_OK == td_add_string("product_name", "goods_name", strlen("goods_name"), properties));
// Report event data with custom properties. Likewise, at least one of account_id and distinct_id must be set
TD_ASSERT(TD_OK == td_track("account_id", "distinct_id", "product_buy", properties, ta));
td_free_properties(properties);

1.2 First events​

A first event is an event that is recorded only once for a given device or an ID of another dimension. For example, in some scenarios you may want to record the activation event on a device; you can report this data as a first event.

TD_ASSERT(TD_OK == td_track_first_event("account_id", "distinct_id", "device_activation", "first_id", properties, ta));

Note: Because the first-event check is performed on the server, first events are stored with a 1-hour delay by default.

1.3 Updatable events​

You can use updatable events to modify event data in specific scenarios. An updatable event requires an ID that identifies the event, which you pass in when you create the updatable event object. The AE backend determines which data to update based on the event name and event ID.

// Report an updatable event with the event name UPDATABLE_EVENT and the event ID event_id
// After reporting, the event property status is 3 and price is 100
TDProperties *properties = td_init_properties();
TD_ASSERT(TD_OK == td_add_int("price",100,properties));
TD_ASSERT(TD_OK == td_add_int("status",3,properties));
TD_ASSERT(TD_OK == td_track_update("account_id", "distinct_id", "UPDATABLE_EVENT", "event_id",properties, ta));
td_free_properties(properties);
// After reporting, the same event property status is updated to 5, and price stays unchanged
TDProperties *new_properties = td_init_properties();
TD_ASSERT(TD_OK == td_add_int("status",5,new_properties));
TD_ASSERT(TD_OK == td_track_update("account_id", "distinct_id", "UPDATABLE_EVENT", "event_id",new_properties, ta));
td_free_properties(new_properties);

1.4 Overwritable events​

Overwritable events are similar to updatable events, except that an overwritable event completely overwrites historical data with the latest data. In effect, the previous record is deleted and the latest data is ingested. The AE backend determines which data to update based on the event name and event ID.

// Report an overwritable event with the event name OVERWRITE_EVENT and the event ID event_id
// After reporting, the event property status is 3 and price is 100
TDProperties *properties = td_init_properties();
TD_ASSERT(TD_OK == td_add_int("price",100,properties));
TD_ASSERT(TD_OK == td_add_int("status",3,properties));
TD_ASSERT(TD_OK == td_track_overwrite("account_id", "distinct_id", "OVERWRITE_EVENT", "event_id",properties, ta));
td_free_properties(properties);
// After reporting, the same event property status is updated to 5, and the price property is deleted
TDProperties *new_properties = td_init_properties();
TD_ASSERT(TD_OK == td_add_int("status",5,new_properties));
TD_ASSERT(TD_OK == td_track_overwrite("account_id", "distinct_id", "OVERWRITE_EVENT", "event_id",new_properties, ta));
td_free_properties(new_properties);

2. User properties​

The user property APIs supported by the AE platform are: td_user_set, td_user_setOnce, td_user_add, td_user_unset, td_user_delete, td_user_append, and td_user_uniq_append.

2.1 td_user_set​

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

//user_name is TA at this point
TDProperties *user_properties = td_init_properties();
TD_ASSERT(TD_OK == td_add_string("user_name", "TA", strlen("TA"), user_properties));
TD_ASSERT(TD_OK == td_user_set("account_id", "distinct_id", user_properties,ta));
td_free_properties(user_properties);

//user_name is AE at this point
TDProperties *user_properties2 = td_init_properties();
TD_ASSERT(TD_OK == td_add_string("user_name", "AE", strlen("AE"), user_properties2));
TD_ASSERT(TD_OK == td_user_set("account_id", "distinct_id", user_properties2,ta));
td_free_properties(user_properties2);

2.2 td_user_setOnce​

If a user property only needs to be set once, you can call td_user_setOnce to set it. If the property already has a value, this record is ignored. The following example sets the first payment time:

//first_payment_time is 2018-01-01 01:23:45.678
TDProperties *user_properties = td_init_properties();
TD_ASSERT(TD_OK == td_add_string("first_payment_time", "2018-01-01 01:23:45.678", strlen("2018-01-01 01:23:45.678"), user_properties));
TD_ASSERT(TD_OK == td_user_setOnce("account_id", "distinct_id", user_properties,ta));
td_free_properties(user_properties);

//first_payment_time is still 2018-01-01 01:23:45.678
TDProperties *user_properties2 = td_init_properties();
TD_ASSERT(TD_OK == td_add_string("first_payment_time", "2018-12-31 01:23:45.678", strlen("2018-12-31 01:23:45.678"), user_properties2));
TD_ASSERT(TD_OK == td_user_setOnce("account_id", "distinct_id", user_properties2,ta));
td_free_properties(user_properties2);

2.3 td_user_add​

When you upload a numeric property, you can call td_user_add to accumulate its value. If the property hasn't been set, it is assigned 0 before the calculation. You can pass in a negative value, which is equivalent to subtraction. The following example accumulates the total payment amount:

// Upload a user property. The value of "total_revenue" is now 30
TDProperties *user_properties = td_init_properties();
TD_ASSERT(TD_OK == td_add_int("total_revenue", 30, user_properties));
TD_ASSERT(TD_OK == td_user_add("account_id", "distinct_id", user_properties, ta));
td_free_properties(user_properties);

// Upload a user property. The value of "total_revenue" is now 678
TDProperties *new_user_properties = td_init_properties();
TD_ASSERT(TD_OK == td_add_int("total_revenue",648 , new_user_properties));
TD_ASSERT(TD_OK == td_user_add("account_id", "distinct_id", new_user_properties, ta));
td_free_properties(new_user_properties);

The property key is a string, and the Value can only be a number.

2.4 td_user_append​

You can call td_user_append to append values to a user property of the array type.

// The value of user_list is now ["apple","ball"]
TDProperties *array_properties = td_init_properties();
TD_ASSERT(TD_OK == td_append_array("user_list", "apple", strlen("apple"), array_properties));
TD_ASSERT(TD_OK == td_append_array("user_list", "ball", strlen("ball"), array_properties));
TD_ASSERT(TD_OK == td_user_append("account_id", "distinct_id", array_properties, ta));
td_free_properties(array_properties);

// The value of user_list is now ["apple","apple","ball","cube"]
TDProperties *new_array_properties = td_init_properties();
TD_ASSERT(TD_OK == td_append_array("user_list", "apple", strlen("apple"), new_array_properties));
TD_ASSERT(TD_OK == td_append_array("user_list", "cube", strlen("cube"), new_array_properties));
TD_ASSERT(TD_OK == td_user_append("account_id", "distinct_id", new_array_properties, ta));
td_free_properties(new_array_properties);

2.5 td_user_uniq_append​

You can call td_user_uniq_append to append values to a user property of the array type. td_user_uniq_append deduplicates the appended user property values, whereas td_user_append doesn't, so the user property may contain duplicates.

// The value of user_list is now ["apple","ball"]
TDProperties *array_properties = td_init_properties();
TD_ASSERT(TD_OK == td_append_array("user_list", "apple", strlen("apple"), array_properties));
TD_ASSERT(TD_OK == td_append_array("user_list", "ball", strlen("ball"), array_properties));
TD_ASSERT(TD_OK == td_user_append("account_id", "distinct_id", array_properties, ta));
td_free_properties(array_properties);

// The value of user_list is now ["apple","ball","cube"]
TDProperties *new_array_properties = td_init_properties();
TD_ASSERT(TD_OK == td_append_array("user_list", "apple", strlen("apple"), new_array_properties));
TD_ASSERT(TD_OK == td_append_array("user_list", "cube", strlen("cube"), new_array_properties));
TD_ASSERT(TD_OK == td_user_uniq_append("account_id","distinct_id", new_array_properties, ta));
td_free_properties(new_array_properties);

2.6 td_user_unset​

To clear the value of a user property, you can call td_user_unset to clear the specified property. If the property hasn't been created in the cluster, td_user_unset doesn't create it

TD_ASSERT(TD_OK == td_user_unset("account_id", "distinct_id", "test", ta));

td_user_unset: the value passed in is the key of the property to be cleared.

2.7 td_user_delete​

To delete a user, you can call td_user_delete. After that, you can no longer query the user's user properties, but the events generated by the user can still be queried. This operation may have irreversible consequences, so use it with caution

TD_ASSERT(TD_OK == td_user_delete("account_id", "distinct_id", ta));

3. Other features​

3.1 BatchConsumer​

Note

When the data volume is too large or the network is abnormal, data may be lost. We don't recommend using it in the production environment

Transmits data to the AE server in batches in real time, without a transfer tool. You can set the buffer size, which is 20 by default; that is, the buffer holds at most 20 records (20 is the batch size of each upload and can be configured).

// First, modify the CMakeLists.txt file to build a library file of the TDBatchConsumer type

struct TDAnalytics* ta = NULL;
struct TDConsumer* consumer = NULL;

//Create the config
TDConfig *config = td_init_config();
// Configure appid and url
char* appid = "APPID";
char* serverURL = "SERVER_URL";
TD_ASSERT(TD_OK == td_add_string("push_url", serverURL, strlen(serverURL), config));
TD_ASSERT(TD_OK == td_add_string("appid", appid, strlen(appid), config));

// Create the SDK instance
if (TD_OK != td_init_consumer(&consumer, config)) {
fprintf(stderr, "Failed to initialize the consumer.");
return 1;
}
td_free_properties(config);
if (TD_OK != td_init(consumer, &ta)) {
fprintf(stderr, "Failed to initialize the SDK.");
return 1;
}

Parameters:

  • APPID: The APPID of your project, which you can find on the Project Settings page in the AE backend

  • SERVER_URL: The URL that data is uploaded to

    • If you use the cloud service, enter: https://global-receiver-ta.thinkingdata.cn
    • If you use an on-premises deployment, bind a domain name to the data collection URL and configure an HTTPS certificate: https://your-domain-for-data-collection
Was this page helpful?