配置网站Google Conversion API 实战演示
最近帮客户架设google conversion api ,期间踩了不少坑做了很多错误的研究,这里写篇文章吧, 希望对大家有所帮助,我后面会录个视频讲得详细点希望对大家有所帮助吧!
首先聊聊什么是conversion api,如果大家做外贸网站/广告 seo搜索那么对 facebook/google 广告不会陌生,之所出现这个conversion api是因为自iOS14政策实施以来,所有应用程序都必须得到用户同意才能追踪数据。随着更多iOS用户选择阻止数据追踪,Facebook Pixel无法有效收集数据用于广告优化。因应这一变化,Facebook更新了其政策:为了协调广告效果与用户隐私之间的关系,从2021年10月1日起,将停止使用Pixel事件,转而采用Conversion API的网络事件。
通俗点讲就是因为法律法规问题不让google 和facebook肆无忌惮的采集和追逐用户的数据了,不够上有政策下有对策conversion api就诞生了, 简单点讲原理就是当pixel 把前端的数据拦截或无法采集的时候用户(站长或网站控制者)可以通过网站采集用户的数据通过这个conversion api 把用户数据采集上传给facebook/google 这样责任就扔给网站用户了。
上面这个图大家可以看到当用户访问网站的时候最开始pixel会采集数据,然后同步给谷歌,当然用户的终端是未知的可以来自android/phone/浏览器无痕模式,或有防火墙adblock类似的软件,这样会降低广告的匹配度, 网站站长可以通过用户在网站上注册或浏览的一些操作行为如,用户注册在网站了会有邮件/电话号码或其他个人信息,站长通过采集这些数据通过conversion api上传给谷歌,这样谷歌就掌握了这些数据可以更精准的追逐用户把广告推送给用户从而提高广告的精准转换!
这里实战演示我就用google conversion api来做了,要利用google conversion api 必须需要用到4个密钥
1.clientID, clientSecret 这里需要去google cloud console (https://console.cloud.google.com/)去project 没有没有就创建一个
接下来需要enable 一下 google ads api 和到credentials 里面去创建一个,需要创建oauth client id,记得scope 一定要加上google ads api ,不然这个密钥无法调用api!
建好后会生成一个clientID 和clientSecret 给你.
2. 有了这个clientID, clientSecret 后可以创建一个refreshtoken 谷歌需要这个这个token接入api,获取refreshtoken的细节这里可以看到
3.Developer token
这里登录google ads系统然后在api center去申请就好了,这里有几个细节需要注意,第一次申请是test account 或basic access权限,在basic access权限下只能发送最高15000请求。 如果你需要上传到数据高于这个峰值你需要申请standard acess, 谷歌api申请一般需要几天到几个星期不等,申请到时候请严格认真的填写申请表,不然有被拒或要求你重新填写的可能!
Sign in to your manager account and navigate to TOOLS & SETTINGS > SETUP > API Center. The API Center option appears only for Google Ads manager accounts.
当以上4个密钥都获取后解析来可以通过程序进行发送请求给api上传你的用户数据了
package com.example.demo;
import com.google.ads.googleads.lib.GoogleAdsClient;
import com.google.ads.googleads.v14.common.UserIdentifier;
import com.google.ads.googleads.v14.enums.ConversionAdjustmentTypeEnum;
import com.google.ads.googleads.v14.enums.UserIdentifierSourceEnum;
import com.google.ads.googleads.v14.services.*;
import com.google.ads.googleads.v14.utils.ResourceNames;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Properties;
@Slf4j
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
Properties properties = new Properties();
// properties.setProperty("api.googleads.clientId", "");
// properties.setProperty("api.googleads.clientSecret", "");
// properties.setProperty("api.googleads.refreshToken", "");
// properties.setProperty("api.googleads.customerId", "");
// properties.setProperty("api.googleads.developerToken", "");
// GoogleAdsClient googleAdsClient = GoogleAdsClient.newBuilder().fromProperties(properties).build();
String conversionActionId = "xxxx";
GoogleAdsClient googleAdsClient = GoogleAdsClient.newBuilder().fromEnvironment().build();
log.info("Google Connection Test : {}", googleAdsClient.getEndpoint());
String orderId = "abc12345";
// String conversionDateTime = SimpleTimestampConverter(event.getEventTime());
Long conversionID = Long.parseLong(conversionActionId);
Long cId = Long.parseLong("5063574237");
ConversionAdjustment.Builder enhancementBuilder =
ConversionAdjustment.newBuilder()
.setConversionAction(ResourceNames.conversionAction(cId, conversionID))
.setAdjustmentType(ConversionAdjustmentTypeEnum.ConversionAdjustmentType.ENHANCEMENT)
// Enhancements MUST use order ID instead of GCLID date/time pair.
.setOrderId(orderId);
MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");
UserIdentifier emailIdentifier =
UserIdentifier.newBuilder()
.setUserIdentifierSource(UserIdentifierSourceEnum.UserIdentifierSource.FIRST_PARTY)
.setHashedPhoneNumber(normalizeAndHash(sha256Digest, "121312321321"))
.setHashedEmail(normalizeAndHashEmailAddress(sha256Digest, "asdsadsada@gmail.com"))
.build();
// Adds the user identifiers to the enhancement adjustment.
enhancementBuilder.addUserIdentifiers(emailIdentifier);
// Creates the conversion upload service client.
try (ConversionAdjustmentUploadServiceClient conversionUploadServiceClient =
googleAdsClient.getLatestVersion().createConversionAdjustmentUploadServiceClient()) {
UploadConversionAdjustmentsResponse response =
conversionUploadServiceClient.uploadConversionAdjustments(
UploadConversionAdjustmentsRequest.newBuilder()
.setCustomerId(String.valueOf(cId))
.addConversionAdjustments(enhancementBuilder)
.setPartialFailure(true)
.build());
if (response.hasPartialFailureError()) {
log.info("Google CAPI : Partial error encountered: {} ", response.getPartialFailureError().getMessage());
} else {
ConversionAdjustmentResult result = response.getResults(0);
log.info("Google CAPI : Uploaded conversion adjustment of {} for order ID {}", result.getConversionAction(), result.getOrderId());
}
}
}
private static String normalizeAndHash(MessageDigest digest, String s)
throws UnsupportedEncodingException {
String normalized = s.trim().toLowerCase();
byte[] hash = digest.digest(normalized.getBytes("UTF-8"));
StringBuilder result = new StringBuilder();
for (byte b : hash) {
result.append(String.format("%02x", b));
}
return result.toString();
}
private static String normalizeAndHashEmailAddress(MessageDigest digest, String emailAddress)
throws UnsupportedEncodingException {
String normalizedEmail = emailAddress.toLowerCase();
String[] emailParts = normalizedEmail.split("@");
if (emailParts.length > 1 && emailParts[1].matches("^(gmail|googlemail)\\.com\\s*")) {
emailParts[0] = emailParts[0].replaceAll("\\.", "");
normalizedEmail = String.format("%s@%s", emailParts[0], emailParts[1]);
}
return normalizeAndHash(digest, normalizedEmail);
}
public static String SimpleTimestampConverter(long timestamp) {
return DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ssxxx")
.withZone(ZoneOffset.UTC)
.format(Instant.ofEpochSecond(timestamp));
}
}