全渠道「API回传」技术开发说明
published on: 2022-05-10 15:01:49
一、背景
客户跨媒体投放行为较为普遍,媒体间形成的转化信息孤岛不利于广告主充分利用数据优化投放,尤其是对于转化事件相对稀疏的行业和客户,数据分散导致模型学习不充分,造成成本高、跑量少,目标人群触达效率低,而在符合法律规定的前提下,通过把跨渠道转化数据回传给巨量引擎(不计入巨量引擎转化,只帮助模型学习),可以帮助模型充分的学习已转化人群特征,达到提高跑量,优化成本的作用。
二、什么是助攻?
TIPS:归因和助攻的区别
-
归因:在巨量引擎产生过广告的触达,且最终转化渠道判定为巨量引擎,记巨量引擎转化(计入广告后台转化数),同时进入模型学习
-
助攻:在巨量引擎产生过广告的触达(展示、播放、点击),但是最终转化渠道归因给其他媒体。这类事件数据只进模型,帮助模型学习,提升模型精准度,不记巨量引擎转化(客户无需付费)
三、数据对接回传实现方案
数据回传前,请填写全渠道助攻API回传问卷: 问卷
广告主投放的转化目标,跟回传的转化事件必须保持一致 。如:投放目标是付费,但回传的是激活,助攻模型是无法正常生效的。
方案一(建议采用)适用于线索类和应用下载(非调起) |
方案二(可选)适用于线索类和应用下载类 |
|
简述 |
客户进行归因判定,并把非巨量引擎转化(自然转化及其他媒体转化)回传给巨量引擎,巨量引擎进行助攻判定 |
客户进行归因及助攻判定,并将判定结果回传给巨量引擎相应接口 |
特点 |
* 客户需要完成全部归因部分的开发,不需要开发助攻判定部分,基本无需多余技术成本 * 对客户来说数据存储量较方案二小 |
* 客户开发成本较高(所有的开发成本都在客户侧)) * 巨量引擎侧全部的展示/点击/播放数据集中在客户侧,对客户侧的存储空间要求较高 |
接入流程 |
1. 广告主实时回传助攻/非巨量引擎转化数据 2. 通知巨量引擎运营,巨量引擎侧确认样本上报传输无误,广告主确认后开启助攻模型 3. 进行一周的流量测试,广告主只需制定测试账户,巨量引擎方反馈测试效果 4. 效果正向后应用至广告主整体投放模型 |
|
归因及数据流转过程 |
|
助攻部分,如果客户区分click和show,可增加match_type回传,便于模型对人群特征的学习 |
接口方案 |
* 接口一:巨量引擎正常下发展示、点击、播放 * 接口二:客户回传归因给巨量引擎的转化 * Valuable接口:客户回传其他渠道全部转化事件,由巨量引擎判定是否属于可应用的助攻事件 |
* 接口一:巨量引擎正常下发展示、点击、播放 * 接口二:客户回传归因给巨量引擎的转化 * Assist接口:客户回传其巨量引擎助攻的转化 |
接口地址 |
接口二:https://ad.oceanengine.com/track/activate/ Valuable接口:https://analytics.oceanengine.com/api/v2/valuable |
接口二:https://ad.oceanengine.com/track/activate/ Assist接口:https://analytics.oceanengine.com/api/v2/assist |
回传方式技术对接介绍 |
详见附件 方案一接入流程 |
详见附件 方案二接入流程 |
回传字段简述 |
见方案一 参数列表 如果是应用场景,必须传包名 |
Assist接口接入参数列表 如果是应用场景,必须传包名 |
四、客户对接流程
附件:方案一接入流程
-
回传方案:
客户自行进行归因判断回传至接口二,其他渠道全部转化事件回传至valuable接口,由巨量引擎判定是否属于可应用的助攻事件,将巨量助攻过的数据用于模型优化,提高转化率,降低广告主成本
-
技术对接方式介绍
接口地址 :https://analytics.oceanengine.com/api/v2/valuable
请求方式 :POST
Content-Type :application/json
参数列表:
字段 |
必要 |
类型 |
举例 |
说明 |
event_type |
是 |
string |
active |
事件类型 |
event_weight |
否 |
number |
0.561 |
事件权重,广告主自定义该事件的价值权重用于模型优化 |
biz_channel |
是 |
number |
0 |
业务类型,默认值:0,应用下载:0;线索收集:5;如果不传该值则当做应用下载类型,其他支持业务类型待补充 |
context |
是 |
object |
广告上下文信息 |
|
context.ad |
否 |
object |
广告信息 |
|
context.ad.ad_id |
否 |
number |
16521212134 |
广告计划id |
context.ad.campaign_id |
否 |
number |
123455666 |
广告组id |
context.ad.advertiser_id |
否 |
number |
1234567890 |
广告主id |
context.ad.customer_id |
否 |
number |
123123123123 |
客户id |
context.device |
否 |
object |
设备信息 |
|
context.device.platform |
否 |
string |
android |
设备平台,android/ios |
context.device.imei |
否 |
string |
0c2bd03c39f19845bf54ea0abafae70e |
安卓系统 imei的 md5 摘要,32位 |
context.device.idfa |
否 |
string |
FCD369C3-F622-43B8-AFDE-12012349F35B |
iOS系统idfa的原值 |
context.device.idfa_md5 |
||||
context.device.idfv |
否 |
string |
FCD369C3-F622-43B8-AFDE-12012349F35B |
iOS系统idfv的原值 |
context.device.gaid |
否 |
string |
FCD369C3-F622-43B8-AFDE-12012349F35B |
Android Google 广告id |
context.device.oaid |
否 |
string |
b305ee2fefdd1234 |
Android系统的 oaid 原值 |
context.device.oaid_md5 |
否 |
string |
5f1c6587f0d6c35fc9e7fb0d4412b80f |
Android系统oaid 的md5摘要,32位 |
context.device.android_id |
否 |
string |
9774d56d682e1234 |
Andoid 系统唯一标识 |
context.device.android_id_md5 |
否 |
string |
a5dc9f6cb53ec2755af66ec7a7a6a51d |
Andoid 系统唯一标识的md5摘要,32位 |
context.device.phone_num |
否 |
string |
62b2d12650ccf2ef170bdf8d8420318356693dbf9b382894e3f3c241c36f106a |
手机号 SHA256加密,54位 |
context.device.ip |
否 |
string |
8.8.8.8 |
事件发生的ip |
context.device.user_agent |
否 |
string |
Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 |
事件发生的user_agent |
context.app |
否 |
object |
应用信息 |
|
context.app.package_name |
否 |
string |
com.oceanengine.app |
应用包名 |
properties |
否 |
object |
{} |
自定义回传属性信息,支持字段待补充 |
timestamp |
是 |
number |
1604299664 |
事件发生的时间戳,自1970/01/01(UTC)以来的秒数 |
注:
-
设备ID(idfa/gaid/oaid/imei/phone_num)中,至少得传一个
-
广告信息(ad_id/campaign_id/advertiser_id/customer_id)中,至少得传一个,否则不能正常归因
完整请求示例:
curl -X POST \\
https://analytics.oceanengine.com/api/v2/valuable \\
\-H 'content-type: application/json' \\
\-d '{
"event\_type": "form",
"event\_weight": 0.561,
"biz\_channel": 5,
"context":{
"device":{
"platform": "ios",
"idfa": "FCD369C3-F622-43B8-AFDE-12012349F35B"
},
"ad": {
"ad\_id": 16521212134
}
},
"timestamp": 1604299664
}'
成功请求assist接口后,返回的HTTP状态码皆为200,如果有错误则通过错误码表示。
成功返回示例: **{"code": 0, "message": "成功"}**
状态码说明:
code |
message |
说明 |
0 |
成功 |
成功 |
10 |
服务暂时不可用 |
服务暂时不可用,可稍后再试 |
100 |
无效的请求,请求数据解析失败 |
上报请求消息体不能解析,请校验一下回传的字段和数据完整性 |
101 |
鉴权认证失败 |
鉴权失败,回传的签名字段不正确 |
102 |
参数:event_type无效 |
event_type为空,或者不合法 |
104 |
不支持的biz_channel |
暂时不支持的业务场景,应用下载默认为0 |
105 |
参数:context.app.package_name不能为空 |
应用包名不能为空,必传字段 |
106 |
device信息不能全为空(idfa,gaid,imei,oaid,android_id至少得填一项) |
context.device中的设备id(idfa/imei/oaid/gaid)至少需要传一个,否则不能归因 |
117 |
ad_id, campaign_id, advertiser_id, customer_id 不能全部为空 |
广告信息不能全部为空 |
118 |
imei/idfa(md5)/oaid(md5)/android_id(md5)/phone_num/ip&user_agent 不能全部为空 |
线索场景对应的设备号不能全为空 |
代码示例
以应用下载场景为例
Go示例
func main() {
url := "https://analytics.oceanengine.com/api/v2/valuable"
data := `{
"event_type": "active",
"event_weight": 0.561,
"biz_channel": 0,
"context":{
"device":{
"platform": "ios",
"idfa": "FCD369C3-F622-43B8-AFDE-12012349F35B"
},
"app": {
"package_name": "com.oceanengine.app"
}
},
"timestamp": 1604299664
}`
payload := bytes.NewReader([]byte(data))
req, _ := http.NewRequest(http.MethodPost, url, payload)
req.Header.Add("content-type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
// handle error
}
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
}
Python 示例
import requests
url = "https://analytics.oceanengine.com/api/v2/valuable"
payload = {
"event_type": "active",
"event_weight": 0.561,
"biz_channel": 0,
"context":{
"device":{
"platform": "ios",
"idfa": "FCD369C3-F622-43B8-AFDE-12012349F35B"
},
"app": {
"package_name": "com.oceanengine.app"
}
},
"timestamp": 1604299664
}
headers = {
'content-type': "application/json",
}
response = requests.request("POST", url, data=json.dumps(payload), headers=headers)
print(response.text)
Nodejs 示例
const request = require("request");
let options = {
method: 'POST',
url: "https://analytics.oceanengine.com/api/v2/valuable",
headers: { 'content-type': 'application/json' },
body: {
"event_type": "active",
"event_weight": 0.561,
"biz_channel": 0,
"context":{
"device":{
"platform": "ios",
"idfa": "FCD369C3-F622-43B8-AFDE-12012349F35B"
},
"app": {
"package_name": "com.oceanengine.app"
}
},
"timestamp": 1604299664
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
PHP 示例
<?php
$request = new HttpRequest();
$request->setUrl('https://analytics.oceanengine.com/api/v2/valuable');
$request->setMethod(HTTP_METH_POST);
$request->setHeaders(array(
'content-type' => 'application/json'
));
$request->setBody('{
"event_type": "active",
"event_weight": 0.561,
"biz_channel": 0,
"context":{
"device":{
"platform": "ios",
"idfa": "FCD369C3-F622-43B8-AFDE-12012349F35B"
},
"app": {
"package_name": "com.oceanengine.app"
}
},
"timestamp": 1604299664
}');
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
?>
JAVA示例
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
JSONObject json = new JSONObject();
json.put("event_type", "active")
.put("event_weight", 0.561)
.put("biz_channel", 0)
.put("context", new JSONObject()
.put("device", new JSONObject()
.put("platform", "ios")
.put("idfa", "FCD369C3-ABCD-1234-EFGH-1234567890B")
)
.put("app", new JSONObject()
.put("package_name": "com.oceanengine.app")
)
)
.put("timestamp", 1604299664)
RequestBody body = RequestBody.create(mediaType, String.valueOf(json));
Request request = new Request.Builder()
.url("https://analytics.oceanengine.com/api/v2/valuable")
.post(body)
.addHeader("content-type", "application/json")
.build();
Response response = client.newCall(request).execute();
常用event_type
注意回传的取值是英文事件名称
event_type(需回传) | 事件名称(中文) | 定义 |
active | 激活 | 用户下载安装完毕应用之后,在联网环境下打开应用 |
next_day_open | 次留 | 用户激活后次日联网环境下打开应用 |
active_register | 注册 | 完成应用下载并且在联网环境打开应用后,完成个人账号/游戏角色注册信息提交 |
active_pay | 付费 | 完成应用下载并且在联网环境打开应用后,应用内完成一笔付款 |
form | 表单 | 完成表单填写并提交 |
consult | 在线咨询 | 用户点击在线咨询按钮 |
consult_effective | 有效咨询 | 用户在消息咨询页面内完成至少一句消息对话 |
game_addiction | 关键行为 | 用户在应用内发生的关键行为/行为集合,若是关键行为集合一般是有关联的行为路径。(举例:某直播类客户以注册+发送弹幕作为关键行为转化目标,电商用注册+收藏商品+加入购物车+下单等) |
in_app_order | app内下单 | 在应用内完成一次订单提交,例如:点击“立即下单” |
in_app_uv | app内访问 | 用户成功打开访问应用 |
in_app_cart | app内添加购物车 | 在应用内成功将商品加入购物车,例如:点击“加入购物车” |
in_app_pay | app内付费 | 在应用内完成一次订单付费。目前主要是电商行业使用,常规建议使用付费事件 |
authorization | 授权 | 完成授权电商/支付/社交等账号登陆 |
in_app_detail_uv | app内详情页到站uv | 成功访问应用内指定页面的UV数 |
customer_effective | 有效获客 | 用户完成了一次有价值的动作,如预约到店,完成授权等,支持广告主根据业务场景自定义 |
方案二接入流程
-
回传方案 :
客户需自己进行归因及助攻判定,并将判定结果回传给巨量引擎,巨量引擎转化回传到接口二,巨量引擎助攻拼接相应字段后回传到assist接口
-
设置监测链接:
- 监测链接设置:可参考开发文档
- 填写展示、点击监测链接
- 填写入口
- 新建计划—创意—展示监测链接
- 资产—转化跟踪—新建转化—展示监测链接
- 填写入口
-
技术对接方式介绍
-
接口地址 :https://analytics.oceanengine.com/api/v2/assist
-
请求方式 :
POST
-
Content-Type :
application/json
-
参数列表 :
字段 |
必要 |
类型 |
举例 |
说明 |
event_type |
是 |
string |
active |
事件类型 |
event_weight |
否 |
number |
0.561 |
事件权重,广告主自定义该事件的价值权重用于模型优化 |
context |
是 |
object |
广告上下文信息 |
|
context.ad |
是 |
object |
广告信息 |
|
context.ad.callback |
是 |
string |
EJiw267wvfQCGKf2g74ZIPD89-vIATAMOAFCIjIwMTkxMTI3MTQxMTEzMDEwMDI2MDc3MjE1MTUwNTczNTBIAQ== |
巨量引擎下发的广告事件信息中的callback(clickid)部分,广告主需将该字段内容原样回传 |
context.ad.match_type |
否 |
number |
0 |
归因方式,0:点击 1:展示 2:有效播放归因 |
context.device |
否 |
object |
设备信息 |
|
context.device.platform |
否 |
string |
android |
设备平台,android/ios |
context.device.imei |
否 |
string |
0c2bd03c39f19845bf54ea0abafae70e |
安卓系统 imei 的md5摘要 |
context.device.idfa |
否 |
string |
FCD369C3-ABCD-1234-EFGH-1234567890B |
iOS系统idfa的原值 |
context.device.oaid |
否 |
string |
b305ee2abcdefgh2 |
Android系统的 oaid 原值 |
properties |
否 |
object |
{} |
自定义回传属性信息,支持字段待补充 |
timestamp |
否 |
number |
1604299664 |
事件发生的时间戳,自1970/01/01(UTC)以来的秒数 |
完整请求示例
curl -X POST \\
https://analytics.oceanengine.com/api/v2/assist \\
\-H 'content-type: application/json' \\
\-d '{
"event\_type": "active",
"event\_weight": 0.561,
"context":{
"ad": {
"callback": "EJiw267wvfQCGKf2g74ZIPD89-vIATAMOAFCIjIwMTkxMTI3MTQxMTEzMDEwMDI2MDc3MjE1MTUwNTczNTBIAQ==",
"match\_type": 0
},
"device":{
"platform": "ios",
"idfa": "FCD369C3-ABCD-1234-EFGH-1234567890B"
}
},
"timestamp": 1604299664
}'
返回值:
成功请求assist接口后,返回的HTTP状态码皆为200,如果有错误则通过错误码表示。
成功返回示例: {"code": 0, "message": "成功"}
状态码说明 :
code |
message |
说明 |
0 |
成功 |
成功 |
10 |
服务暂时不可用 |
服务暂时不可用,可稍后再试 |
100 |
无效的请求,请求数据解析失败 |
上报请求消息体不能解析,请校验一下回传的字段和数据完整性 |
101 |
鉴权认证失败 |
鉴权失败,回传的签名字段不正确 |
102 |
参数:event_type无效 |
event_type为空,或者不合法 |
103 |
参数:callback无效 |
callback为空,或者不能解析 |
示例:
Go示例
func main() {
url := "https://analytics.oceanengine.com/api/v2/assist"
data := \`{
"event\_type": "active",
"event\_weight": 0.561,
"context": {
"ad": {
"callback": "EJiw267wvfQCGKf2g74ZIPD89-vIATAMOAFCIjIwMTkxMTI3MTQxMTEzMDEwMDI2MDc3MjE1MTUwNTczNTBIAQ==",
"match\_type": 0
},
"device": {
"platform": "ios",
"idfa": "FCD369C3-ABCD-1234-EFGH-1234567890B"
}
},
"timestamp": 1604299664
}\`
payload := bytes.NewReader(\[\]byte(data))
req, \_ := http.NewRequest(http.MethodPost, url, payload)
req.Header.Add("content-type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
// handle error
}
defer res.Body.Close()
body, \_ := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
}
Python示例
import requests
url = "https://analytics.oceanengine.com/api/v2/assist"
payload = {
"event\_type": "active",
"event\_weight": 0.561,
"context": {
"ad": {
"callback": "EJiw267wvfQCGKf2g74ZIPD89-vIATAMOAFCIjIwMTkxMTI3MTQxMTEzMDEwMDI2MDc3MjE1MTUwNTczNTBIAQ==",
"match\_type": 0
},
"device": {
"platform": "ios",
"idfa": "FCD369C3-ABCD-1234-EFGH-1234567890B"
}
},
"timestamp": 1604299664
}
headers = {
'content-type': "application/json",
}
response = requests.request("POST", url, data=json.dumps(payload), headers=headers)
print(response.text)
Nodejs示例
const request = require("request");
let options = {
method: 'POST',
url: "https://analytics.oceanengine.com/api/v2/assist",
headers: { 'content-type': 'application/json' },
body: {
"event\_type": "active",
"event\_weight": 0.561,
"context": {
"ad": {
"callback": "EJiw267wvfQCGKf2g74ZIPD89-vIATAMOAFCIjIwMTkxMTI3MTQxMTEzMDEwMDI2MDc3MjE1MTUwNTczNTBIAQ==",
"match\_type": 0
},
"device": {
"platform": "ios",
"idfa": "FCD369C3-ABCD-1234-EFGH-1234567890B"
}
},
"timestamp": 1604299664
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
PHP示例
<?php
$request = new HttpRequest();
$request->setUrl('https://analytics.oceanengine.com/api/v2/assist');
$request->setMethod(HTTP\_METH\_POST);
$request->setHeaders(array(
'content-type' => 'application/json'
));
$request->setBody('{
"event\_type": "active",
"event\_weight": 0.561,
"context": {
"ad": {
"callback": "EJiw267wvfQCGKf2g74ZIPD89-vIATAMOAFCIjIwMTkxMTI3MTQxMTEzMDEwMDI2MDc3MjE1MTUwNTczNTBIAQ==",
"match\_type": 0
},
"device": {
"platform": "ios",
"idfa": "FCD369C3-ABCD-1234-EFGH-1234567890B"
}
},
"timestamp": 1604299664
}');
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
?>
JAVA示例
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
JSONObject json = new JSONObject();
json.put("event\_type", "active")
.put("event\_weight", 0.561)
.put("context", new JSONObject()
.put("ad", new JSONObject()
.put("callback", "EJiw267wvfQCGKf2g74ZIPD89-vIATAMOAFCIjIwMTkxMTI3MTQxMTEzMDEwMDI2MDc3MjE1MTUwNTczNTBIAQ==")
.put("match\_type", 0)
)
.put("device", new JSONObject()
.put("platform", "ios")
.put("idfa", "FCD369C3-ABCD-1234-EFGH-1234567890B")
)
)
.put("timestamp", 1604299664)
RequestBody body = RequestBody.create(mediaType, String.valueOf(json));
Request request = new Request.Builder()
.url("https://analytics.oceanengine.com/api/v2/assist")
.post(body)
.addHeader("content-type", "application/json")
.build();
Response response = client.newCall(request).execute();
Q&A
Q: 为什么巨量引擎下发的数据里面没有callback字段信息
A: 有些情况下,广告主收到的是clickid字段,含义和callback是一样的,即把收到的clickid值当做callback进行回传即可,注意不要进行url encode
常用event_type
注意回传的取值是英文事件名称
event_type(需回传) | 事件名称(中文) | 定义 |
active | 激活 | 用户下载安装完毕应用之后,在联网环境下打开应用 |
next_day_open | 次留 | 用户激活后次日联网环境下打开应用 |
active_register | 注册 | 完成应用下载并且在联网环境打开应用后,完成个人账号/游戏角色注册信息提交 |
active_pay | 付费 | 完成应用下载并且在联网环境打开应用后,应用内完成一笔付款 |
form | 表单 | 完成表单填写并提交 |
consult | 在线咨询 | 用户点击在线咨询按钮 |
consult_effective | 有效咨询 | 用户在消息咨询页面内完成至少一句消息对话 |
game_addiction | 关键行为 | 用户在应用内发生的关键行为/行为集合,若是关键行为集合一般是有关联的行为路径。(举例:某直播类客户以注册+发送弹幕作为关键行为转化目标,电商用注册+收藏商品+加入购物车+下单等) |
in_app_order | app内下单 | 在应用内完成一次订单提交,例如:点击“立即下单” |
in_app_uv | app内访问 | 用户成功打开访问应用 |
in_app_cart | app内添加购物车 | 在应用内成功将商品加入购物车,例如:点击“加入购物车” |
in_app_pay | app内付费 | 在应用内完成一次订单付费。目前主要是电商行业使用,常规建议使用付费事件 |
authorization | 授权 | 完成授权电商/支付/社交等账号登陆 |
loan_credit | 互联网金融——授信 | |
in_app_detail_uv | app内详情页到站uv | 成功访问应用内指定页面的UV数 |
customer_effective | 有效获客 | 用户完成了一次有价值的动作,如预约到店,完成授权等,支持广告主根据业务场景自定义 |