注意:不要在线上页面直接切换不同项目的数据接收地址,会导致首日首次,id 关联异常。建议在线下测试时数据发到测试项目,没问题的话,线上采集的数据直接发往正式项目。

新增用户

一般我们对新增用户的定义是第一次使用产品的用户,或者是一些关键行为(比如注册、购买)的首次触发。在神策分析中,可以结合 是否首日访问( $is_first_day ) 属性来得到每天访问的新增用户,以及结合 是否首次触发事件(  $is_first_time )属性来得到首次触发关键事件的用户。

新增用户指标配置

Web 端新增用户定义:当日的独立访客中,历史上首日访问网站的访客定义为新用户。

App 端新增用户定义:当日启动 App 的用户中,历史上首日启动 App 的用户为新用户数。

小程序端新增用户定义:当日启动小程序的用户中,历史上首日启动小程序的用户为新用户数。

用户首次访问时间分布:用户第一次使用 Web/App/小程序 的时间分布

首次触发事件定义:第一次触发 APP 启动/Web 浏览/小程序启动的新用户

新增用户标记采集

新用户的标记主要是在客户端完成,神策 SDK 默认会采集的区分新增用户的字段有

前端事件公共属性:是否首日访问($is_first_day)

字段名称类型说明JS SDK 自动采集iOS SDK 自动采集Android SDK 自动采集小程序 SDK 自动采集服务端 SDK 自动采集
$is_first_day布尔值是否首日访问YYYYN

实现逻辑:

1. Web 端:用户第一次访问埋入神策 SDK 页面的当天(即第一天),JS SDK 会在网页的 cookie 中设置一个首日访问的标记,并设置第一天 24 点之前,该标记记为首日为 true,即第一天触发的网页端所有事件中,$is_first_day=true。第一天之后,该标记则为 首日为 false,即第一天之后触发的网页端所有事件中,​$is_first_day= false;

2. 小程序端:用户第一天访问埋入神策 SDK 的页面时,小程序 SDK 会在 storage 缓存中创建一个首日为 true 的标记,并且设置第一天 24 点之前,该标记均为 true。即第一天触发的小程序端所有事件中,$is_first_day=true。第一天之后,该标记则为 首日为 false,即第一天之后触发的小程序端所有事件中,​$is_first_day= false;

3. APP 端:用户安装 App 后,第一次打开埋入神策 SDK 的 App 的当天,Android/iOS SDK 会在手机本地缓存内,创建一个首日为 true 的标记,并且设置第一天 24 点之前,该标记均为 true。即第一天触发的 APP 端所有事件中,$is_first_day=true。第一天之后,该标记则为 首日为 false,即第一天之后触发的 APP 端所有事件中,$is_first_day= false;

前端事件属性:是否首次触发事件($is_first_time)

字段名称类型说明JS SDK 自动采集iOS SDK 自动采集Android SDK 自动采集小程序 SDK 自动采集服务端 SDK 自动采集
$is_first_time布尔值是否首次触发事件YYYYN

实现逻辑:

本地针对 $pageview/$AppStart/$MPLaunch 事件存储一个标记。标记默认是 no,首次为把 no 修改为 yes,之后都是 no。

用户属性:首次访问时间($first_visit_time)

字段名称类型说明JS SDK 自动采集iOS SDK 自动采集Android SDK 自动采集小程序 SDK 自动采集服务端 SDK 自动采集
$first_visit_timeDatetime首次访问时间YYYYN

实现逻辑:

1. Web 端、小程序端:集成神策 Js、MiniProgram SDK 后,设置 autotrack 开启全埋点,SDK 会默认在用户第一次浏览页面/启动小程序时,调用 profile_set_once 接口给用户设置首次访问时间属性。

2. APP 端:集成神策 iOS、Android SDK 后调用 trackInstallation 接口,调用此接口之后会在用户首次使用 app 的时候设置首次访问时间属性。如果没有调用 trackInstallation 接口,不会主动设置首次访问时间。

首次首日标记修正

