User Identification and Properties

SDKs' default behavior is to track the device it is running on (with a unique device ID), where each user you see in your dashboard indicates a device (like browser or a phone.) However if you are able identify the person using that device you can let the SDK know and this way migrate from device tracking to user tracking.

Do not forget to check our User Tracking strategy guide from here.

You can also provide user information like a username or email address. This will allow you to distinguish users further on "User Profiles".

User Profiles is a Countly Enterprise plugin and built-in Flex.

Web Android iOS Node Flutter Dart HarmonyOS React Native Windows Unity Java C++ API Call

User Identification

To change the device ID provide your unique identifier.

Asynchronous Synchronous
Countly.q.push(['set_id', "newID"]);
Countly.sharedInstance().deviceId().setID("newID");
Objective-C Swift
[Countly.sharedInstance setID:@"newID"];
Countly.set_id("newID");
Countly.instance.deviceId.setID("newID");
final sdk = Countly.defaultInstance!;

// change alias for the same user (merge)
await sdk.id.changeWithMerge("newID");

// for a new user (without merge)
await sdk.id.changeWithoutMerge("newAnonymousID");
await sdk.consents.giveConsent();
await Countly.sharedInstance().deviceId.setID('newID');
Countly.deviceId.setID("newID");

// or explicitly control merge behavior
Countly.deviceId.changeID("newID", true);
Countly.deviceId.changeID("newAnonymousID", false);
await Countly.Instance.SetId("newID");
Countly.Instance.Device.SetId("newID");
Countly.instance().deviceId().setID("newID");

To create a new user you would call:

cly::Countly::getInstance().setDeviceID("newID", false);

To change the server alias (device ID) of the same user you would use:

cly::Countly::getInstance().setDeviceID("newID", true);

Simply providing a device ID in your requests will create a user if they don't exist in your server yet. Whenever you want to change the device ID of an already existing user (basically the alias they have in the server) then you can do it the following way:

PS: This is a resource intensive operation for server which we call 'user merging' so use it sparingly.

curl --request GET \
  --url 'https://YOUR_SERVER/i?app_key=APP_KEY&device_id=NEW_DEVICE_ID&old_device_id=PREVIOUS_DEVICE_ID' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \

You should expect the response to be:

# 200
{
  "result": "Success"
}

User Properties

To record predefined (which has a special UI location in your server) or custom User Properties alike:

Asynchronous Synchronous
Countly.q.push(['user_details',{
  "name": "John Smith",
  "username": "johnS",
  "email": "js@mail.com",
  "organization": "Company A",
  "phone": "+999000555",
  "picture": "https://imagehost/avatar.jpg", 
  "gender": "M",
  "byear": 1960,
  "custom":{
    "custom key":"custom value",
    ...
  }
}]);
Map<String, Object> userInformation = new HashMap<>();
userInformation.put("name", "John Smith");
userInformation.put("username", "johnS");
userInformation.put("email", "js@mail.com");
userInformation.put("organization", "Company A");
userInformation.put("phone", "+999000555");
userInformation.put("picture", "https://imagehost/avatar.jpg");
userInformation.put("gender", "M");
userInformation.put("byear", 1960);
userInformation.put("custom key", "custom val");

Countly.sharedInstance().userProfile().setProperties(userInformation);
Objective-C Swift
//default properties
Countly.user.name = @"John Smith";
Countly.user.username = @"johnS";
Countly.user.email = @"js@mail.com";
Countly.user.birthYear = @1960;
Countly.user.organization = @"Company A";
Countly.user.gender = @"M";
Countly.user.phone = @"+999000555";
Countly.user.custom = @{@"custom key": @"custom value"};
Countly.user.pictureURL = @"https://imagehost/avatar.jpg";
//or local image on the device
Countly.user.pictureLocalPath = localImagePath;
Countly.user_details({
  "name": "John Smith",
  "username": "johnS",
  "email": "js@mail.com",
  "organization": "Countly",
  "phone": "+999000555",
  "picture": "https://imagehost/avatar.jpg", 
  "gender": "M",
  "byear": 1960,
  "custom":{
    "custom key":"custom value",
    ...
  }
 });
Map<String, Object> userProperties= {
  "name": "John Smith",
  "username": "johnS",
  "email": "js@mail.com",
  "organization": "Company A",
  "phone": "+999000555",
  "picture": "https://imagehost/avatar.jpg",
  "gender": "M",
  "byear": "1960",
  "custom key": "custom value"
};
Countly.instance.userProfile.setUserProperties(userProperties);
final sdk = Countly.defaultInstance!;

await sdk.users.setProperties({
    NamedUserProperty.name: 'John Smith',
    NamedUserProperty.username: 'johnS',
    NamedUserProperty.email: 'js@mail.com',
    NamedUserProperty.organization: 'Company A',
    NamedUserProperty.phone: '+999000555',
    NamedUserProperty.picture: 'https://imagehost/avatar.jpg',
    NamedUserProperty.gender: 'M',
    NamedUserProperty.byear: 1960,
    'custom key': 'custom value',
});
const userProfile = Countly.sharedInstance().userProfile;

