Title: How to Properly Identify Users Locale: en URL: https://sensorswave.com/en/docs/data-integration/user-identification/ Description: Best practices for user identification — understanding Anonymous ID and Login ID Accurately identifying and tracking users is the foundation of data analysis. Sensors Wave provides a comprehensive user identification system that helps you connect user behavioral data across pre-login and post-login states, as well as cross-device usage, enabling complete user behavior analysis. ## Why Is User Identification Important? In real business scenarios, a user's behavior path often looks like this: 1. **Anonymous browsing**: The user visits the app for the first time, browsing products and reading content 2. **Registration and login**: The user decides to register an account and log in 3. **Cross-device usage**: The same user uses the app on a phone, tablet, and computer 4. **Device sharing**: Family members share a single device, with different users logging in one after another Without proper user identification, the following problems will arise: - The same user's pre-login and post-login behaviors are fragmented, making it impossible to analyze the complete user journey - Cross-device behaviors are identified as multiple different users, leading to inaccurate user count statistics - Funnel analysis becomes inaccurate, impacting business decisions Sensors Wave's user identification system solves these problems, ensuring the accuracy of data analysis. ## Core Principles of User Identification ### Automatic User Identity Merging When you call the `identify` method, Sensors Wave automatically associates a user's pre-login anonymous behaviors with their post-login behaviors under the same user. This process is **automatic and transparent** — you do not need to manually handle user data merging. **Example**: ``` User A's behavior trail: 1. Anonymously browsing products (Anonymous ID: device_001) 2. Adding to cart (Anonymous ID: device_001) 3. Registering and logging in (calls identify('user_123')) ↓ Sensors Wave automatically associates: device_001 → user_123 4. Completing a purchase (Login ID: user_123) Result: All behaviors (steps 1-4) are attributed to user user_123 ``` ### Historical Data Preservation All of a user's historical behavioral data is preserved, even if device information changes: - After clearing cookies or app data, historical data remains intact when the user logs in again - When a user logs in on a new device, the new device's behaviors are automatically attributed to the same user - The user's complete behavior trail is traceable and will not be lost due to device changes ### Cross-Device User Recognition Behaviors from the same user across multiple devices are automatically aggregated: ``` User user_123's cross-device behavior: - Device A (phone): browsing, adding to cart - Device B (computer): logging in, completing purchase - Device C (tablet): viewing orders All device behaviors are attributed to user_123 User count: 1 user (not 3) ``` ## Core Concepts ### Anonymous ID The Anonymous ID identifies a user's device or browser. It is automatically generated and stored locally when the user first visits the app. **Anonymous ID on different platforms**: - **Web browser**: A unique identifier stored in cookies - **iOS app**: IDFA (Advertising Identifier) or a device-generated UUID - **Android app**: Android ID or a device-generated UUID **Characteristics**: - Automatically generated and managed by the SDK; no manual setup required - Tracks user behavior when the user is not logged in - Stored locally; regenerated when app data or cookies are cleared ### Login ID The Login ID is the unique identifier for a user after login, typically the user primary key in the business system. **Common Login IDs**: - User ID (e.g., `user_12345`) - Custom account name (e.g., `zhangsan`) - Phone number (e.g., md5(`13800138000`)) - Email (e.g., md5(`user@example.com`)) (Note: If personally sensitive information is involved, plaintext transmission is not allowed.) **Characteristics**: - Uniquely identifies a logged-in user - Remains consistent across devices - Must be actively set when the user logs in ### SSID (Server-Side User ID) Sensors Wave automatically generates a unique user ID (i.e., SSID) on the server based on the Anonymous ID and Login ID you report. This is used to identify unique users during data analysis. **Generation rules**: - With only Anonymous ID: Uses the Anonymous ID to generate the user ID - With only Login ID: Uses the Login ID to generate the user ID - With both: Uses the Login ID preferentially to generate the user ID ## Client SDK Usage Guide For Web, iOS, Android, and other client SDKs, you only need to focus on two key methods. ### identify - Call When User Logs In When the user completes registration or login, call the `identify` method to associate the Login ID with the current device's Anonymous ID. > **Key point**: Calling the `identify` method **automatically generates and sends a `$Identity` event**. You do not need to manually send this event. This is an important distinction between client SDKs and server-side SDKs. **JavaScript Example**: ```javascript // After user login succeeds const userId = 'user_12345'; // Get user ID from login API // Call identify to associate user identity SensorsWave.identify(userId); // identify automatically generates a $Identity event; no need to track a login event separately // If you need to record additional info like login method, you can optionally track a business login event SensorsWave.trackEvent('UserLogin', { login_method: 'email' }); ``` **iOS Example**: ```swift // After user login succeeds let userId = "user_12345" // Call identify to associate user identity SensorsWave.identify(userId) // identify automatically generates a $Identity event; no need to track a login event separately // If you need to record additional info like login method, you can optionally track a business login event SensorsWave.trackEvent("UserLogin", properties: [ "login_method": "email" ]) ``` **Android Example**: ```java // After user login succeeds String userId = "user_12345"; // Call identify to associate user identity SensorsWave.identify(userId); // identify automatically generates a $Identity event; no need to track a login event separately // If you need to record additional info like login method, you can optionally track a business login event JSONObject properties = new JSONObject(); properties.put("login_method", "email"); SensorsWave.trackEvent("UserLogin", properties); ``` **What happens behind the scenes**: 1. The SDK stores the Login ID locally 2. **The SDK automatically sends a `$Identity` event** that associates the Anonymous ID with the Login ID 3. All subsequent events will report both the Anonymous ID and Login ID > **About the `$Identity` event**: This is a Sensors Wave Preset Event that marks user identity association behavior. **Calling the `identify` method automatically generates and sends this event** — you should not send it manually. This event contains `anon_id` and `login_id` fields, and the server automatically handles user identity merging based on this event. Business events like `UserLogin` tracked after `identify` are optional and are mainly used to record business information such as login method and login time. ### reset - Call When User Logs Out When the user logs out, call the `reset` method to unbind the Login ID from the device. **JavaScript Example**: ```javascript // When user logs out SensorsWave.reset(); // Keeps the Anonymous ID by default // If you also need to reset the Anonymous ID (e.g., shared device scenario) SensorsWave.reset(true); ``` **Parameter description**: - `reset()`: Log out, keep the Anonymous ID (default behavior) - `reset(true)`: Log out and reset the Anonymous ID, generating a new Anonymous ID > **Usage recommendation**: In most cases, `reset()` is sufficient. Only reset the Anonymous ID on shared devices (e.g., kiosk devices in a store). ### Complete Login/Logout Example ```javascript // Initialize SDK SensorsWave.init('YOUR_SOURCE_TOKEN', { apiHost: 'https://your-api-endpoint.com', autoCapture: true }); // User login flow async function handleLogin(email, password) { try { const response = await fetch('/api/login', { method: 'POST', body: JSON.stringify({ email, password }) }); const { userId } = await response.json(); // Associate user identity (automatically generates $Identity event) SensorsWave.identify(userId); // Optional: track a business login event to record login method and other business info SensorsWave.trackEvent('UserLogin', { login_method: 'email', login_time: new Date().toISOString() }); } catch (error) { console.error('Login failed:', error); } } // User logout flow function handleLogout() { // Unbind user identity SensorsWave.reset(); // Track logout event SensorsWave.trackEvent('UserLogout'); } ``` ## Server-Side SDK Usage Guide Due to limitations of the runtime environment, server-side SDKs require you to manually manage Anonymous IDs and Login IDs. ### Server-Side SDK Limitations - Cannot automatically collect Anonymous IDs (the server cannot access client cookies or device information) - Cannot use local storage (each request is independent) Therefore, server-side SDKs require you to actively set ID information. ### Scenario 1: Tracking Anonymous User Events If you need to track anonymous user behavior on the server, you need to obtain the Anonymous ID from the client and pass it to the server. **Go Example**: ```go // Get the Anonymous ID from the client (e.g., via HTTP Header or request parameter) anonId := r.Header.Get("X-Anon-ID") // Set the Anonymous ID when sending the event user := sensorswave.User{ AnonID: anonId, } err := client.TrackEvent(user, "PageView", sensorswave.Properties{ "page_url": "/products/123", }) ``` ### Scenario 2: Tracking Logged-In User Events If the user is already logged in, you can directly use the Login ID. **Go Example**: ```go // Get the user ID from the session or token userId := session.Get("user_id") // Set the Login ID when sending the event user := sensorswave.User{ LoginID: userId, } err := client.TrackEvent(user, "Purchase", sensorswave.Properties{ "order_id": "ORDER-001", "total_amount": 299.00, }) ``` ### Scenario 3: Server-Side User Login Tracking **Important**: Unlike client SDKs, the server-side SDK requires you to **manually call the `Identify` method** to associate user identity. When tracking login behavior on the server, you **must provide both the Anonymous ID and Login ID** to connect the user's pre-login and post-login behaviors. **Go Example**: ```go // User login endpoint func handleLogin(w http.ResponseWriter, r *http.Request) { // Get the Anonymous ID from the request (passed by the client via form or Header) anonId := r.FormValue("anon_id") // Verify username/password and get user ID userId := authenticateUser(username, password) // Server-side must manually associate user identity user := sensorswave.User{ AnonID: anonId, LoginID: userId, } err := client.Identify(user) if err != nil { log.Printf("Failed to associate user: %v", err) } } ``` > **Client vs Server**: > - **Client SDK**: Calling the `identify()` method automatically generates and sends a `$Identity` event > - **Server SDK**: You must manually call the `Identify()` method and set both `AnonID` and `LoginID` on the User object **Client-side companion example** (JavaScript): ```javascript // When the login form is submitted, send the Anonymous ID along with the request to the server async function submitLogin(email, password) { const anonId = SensorsWave.getAnonId(); // Get the current Anonymous ID const response = await fetch('/api/login', { method: 'POST', body: JSON.stringify({ email, password, anon_id: anonId // Pass to the server }) }); // After login succeeds, the client should also call identify (automatically generates $Identity event) const { userId } = await response.json(); SensorsWave.identify(userId); } ``` ## Typical Business Scenarios ### Scenario 1: New User Registration Flow **Business description**: The complete flow from a new user's first visit to registration and login. **User behavior path**: ``` 1. User visits the website for the first time (anonymous phase) └─> SDK generates Anonymous ID: anno_001 2. User browses products (anonymous phase) └─> Event: ProductView (anon_id: anno_001) 3. User adds to cart (anonymous phase) └─> Event: AddToCart (anon_id: anno_001) 4. User registers and logs in └─> Call: SensorsWave.identify('user_001') └─> SDK auto-generates event: $Identity (anon_id: anno_001, login_id: user_001) 5. User completes purchase (after login) └─> Event: Purchase (anon_id: anno_001, login_id: user_001) ``` **Analysis outcome**: - All pre-login and post-login behaviors are attributed to the same user (`user_001`) - You can analyze the complete conversion path from first visit to purchase completion - When counting users, `anno_001` and `user_001` are recognized as the same user ### Scenario 2: Multi-Device Login **Business description**: The same user logs in and uses the app on multiple devices. **User behavior path**: ``` 1. User logs in on Device A └─> Call: SensorsWave.identify('user_001') └─> SDK auto-generates event: $Identity (anon_id: device_a, login_id: user_001) 2. User browses on Device B (not logged in) └─> Event: ProductView (anon_id: device_b) 3. User logs in on Device B └─> Call: SensorsWave.identify('user_001') └─> SDK auto-generates event: $Identity (anon_id: device_b, login_id: user_001) 4. Subsequent behavior on any device └─> All attributed to user user_001 ``` **Analysis outcome**: - Behaviors from Device A and Device B are both attributed to `user_001` - You can analyze user cross-device usage habits - User count statistics are accurate without double-counting ### Scenario 3: Device Sharing (Family Scenario) **Business description**: Multiple users share a single device, with different users logging in one after another. **User behavior path**: ``` 1. Device initial state (anonymous) └─> SDK generates Anonymous ID: device_shared 2. User A logs in └─> Call: SensorsWave.identify('user_a') └─> SDK auto-generates event: $Identity (anon_id: device_shared, login_id: user_a) 3. User A uses the app └─> Event: ProductView (anon_id: device_shared, login_id: user_a) 4. User A logs out └─> Call: SensorsWave.reset() 5. User B logs in (same device) └─> Call: SensorsWave.identify('user_b') └─> SDK auto-generates event: $Identity (anon_id: device_shared, login_id: user_b) 6. User B uses the app └─> Event: ProductView (anon_id: device_shared, login_id: user_b) ``` **Analysis outcome**: - Device behaviors at different time periods are attributed to different users - User A and User B are correctly identified as two different users - Anonymous behaviors before the first login are attributed to User A > **Tip**: In this scenario, the Anonymous ID will exist in the historical records of multiple users. Sensors Wave uses timestamps and login events to correctly attribute behavioral data. ### Scenario 4: Public Device (Store Kiosk) **Business description**: A public kiosk device in a store that needs to clear user data when each user logs out. **Best practice**: ```javascript // Reset the Anonymous ID when user logs out function handleLogoutOnPublicDevice() { // Clear user identity and generate a new Anonymous ID SensorsWave.reset(true); // Parameter is true // Track logout event SensorsWave.trackEvent('UserLogout', { device_type: 'public_kiosk' }); } ``` **Outcome**: - A new Anonymous ID is generated after each logout - Different users' data is completely isolated - User privacy is protected ## Important Notes ### Client SDK **Recommended practices**: - (Recommended) Call the `identify` method immediately after a successful login - (Recommended) Call the `reset` method when the user logs out - (Recommended) Let the SDK automatically manage the Anonymous ID; no manual setup needed - (Recommended) In single-page applications, ensure SDK initialization completes before routing **Practices to avoid**: - (Not recommended) Do not call `identify` when the user is not logged in - (Not recommended) Do not frequently call `reset(true)` to reset the Anonymous ID (unless on a public device) - (Not recommended) Do not repeatedly call `identify` on page refresh - (Not recommended) Do not use mutable values as the Login ID (e.g., session ID) ### Server-Side SDK **Recommended practices**: - (Recommended) When tracking login behavior (`$Identity`), always provide both the Anonymous ID and Login ID - (Recommended) Obtain the Anonymous ID from the client and pass it to the server - (Recommended) Use a stable user primary key as the Login ID **Practices to avoid**: - (Not recommended) Do not generate random Anonymous IDs on the server (will make user association impossible) - (Not recommended) Do not provide only the Login ID without the Anonymous ID in login events - (Not recommended) Do not use session IDs or tokens as user IDs ### Login ID Selection **Recommended practices**: - (Recommended) Use the user primary key from the business system (e.g., `user_id`) - (Recommended) Use an immutable unique identifier (e.g., user ID, email) - (Recommended) Ensure the Login ID is globally unique within the system - (Recommended) Use the same Login ID across platforms to identify the same user **Practices to avoid**: - (Not recommended) Do not use values that may change (e.g., phone numbers — users may change numbers) - (Not recommended) Do not use Session IDs or temporary tokens - (Not recommended) Do not use different user identifiers on different platforms (they will be identified as different users) ## FAQ ### When should I call the identify method? **Recommended timing**: 1. **After user registration succeeds** ```javascript async function handleSignup(email, password) { const { userId } = await registerUser(email, password); // Calling identify automatically generates a $Identity event SensorsWave.identify(userId); } ``` 2. **After user login succeeds** ```javascript async function handleLogin(email, password) { const { userId } = await loginUser(email, password); // Calling identify automatically generates a $Identity event SensorsWave.identify(userId); } ``` 3. **At app startup, if the user is already logged in** ```javascript // Check login status at app initialization const currentUser = getCurrentUser(); if (currentUser) { // Calling identify automatically generates a $Identity event SensorsWave.identify(currentUser.userId); } ``` **Not recommended timing**: - (Not recommended) Calling on every page refresh (will produce duplicate `$Identity` events) - (Not recommended) Calling when the user is not logged in - (Not recommended) Calling with a temporary ID (e.g., session ID) ### What happens if identify is called multiple times? Calling `identify` multiple times for the same user is safe, but will produce multiple `$Identity` events: ```javascript // First call SensorsWave.identify('user_123'); // Sends $Identity event // Second call (same user_123) SensorsWave.identify('user_123'); // Sends $Identity event again (redundant) ``` **Best practice**: ```javascript // Track whether identify has already been called let hasIdentified = false; function identifyUser(userId) { if (!hasIdentified) { SensorsWave.identify(userId); hasIdentified = true; } } ``` Or use a method provided by the SDK to check: ```javascript // Check the current Login ID const currentLoginId = SensorsWave.getLoginId(); if (currentLoginId !== userId) { SensorsWave.identify(userId); } ``` ### Does the order of identify and trackEvent matter? **Yes!** You should call `identify` first, then track post-login business events. **Recommended order**: ```javascript async function handleLogin(email, password) { const { userId } = await loginUser(email, password); // 1. Associate user identity first (automatically generates $Identity event) SensorsWave.identify(userId); // 2. Optional: track a business login event to record additional login info SensorsWave.trackEvent('UserLogin', { login_method: 'email' }); // 3. Other post-login business logic loadUserProfile(userId); } ``` **Explanation**: - The `identify` method automatically generates a `$Identity` event for identity association — this is required - Business events like `UserLogin` are optional and are mainly used to record business information such as login method and login source - If you only need to associate user identity, you can just call `identify` without additionally tracking a `UserLogin` event **Not recommended order**: ```javascript // Bad example async function handleLogin(email, password) { const { userId } = await loginUser(email, password); // Tracking event first (user identity not yet associated) SensorsWave.trackEvent('UserLogin'); // Calling identify later (UserLogin event will carry old identity info) SensorsWave.identify(userId); } ``` ### How do I handle a user changing their Login ID? If a user changes their Login ID (e.g., changes email or phone number), you need to choose an approach based on your business needs: **Method 1: Use an immutable user primary key (Recommended)** ```javascript // Use the database user primary key as the Login ID SensorsWave.identify(user.id); // 'user_12345', never changes // Record email, phone number as User Properties SensorsWave.profileSet({ email: user.email, phone: user.phone }); ``` **Method 2: Re-identify with the new Login ID** ```javascript // After user changes email function handleEmailChange(oldEmail, newEmail) { // Re-identify with the new email SensorsWave.identify(newEmail); // Track email change event SensorsWave.trackEvent('EmailChanged', { old_email: oldEmail, new_email: newEmail }); } ``` > **Recommendation**: Prefer Method 1 — use an immutable user primary key (e.g., database auto-increment ID, UUID) as the Login ID, and store mutable information (e.g., email, phone number) as User Properties. ### What happens when a user clears cookies or app data? After clearing cookies or app data, the SDK will generate a new Anonymous ID. When the user logs in again: 1. The SDK calls the `identify` method to associate the new Anonymous ID with the Login ID 2. Sensors Wave automatically attributes the new device to the logged-in user 3. Historical data from the previous Anonymous ID is still retained under that user **Example**: ``` Original device (before clearing data): - Anonymous ID: device_old - User behavior: browsing products, adding to cart After user clears data: - Anonymous ID: device_new (SDK generates a new Anonymous ID) User logs in again: - Calls identify('user_123') - Sensors Wave auto-associates: device_new → user_123 Result: - user_123's historical data includes: (Supported) device_old behaviors (browsing, adding to cart) (Supported) device_new behaviors (all post-login behaviors) ``` **Result**: All of the user's historical data is correctly attributed and nothing is lost. ### How do I verify that user identification is configured correctly? **Method 1: Use debug mode** ```javascript // Enable debug mode to view event reporting details SensorsWave.init('YOUR_SOURCE_TOKEN', { apiHost: 'https://your-api-endpoint.com', debug: true // View event details in the console }); ``` **Method 2: View real-time events in the Sensors Wave dashboard** 1. Log in to the Sensors Wave console 2. Go to "Data Center" → "Pipeline" → "Real-time Events" 3. View the latest events and confirm that `anon_id` and `login_id` fields are correctly reported **Method 3: Test the complete flow** ```javascript // Test flow console.log('1. Anonymous ID:', SensorsWave.getAnonId()); // Track an anonymous event SensorsWave.trackEvent('TestAnonymousEvent'); // Simulate login SensorsWave.identify('test_user_001'); console.log('2. Login ID:', SensorsWave.getLoginId()); // Track a post-login event SensorsWave.trackEvent('TestLoginEvent'); // Check in the dashboard whether these two events are associated with the same user ``` ### Do single-page applications (SPAs) require special handling? No. The SDK automatically handles route changes. Just ensure: 1. The SDK is loaded at app initialization (before route configuration) 2. The `isSinglePageApp` configuration is enabled 3. `identify` and `reset` methods are called normally when users log in and out ```javascript // React app example // Initialize at the app entry point (before routing) SensorsWave.init('YOUR_SOURCE_TOKEN', { apiHost: 'https://your-api-endpoint.com', isSinglePageApp: true // Enable SPA support }); ``` ### How do I handle third-party login (WeChat, Alipay, etc.)? Third-party login is handled the same way as regular login. The key is to use a unified user ID: ```javascript // After WeChat login succeeds async function handleWechatLogin(wechatCode) { // Exchange WeChat code for user info const response = await fetch('/api/login/wechat', { method: 'POST', body: JSON.stringify({ code: wechatCode }) }); const { userId } = await response.json(); // Use the business system's user ID, not WeChat's openId // identify automatically generates a $Identity event SensorsWave.identify(userId); // Optional: track a business login event to record login method SensorsWave.trackEvent('UserLogin', { login_method: 'wechat' }); } ``` > **Recommendation**: Use the business system's unified user ID rather than third-party platform IDs (e.g., WeChat openId). This allows associating user data from different login methods under the same user. ## Related Documentation - [JavaScript SDK Guide](sdks/javascript.mdx): Detailed SDK integration instructions - [Tracking Strategy](tracking-strategy.mdx): Understand the pros and cons of server-side and client-side tracking - [Data Model](data-model.mdx): Understand the Sensors Wave data structure - [Events and Properties](events-and-properties.mdx): Event design guidelines and best practices --- **Last updated**: January 19, 2026