如果用户的 App 缓存被清理或者用户卸载重装后,如果匿名 ID 不变的话都会造成 App 端目前的⾸日⾸次判断逻辑失效,虽然是⽼用户,但是⾸日首次属性却为 true。为了避免此种情况造成的新增用户不准的问题,神策服务端增加了⾸⽇首次的修正功能。

首日访问在服务端的修正

从神策分析 1.8 版开始,所有的单机版用户和集群版用户已经默认开启了“是否首日访问”标记在服务端的修正,即以一个专用的数据库记录用户首日访问的时间。当上报的事件包含 $is_first_day (是否首日访问)属性并且取值为 true 时,服务端导入这条事件时会先在数据库中以触发的 Distinct Id 对应的神策内部 Id 进行查询,若没有查到,那么在数据库中记录该 Distinct Id 首日访问的时间;如果可以查到那么判断本次事件触发时间与之前记录的是否是同一天,若不是同一天(无论是之前的时间还是之后的时间)那么修改 $is_first_day 为 false。

这在一定程度上解决了 App 卸载重装被算作新用户的问题,例如 App 重装后设备里存的 "首日标记"被删除,那么客户端向服务端上报时 $is_first_day 的值为 true,服务端可以根据数据库中的记录判断该值是否应该被修正为 false 。

在判断新增用户时,神策是选择【App 启动是否⾸日为真】判断的。如果客户在接入神策之前有一批历史用户,正常接入神策后,由于神策没有保存这些历史用户的首次访问时间,会将这批老用户标记为新增用户。如果想将这批历史⽤户正确标记为老用户,需要在他们的数据上报之前就将他们的首次访问时间导入到该数据库。导入步骤如下:

1. 生成一个文件,每行为一个用户的 Distinct Id 和首次访问时间(以 unix 时间戳表示):

6D92078A-8246-4BA4-AE5B-76104861E7DC 1513577063
5D3169E2-16BC-316C-12AB-1E2EC1A79E2B 1512057600

注意:

  • 该文件上传之后,只对上传日期之后入库的数据有效。早于首次访问时间文件上传时间的入库的数据无法修改;
  • 服务端会根据上传的首次访问时间,对实时导入的事件属性 $is_first_day(是否首日访问)取值为 true 修正,修正规则是仅对 $is_first_day 为 true 的属性值进行修复,且只要导入的事件的 time 和服务端记录的首次访问时间不是同一天就会修正为 false(包含 time 早于服务端的时间也会修正 )。不会修复 $is_first_day 为 false 的属性值。
  • 服务端会根据上传的首次访问时间,修正实时导入的用户属性 $first_visit_time(首次访问时间),修正 $first_visit_time 为服务端上传的首次访问时间 。
  • 服务端上传的首次访问时间,不会 对 $is_first_time 的属性进行修正。目前不支持提前在服务端上传首次访问时间,对 ​$is_first_time = true 的属性进行修正。只有在导入过 ​$is_first_time = true 事件数据之后,服务端才能记录该事件的首次访问时间。

2. 如果文件中的 Distinct Id 是设备 ID(参考2021-10-19_10-11-05_.标识用户 v1.13),继续下一步。若 Distinct Id 是登录 ID,则需要通过 SDK 或导入工具对每个 ID 导入一条 profile_set,设置 is_login_id 为 true,properties 可以为空。例如 Java SDK 可以调用:

sensorsAnalytics.profileSet("123456789", true, Collections.emptyMap());
JAVA

3. 登录神策服务器,使用 sa_cluster 用户执行:

java -cp '/home/sa_cluster/sa/extractor/lib/extractor-1.0-SNAPSHOT.jar:/home/sa_cluster/sa/commonjars/*' com.sensorsdata.analytics.extractor.utils.ImportFirstTimeUtils --project 导入的项目名 --file 数据文件路径 --is_login_id distinct_id 是否是登录 ID,若是则为 yes,否则为 no
CODE
java -cp '/home/sa_cluster/sp/extractor/lib/extractor-1.0-SNAPSHOT.jar:/home/sa_cluster/sp/commonjars/*' com.sensorsdata.analytics.extractor.utils.ImportFirstTimeUtils --project 导入的项目名 --file 数据文件路径 --is_login_id distinct_id 是否是登录 ID,若是则为 yes,否则为 no
CODE
sdfadmin import_first_time --project 导入的项目名 --file 数据文件路径 --event 事件名,可选
CODE