userProfile.setProperties({
  'name': 'John Smith',
  'username': 'johnS',
  'email': 'js@mail.com',
  'organization': 'Company A',
  'phone': '+999000555',
  'picture': 'https://imagehost/avatar.jpg',
  'gender': 'M',
  'byear': 1960,
  'custom key': 'custom value',
});

// property modifiers (also need .save() to flush)
userProfile.increment('launches');
userProfile.incrementBy('points', 50);
userProfile.saveMax('highScore', 100);
userProfile.push('badges', 'gold');

// flush the buffered changes to the server
await userProfile.save();
const options = {};

options.name = "John Smith";
options.username = "johnS";
options.email = "js@mail.com";
options.organization = "Company A";
options.phone = "+999000555";
options.gender = "M";
options.byear = 1960;
  options.custom = {"custom key": "custom value"};
options.picture = "https://imagehost/avatar.jpg";
// or
options.picturePath = "/some/path";
  
Countly.setUserData(options);

Each time you change a property value, Countly syncs it with a server. If you set value as null, you will delete the property.

Example:

Countly.UserDetails.Name = "John Smith";
Countly.UserDetails.Username = "johnS";
Countly.UserDetails.Email = "js@mail.com";
Countly.UserDetails.Organization = "Company A";
Countly.UserDetails.Phone = "+999000555";
Countly.UserDetails.Gender = "M";
Countly.UserDetails.BirthYear = 1960;
Countly.UserDetails.Custom.Add("custom key", "custom value");
Countly.UserDetails.Picture = "https://imagehost/avatar.jpg";
// or
Countly.UserDetails.UploadUserPicture(picture_stream);
var userProperties = new Dictionary<string, object="object">
{
  { "name", "John Smith" },
  { "username", "johnS" },
  { "email", "js@mail.com" },
  { "organization", "Company A" },
  { "phone", "+999000555" },
  { "picture", "https://imagehost/avatar.jpg" },
  { "gender", "M" },
  { "byear", 1960 },
  { "custom key", "custom val" },
};
Countly.Instance.UserProfile.SetProperties(userProperties);</string,>
Countly.instance().userProfile().setProperty(PredefinedUserPropertyKeys.NAME, "John Smith");
Countly.instance().userProfile().setProperty(PredefinedUserPropertyKeys.EMAIL, "js@mail.com");
Countly.instance().userProfile().setProperty(PredefinedUserPropertyKeys.USERNAME, "johnS");
Countly.instance().userProfile().setProperty(PredefinedUserPropertyKeys.ORGANIZATION, "Company A");
Countly.instance().userProfile().setProperty(PredefinedUserPropertyKeys.PHONE, "+999000555");
Countly.instance().userProfile().setProperty(PredefinedUserPropertyKeys.PICTURE, "https://imagehost/avatar.jpg");
Countly.instance().userProfile().setProperty(PredefinedUserPropertyKeys.GENDER, "M");
Countly.instance().userProfile().setProperty(PredefinedUserPropertyKeys.BIRTHYEAR, 1960);
Countly.instance().userProfile().setProperty("custom key", "custom val");
Countly.instance().userProfile().save();
std::map<std::string, std::string> userdetail = { 
  {"name", "John Smith"}, 
  {"username", "johnS"},
  {"email", "js@mail.com"},
  {"phone", "+999000555"},
  {"picture", "https://imagehost/avatar.jpg"},
  {"gender", "M"},
  {"byear", "1960"},
  {"organization", "Company A"},
};
cly::Countly.getInstance().setUserDetails(userdetail);

You can simply make a POST request to send the user properties:

curl --request POST \
  --url 'https://YOUR_SERVER/i?app_key=APP_KEY&device_id=DEVICE_ID' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "user_details": {
      "name": "John Smith",
      "username": "johnS",
      "email": "js@mail.com",
      "organization": "Company A",
      "phone": "+999000555",
      "picture": "https://imagehost/avatar.jpg",
      "gender": "M",
      "byear": 1960,
      "custom": {
        "key": "value",
      }
    }
  }'

You should expect the response to be:

# 200
{
  "result": "Success"
}

If a parameter is set as an empty string, it will be deleted on the server side.

The keys for predefined user properties are as follows:

Key Type Description
name String User's full name
username String User's nickname
email String User's email address
organization String User's organization name
phone String User's phone number
picture String URL to avatar or profile picture of the user*
gender String User's gender as M for male and F for female
byear int User's year of birth as integer

* With Android and Unity SDKs picturePath and with iOS SDK pictureURL and pictureLocalPath available.

Was this page helpful?
Reach out to us for any other questions.
Helpful?

Looking for more Help?