# 如何准确识别用户
识别用户是一个比较复杂的过程,尤其是对于有帐号体系的产品来说,用户会有多种使用场景,可能会在匿名的情况下访问,也有可能在登录情况下使用,也有可能在同一台设备上登录不同的帐号,也可能同一个帐号在多台设备上登录。
因此,选择合适的用户标识有助于准确标识用户,提高分析的准确性。
## 1. 标识用户
方舟的事件模型中,数据上报时会有用户这个实体,使用 `xwho` 来进行标识。在登录前匿名阶段,`xwho` 中会记录一个匿名 ID ,登录后则应该调用 `alias` 方法传入 注册 ID。后续在方舟中就可通过这个注册ID来查询用户相关的行为了。
### 1.1 匿名 ID
匿名 ID 用来在用户主体未登录应用之前标识,当用户打开集成有方舟 SDK 的应用时,SDK 会给其分配一个 `UUID` 来做为匿名 ID 。
当然,方舟也提供了给用户主体设置匿名 ID 的方式,比如可以使用设备 ID ( iOS 的 IDFA/IDFV,Web 的 Cookie 等)。
### 1.2 注册 ID
通常是业务数据库里的主键或其它唯一标识,注册 ID 是更加精确的用户 ID,但很多应用不会用注册 ID,或者用户使用一些功能时是在未登录的状态下进行的,此时,就不会有注册 ID。
另外,在方舟系统中,我们以为用户主体来进行分析,这个用户主体可能是一个人,一个帐号,也可能是一个家电,一辆汽车。具体以什么做为用户主体,要根据用户实际的业务场景来决定。
### 1.3 distinct_id
即使有了 xwho( 注册 ID / 匿名 ID),实际使用中也会存在注册用户匿名访问等情况,所以需要一个唯一标识将用户行为贯穿起来,distinct_id 就是在 xwho 的基础上根据一些规则生成的唯一 ID。
## 2. 不同场景下选择不同的识别方案
实际接入分析的应用会有多种情况,可以分为两大类:
* **无帐号体系**,e.g. Snapseed、日历
* **有帐号体系**
① 强帐号体系,必须登录 e.g. 钉钉、QQ、微信
② 强帐号体系,存在访客模式,关键转化需登录 e.g. 淘宝、微博、大众点评、招商银行
③ 弱帐号体系,存在访客模式,不登录不影响核心功能使用 e.g. 高德地图、今日头条、墨迹天气
### 2.1 无帐号体系 / 弱帐号体系且不分析登录用户的情况
在这种情况下,无需关心注册 ID,使用方舟的客户端 SDK 时,方舟的SDK会自动生成一个 **UUID** 作为匿名 ID,这个 **UUID** 会做为后续行为数据的匿名 ID(xwho),此时系统生成的 distinct_id 会与匿名 ID 一一对应,计算的用户数也会是 匿名的用户数。
当然,用户也可以通过调用 **identify** 接口来设置匿名 ID,比如使用设备唯一标识。
**identify** 接口格式如下:
```java
void identify(Context context, String xwho)
```
### 2.2 有帐号体系,需要分析注册用户和匿名用户的情况
这种情况下在集成时需要客户在用户进行登录 / 注册 / 完善个人资料等情况下调用 `alias` 接口获得注册 ID,使得匿名 ID 实名化,然后 SDK 就会将数据的 `$is_login` 属性变成 `true`,表示这是一个注册 ID,后续的行为中上报的`xwho`也会有注册ID。
> $is_login 用于标识是否是注册用户
但是实际会存在单用户多设备、单设备多用户、注册用户匿名访问等情况下,如何把每一条记录精准识别到各个用户上,贯通一个用户在一个设备上注册前后的行为,贯通一个注册用户在不同设备上登录之后的行为是个比较复杂的问题。
针对这种场景易观方舟提供了一种识别方案:
当调用 **alias** 接口之后,会将匿名 ID 和注册 ID 关联,后台算法根据一定的规则生成一个distinct_id,用于唯一标识用户,被绑定的匿名 ID 和注册 ID 发生的所有行为都会被认为是同一个用户实体发生的,在进行事件、漏斗、留存等用户相关的分析的时候也只会算作一个用户。
## 3. 原理说明
下面以一个实际的场景来说明用户识别的机制,其中:
发送的 `xwho`:登录前是匿名 ID ,登录后是注册 ID,调用 **alias** 接口时,两个 ID 会同时发送;
是否是注册 ID:当`xwho`为是否为一个注册 ID;
方舟 distinct_id:方舟内部给该用户分配的唯一标识,是用于计算触发用户数、漏斗、留存等的最终依据,对应自定义查询中 events 表中的 user_id 及 users 表中的 id 字段。
> 注意:在识别过程中,一个匿名 ID 只能和一个注册 ID 绑定,同样的一个注册 ID 也只能和一个匿名 ID 绑定。
| 行为顺序 | 发送的xwho | 是否是注册 ID | 方舟 distinct_id |
| ---- | --------------- | ----------- | ---------------- |
| 1 | X | 否 | 1 |
| 2 | xiaozhou -> X | ID 关联(成功) | 1 |
| 3 | xiaozhou | 是 | 1 |
| 4 | xiaozhou | 是 | 1 |
| 5 | dawang -> X | ID 关联(失败) | 2 |
| 6 | dawang | 是 | 2 |
| 7 | Y | 否 | 3 |
| 8 | xiaozhou -> Y | ID 关联(失败) | 1 |
| 9 | xiaozhou | 是 | 1 |
| 10 | dawang -> Y | ID 关联(失败) | 2 |
详细说明如下:
1. 某用户在小米手机上新安装了 App,匿名产生了一系列操作,SDK 生成的匿名 ID 为 X,对应分配的方舟 distinct_id 为 1;
2. 该用户进行了注册并登录,其注册 ID 为 xiaozhou,此时,需要调用 SDK 的 `alias` 接口,此时方舟会将匿名 ID X 与 注册 ID xiaozhou 进行成功关联;
3. 该用户在登录之后继续进行了一系列行为;
4. 该用户退出登录并进行了一系列的操作,SDK 不调用任何方法,此时方舟依然使用注册 ID xiaozhou 来标识当前用户;
5. 该用户使用一个已注册但未接入方舟系统的的帐号 dawang 来进行登录,此时方舟将尝试将 X 与 dawang 进行关联,由于 X 已经和 xiaozhou 关联,所以会关联失败,同时会分配一个新的方舟 distinct_id 为 2;
6. 该用户使用帐号 dawang 进行了一系列行为,这里方舟都使用注册 ID dawang来标识此用户;
7. 该用户更换了一个全新的苹果手机,并进行了一系列操作,由于尚未登录,此时方舟使用全新的匿名 ID Y 来标识此用户,对应分配的方舟 distinct_id 为 3;
8. 该用户在苹果手机上使用帐号 xiaozhou 进行登录,此时方舟将尝试将匿名 ID Y 与注册 ID xiaozhou进行关联,由于 xiaozhou 已经与 X 关联,因此会关联失败,但是依然会切换到以 xiaozhou 为注册 ID 的用户,其对应的方舟 distinct_id 依然为 1;
9. 该用户在苹果手机上的后续行为都以注册 ID xiaozhou来标识。
## 4. 使用前提
正确集成SDK,遵循接口的调用顺序,否则可能会导致部分用户标识异常,影响数据统计的正确性。
在 SDK 初始化完成之后,SDK 会自动生成一个 UUID 作为匿名用户标识,记录在 `xwho` 中,之后 SDK 采集上报的数据中 `$is_login` 属性为 `false`,来表示这是 匿名 ID 。
>[warnig] 如果因业务要求需要对SDK生成的UUID进行调整,可以通过调用接口 **`identify`** 进行修改,接口使用方式请查看SDK指南。
当用户进行登录 / 注册 / 完善个人资料等会使得用户有 注册 ID 时的操作时,调用 `alias` 接口,上传匿名ID 和注册 ID 的关联关系。
**alias**接口格式如下:
```java
//Andorid SDK 示例,其中aliasId为您业务系统的ID
void alias(Context context, String aliasId)
```
当调用**alias**接口之后,接下来事件数据的 `$is_login` 属性都会被自动设置为`true`,表示事件是由一个注册 ID 触发的,后续行为事件中 `xwho` 都会是注册 ID。
在用户退出登录或者注销帐号时,如果想让匿名期间的行为归属到上一个登录用户时,可以不调用任何接口;反之,不想让匿名记录归属到上一个登录用户时,需要调用 **reset** 接口,之后方舟的 SDK 会自动生成一个 UUID 作为用户标识,上传到服务器时,会根据新生成一个distinct_id:
* 当下一个登录用户是首次注册,没被别的设备绑定时,匿名期间的用户就会归属到新用户上;
* 当下一个登录用户已经被其他设备绑定过时,匿名期间的用户行为就既不属于上一个用户也不属于下一个用户,只属于新生成的 UUID 这个匿名用户的行为。
**reset**接口格式如下:
```java
//Andorid SDK 示例
void reset(Context context)
```
当调用**reset**接口之后,接下来事件数据的 `$is_login` 属性都会被自动设置为 `false`,表示事件是由一个匿名 ID 触发的。
## 5. 方案缺点
虽然该方案可以实现跨设备的用户贯通、以及准确的注册漏斗,但仍然存在局限性:
如果一个已注册用户(即已经和某个匿名 ID 关联过了)在一个新设备上进行操作,那么他在这个新设备的登录前行为是无法被准确识别的;
同样的,如果一个已注册的设备(即已经被关联到某个注册 ID了)上再次有新用户进行注册,也无法再次进行关联。
事实上,在比如如下的场景中,
1. 用户 xiaoming 登录后使用了一些功能后退出;
2. 匿名用户 X 访问;
3. 用户 dawang 登录使用
但匿名 X 到底是 xiaoming 还是 dawang ,或者是其他人都有可能,但是目前的方案还不能对全部场景做出准确判断。
>[info] 以上内容没有解答我的问题?[点击我进入方舟论坛去反馈](https://www.analysysdata.com/forum/index) 🚀
- 产品简介
- 快速上手
- Step 1 安装部署
- Step 2 激活系统创建项目
- Step 3 开启您的分析旅程
- 1. 集成 SDK
- 2. 可视化埋点
- 3. 创建分析模型
- 附:埋点方案设计
- 附:数据分析思路
- 产品更新日志
- V5.5 新增LTV分析功能等
- V5.3 UI 升级、分布分析重构、维度表动态更新、细节优化等
- V5.2 新增归因分析、消息中心、重构埋点方案、优化看数据体验……
- V5.1.0317 体验优化& Bug修复
- V5.1 升级可视化埋点、增强权限控制……
- Part I 产品功能说明
- 名词解释
- 指标说明
- 看板
- 5.3.3 看板 UI 重构
- 分析
- 事件分析
- 渠道分析
- 渠道相关名词解释
- 来源识别规则
- 搜索引擎
- 社交媒体
- 小程序场景值
- Session 分析
- Session 规则
- 实时分析
- 留存分析
- 转化漏斗
- 智能路径
- 归因分析
- 热图分析
- Web/H5 热图
- APP 热图
- 分布分析
- 间隔分析
- 属性分析
- LTV 分析
- 多主体分析
- 自定义查询
- 用户
- 用户分群
- 用户探查
- 用户标签
- 标签体系应用概览
- 标签体系
- 标签生命周期管理
- 标签加工
- 如何自定义SQL创建标签
- 单用户档案
- 运营
- 广告跟踪
- 微信小程序渠道追踪
- 预置广告媒介和渠道
- App 推广监测(Beta)
- 电子邮件
- 短信
- 消息通知
- 项目管理
- 项目概览
- 项目角色管理
- 项目成员管理
- 数据接入管理
- 埋点方案
- 可视化埋点
- 集成SDK接入数据
- 数据验证
- 用户数据导入
- 微信小程序全埋点事件定义
- 元数据管理
- 元事件
- 虚拟事件
- 事件属性
- 用户属性
- Session 管理
- 页面组管理
- 维度表
- 服务集成配置
- 监控告警
- 智能监控
- 自定义监控
- 平台管理
- 企业概览
- 项目管理
- 成员管理
- 安全设置
- 企业设置
- 日志管理
- 帐号设置
- Part II 技术文档
- 技术接入准备工作
- 部署环境检测工具
- 数据模型
- 数据格式
- 预置事件和属性
- App预置事件/属性
- JS 预置事件/属性
- 如何准确识别用户
- 如何设计埋点方案
- 分平台上报数据 vs 跨平台打通
- SDK 指南
- Android SDK
- 快速集成
- 全埋点模块
- 消息推送模块
- Android Hybrid模式
- SDK Gradle集成方式
- 多渠道打包
- 易观小工具
- 合规相关
- iOS SDK
- 快速集成
- 全埋点介绍
- iOS Hybrid模式
- 消息推送模块
- JS SDK
- 快速集成
- JS SDK基础版
- JS SDK插件
- uni-app SDK
- 快速集成
- 打包原生APP
- 开启移动端全埋点
- uni-app SDK标准版
- 微信小程序 SDK
- 快速集成
- 微信小程序标准版
- 微信小程序插件版
- 微信小程序通用框架版
- 支付宝小程序 SDK
- 支付宝小程序标准版
- 支付宝小程序通用框架版
- 字节跳动小程序 SDK
- 字节跳动小程序标准版
- 字节跳动小程序通用框架版
- 百度小程序 SDK
- 百度小程序标准版
- 百度小程序通用框架版
- 钉钉小程序 SDK
- 钉钉小程序标准版
- 钉钉小程序通用框架版
- QQ小程序 SDK
- QQ小程序标准版
- QQ小程序通用框架版
- 快应用 SDK
- 华为WeCode小程序
- WeCode SDK 标准版
- WeCode SDK插件
- PhoneGap SDK
- mPaaS SDK
- ReactNative SDK
- Flutter SDK
- Java SDK
- Python SDK
- PHP SDK
- C++ SDK
- C# SDK
- Node JS SDK
- Lua SDK
- Golang SDK
- SDK FAQ
- identify与alias的区别
- 爬虫数据如何识别?
- 页面停留如何获取时间?
- 如果获取SDK及更新日志
- 代码埋点和无埋点有什么区别
- Web页面中发现丢失某一个事件
- 自研 SDK 注意事项
- 页面时长统计功能
- 飞书小程序 SDK
- 飞书小程序标准版
- 飞书小程序通用框架版
- Unreal Engine SDK
- 数据验证
- 客户端埋点验证
- Debug 数据验证
- 数据入库验证
- 数据导入
- 接口导入
- JAVA工具包
- 标准json文件导入
- csv格式导入
- 数据导入FAQ
- 数据导出
- JAVA工具包
- 事件数据导出
- 用户数据导出
- 直接从Kafka中消费数据
- 使用程序访问数据库
- 脚本工具
- API
- 分析API
- 事件分析
- 留存分析
- 自定义查询
- 转化漏斗
- 属性分析
- Session分析
- 渠道分析
- 分布分析
- 用户API
- 分群查询
- 用户档案
- 分群管理
- 管理API
- 权限管理
- 元数据管理
- 埋点方案管理
- 维度表管理
- 运营API
- 广告跟踪
- APP推广监测
- 平台管理API
- 项目管理
- 成员管理
- 第三方登录
- OAuth2.0登录
- LDAP登录
- GDPR 合规
- Part III 常见问题
- License 许可
- 产品试用及采购
- 参与贡献