首次触发事件在服务端的修正

目前神策预制采集的“是否首次触发事件” 只针对 $pageview/$AppStart/$AppStartPassively/$MPLaunch 事件才会采集,并不是所有事件都会有这个属性。如果需要对自定义事件添加 $is_first_time 属性,可参考 1.2.2.2 。

在一些分析场景中,我们希望可以通过一个事件属性判断该事件(自定义事件,前端和后端事件皆可)是否是某个用户首次触发,例如 App 启动中的这个属性可以判断用户是否首次启动 App,加入购物车事件中的这个属性可以判断用户是否首次将商品加入购物车。这就需要我们针对“启动”,“购物”事件来增加 $is_first_time 属性来判断是否是触发关键事件的新用户。

导入时添加字段

在导入事件时,若认为这次事件 可能 是该用户(distinct_id)首次触发,设置 $is_first_time 的值为 true 即可。其原理是神策后端导入模块在数据导入过程中会在遇到 $is_first_time 的值为 true 时判断和 修正 该值,具体来说,若遇到 $is_first_time 的值为 true 的事件数据,神策后端会在数据库查询该用户在该事件是否有首次访问记录,若已记录的触发时间与本次不同,那么将修改 $is_first_time 的值为 false,否则将记录该用户首次触发事件时间并保持 $is_first_time 值为 true。

自定义事件设置首次触发事件属性示例

以 Java SDK 为例:

// 首次触发"BuyGold"事件标记"$is_first_time"为 true,最终导入值为 true
properties.put("$is_first_time", true); 
sa.track("user1", false, "BuyGold", properties);

// do something else ...

// 再次触发"BuyGold"事件标记"$is_first_time"为 true,最终导入值为 false
properties.put("$is_first_time", true); 
sa.track("user1", false, "BuyGold", properties);
CODE

虽然两次都设置了 $is_first_time 为 true,但实际导入后仅第一次导入的值为 true。

注意事项

  1. 仅当 $is_first_time 值为 true 时会触发上述逻辑;
  2. 若之前导入数据没有设置过 $is_first_time 值为 true,那么第一次出现时才会记录首次触发时间,并且以后以这次时间判断;
  3. 该逻辑里判断是否首次触发是以事件触发时间(精确到毫秒)是否与数据库里的值相等作为条件,若两次触发事件时间相同且都设置了 $is_first_time 值为 true 将不会进行修正;一般情况下不会发生这种情况,例如 App 连续发送两次事件,若第二次已经明确知道不是首次时,不应该设置 $is_first_time 值为 true;
  4. 该逻辑受数据导入顺序影响,例如先导入 6 日数据并标记了首次,再导入 3 日的数据并标记了首次,最终 6 日的数据首次被标记为 true,而 3 日的将被标记为 false;
  5. 本功能在 1.8 及以后的版本中支持,且构建时间(可在后端的关于页面查看)在 2017-11-26 之后,否则需要先进行升级。

常见问题

同一用户同一天的事件中首日($is_first_day)有真有假

可能是时区差异造成的,例如用户在 A 地的的客户端时间比中国时间晚 12 个小时,客户服务器的时间是中国时间。当用户在 A 地客户端时间为 2019-08-02  23:00 时触发事件,对应的 $is_first_day 属性为 true,记录该事件的时间是 2019-08-02 11:00; 而当用户在 A 地客户端时间为 2019-08-03  02:00 时触发事件,对应的 $is_first_day 属性为 false,记录该事件的时间是 2019-08-02 14:00。在神策分析查询数据时,就会出现 20219-08-02 这一天同一用户触发的事件中 $is_first_day 有真有假的情况。