Google ADS API 接口调研

简介

Google Ads API 用于管理大型或复杂的 Google Ads 帐号和广告系列。您可以构建软件,从客户级别到关键字级别管理帐号。一些典型用例包括:

  • 自动账号管理
  • 自定义报告
  • 基于产品目录的广告管理
  • 管理智能出价策略

要发出 Google Ads API 调用,您应具备以下详细信息。本教程的其余部分将介绍如何获取每项内容。

Google Ads 经理帐号:您需要拥有 Google Ads 经理帐号才能申请 Google Ads API

开发者令牌:此令牌可让您的应用连接到 Google Ads API。每个开发者令牌都分配有一个 API 访问权限级别,该级别控制您每天可以发出 API 调用的次数以及可以进行调用的环境测试及普通权限每天有访问限制,标准权限无调用次数限制

Google API 控制台项目:项目用于为您的应用生成 OAuth 2.0 客户端 ID 和密钥。然后,ID 和密钥可用于生成对 Google Ads 账号的 API 调用所需的 OAuth 2.0 凭据。该项目还会使该 API 能够接听电话。

Google Ads 客户帐号:您要向其发出 API 调用的帐号。您需要拥有必要的权限才能对此账号执行操作,例如获取报告或更改广告系列。

您还需要要向其发出 API 调用的帐号的 10 位数帐号。它在 Google Ads 网页界面中显示为 123-456-7890 格式。此帐号会作为参数传递给 Google Ads API 调用,不带连字符:1234567890。

支持工具和客户端库:这套工具可帮助您更快地与 API 集成

注:Google Ads API 目前国内访问需要开通国外VPN(fanqiang)

1.选择或创建一个 Google API 控制台项目

注:如果您已有 Google API 控制台项目并希望使用它创建凭据,则可以跳至创建客户端 ID 和客户端密钥。

  1. 前往 Google API 控制台
  2. 点击创建项目
  3. 输入名称或接受生成的建议
  4. 确认或修改其余所有字段
  5. 点击创建

如果已启用结算功能,请为新项目选择结算帐号。Google Ads API 可免费使用,但 Cloud 项目总数有配额限制。

2.启动API和服务

点击“API和服务”—》再击“启用API和服务”—》 搜索“google ads api” —》最后点击“启用”

3.接口OAuth2.0 凭据授权

点击“凭据”-》 再点击“创建凭据”-》再点击“OAuth客户端ID”

创建后生成秘钥信息

编辑查看信息,可更换回调地址、添加多个回调地址

下载凭证 ,获取刷新令牌时使用

4.生成OAuth2.0刷新令牌

Google OAuth2.0刷新令牌 Web授权方式仅供参考

4.1 Web授权步骤一:获取code

向Google 的授权服务端发送请求https://accounts.google.com/o/oauth2/v2/auth

字段

类型

描述

client_id

String

应用ID

client_id  从凭证授权获取

redirect_uri

String

回调地址

Google会验证地址是否一致

response_type

String

默认值 code

scope

String

访问API授权列表,多个空格(%20)分隔

Google API 授权链接

Google for Developers - 从 AI 和云到移动和 Web

/identity/protocols

/oauth2/scopes?hl=zh-cn

access_type

String

建议 offline

,默认online

您的应用需要在用户不在浏览器时刷新访问令牌,请将值设置为 offline,获取token时返回refreshToken

include_granted

_scopes

Boolean

建议 true

允许应用使用增量授权在上下文中请求访问其他范围

prompt

String

建议 consent

提示用户同意并返回refreshToken

参考源码实现:google-auth-library-oauth2-http-1.23.0.jar

 com.google.auth.oauth2.UserAuthorizer#getAuthorizationUrl()方法

public URL getAuthorizationUrl(
    String userId, String state, URI baseUri, Map<String, String> additionalParameters) {
  URI resolvedCallbackUri = getCallbackUri(baseUri);
  String scopesString = Joiner.on(' ').join(scopes);

  GenericUrl url = new GenericUrl(userAuthUri);
  url.put("response_type", "code");
  url.put("client_id", clientId.getClientId());
  url.put("redirect_uri", resolvedCallbackUri);
  url.put("scope", scopesString);
  if (state != null) {
    url.put("state", state);
  }
  url.put("access_type", "offline");
  url.put("approval_prompt", "force");
  if (userId != null) {
    url.put("login_hint", userId);
  }
  url.put("include_granted_scopes", true);

//改动点
  url.put("prompt","consent");
  if (additionalParameters != null) {
    for (Map.Entry<String, String> entry : additionalParameters.entrySet()) {
      url.put(entry.getKey(), entry.getValue());
    }
  }

  if (pkce != null) {
    url.put("code_challenge", pkce.getCodeChallenge());
    url.put("code_challenge_method", pkce.getCodeChallengeMethod());
  }
  return url.toURL();
}

Request: Get

https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/adwords%20https://www.googleapis.com/auth/userinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&prompt=consent&redirect_uri=https://xxx.xxx.com/returnUrl&client_id=xxxxxx.apps.googleusercontent.com

Google CallBack Url :

https://xxx.xxx.com/returnUrl?code=xxxxxxxx&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/adwords&authuser=1&prompt=consent

从回调地址中获取 code 进行下一步操作

4.2 Web授权步骤二:获取refreshToken

Request:https://oauth2.googleapis.com/token

参考源码实现:google-auth-library-oauth2-http-1.23.0.jar

com.google.auth.oauth2.UserAuthorizer#getCredentialsFromCode() 方法

public UserCredentials getCredentialsFromCode(
    String code, URI baseUri, Map<String, String> additionalParameters) throws IOException {
  Preconditions.checkNotNull(code);
  URI resolvedCallbackUri = getCallbackUri(baseUri);

  GenericData tokenData = new GenericData();
  tokenData.put("code", code);
  tokenData.put("client_id", clientId.getClientId());
  tokenData.put("client_secret", clientId.getClientSecret());
  tokenData.put("redirect_uri", resolvedCallbackUri);
  tokenData.put("grant_type", "authorization_code");

  if (additionalParameters != null) {
    for (Map.Entry<String, String> entry : additionalParameters.entrySet()) {
      tokenData.put(entry.getKey(), entry.getValue());
    }
  }

  if (pkce != null) {
    tokenData.put("code_verifier", pkce.getCodeVerifier());
  }

  UrlEncodedContent tokenContent = new UrlEncodedContent(tokenData);
  HttpRequestFactory requestFactory = transportFactory.create().createRequestFactory();
  HttpRequest tokenRequest =
      requestFactory.buildPostRequest(new GenericUrl(tokenServerUri), tokenContent);
  tokenRequest.setParser(new JsonObjectParser(OAuth2Utils.JSON_FACTORY));

  HttpResponse tokenResponse = tokenRequest.execute();

  GenericJson parsedTokens = tokenResponse.parseAs(GenericJson.class);
  String accessTokenValue =
      OAuth2Utils.validateString(parsedTokens, "access_token", FETCH_TOKEN_ERROR);
  int expiresInSecs = OAuth2Utils.validateInt32(parsedTokens, "expires_in", FETCH_TOKEN_ERROR);
  Date expirationTime = new Date(new Date().getTime() + expiresInSecs * 1000);
  String scopes =
      OAuth2Utils.validateOptionalString(
          parsedTokens, OAuth2Utils.TOKEN_RESPONSE_SCOPE, FETCH_TOKEN_ERROR);
  AccessToken accessToken =
      AccessToken.newBuilder()
          .setExpirationTime(expirationTime)
          .setTokenValue(accessTokenValue)
          .setScopes(scopes)
          .build();
  String refreshToken =
      OAuth2Utils.validateOptionalString(parsedTokens, "refresh_token", FETCH_TOKEN_ERROR);

  return UserCredentials.newBuilder()
      .setClientId(clientId.getClientId())
      .setClientSecret(clientId.getClientSecret())
      .setRefreshToken(refreshToken)
      .setAccessToken(accessToken)
      .setHttpTransportFactory(transportFactory)
      .setTokenServerUri(tokenServerUri)
      .build();
}

client_id ,client_secret 从凭证授权获取

POST /token HTTP/1.1

Host: oauth2.googleapis.com

Content-Type: application/x-www-form-urlencoded

code=xxxxx&

client_id=xxxxx&

client_secret=xxxxx&

redirect_uri=https://xxx.xxx.com/returnUrl&

grant_type=authorization_code

Response:

{
  "access_token": "xxxxxxx",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/adwords%20https://www.googleapis.com/auth/userinfo.email",
  "refresh_token": "xxxxxxx"
}

返回数据保存refresh_token ,接口返回的 access_token 只有1小时有效期,注:Google API JAR 只需要 refreshToken ,API会自动获取access_token 请求API接口

4.3 Web授权步骤三:获取accessToken

Google API JAR 客户端已实现,如果自实现http请求可参考

Request:https://oauth2.googleapis.com/token

参考源码实现:google-auth-library-oauth2-http-1.23.0.jar

com.google.auth.oauth2.UserCredentials#refreshAccessToken

com.google.auth.oauth2.UserCredentials#doRefreshAccessToken

public AccessToken refreshAccessToken() throws IOException {
  GenericData responseData = doRefreshAccessToken();
  String accessToken =
      OAuth2Utils.validateString(responseData, "access_token", PARSE_ERROR_PREFIX);
  int expiresInSeconds =
      OAuth2Utils.validateInt32(responseData, "expires_in", PARSE_ERROR_PREFIX);
  long expiresAtMilliseconds = clock.currentTimeMillis() + expiresInSeconds * 1000;
  String scopes =
      OAuth2Utils.validateOptionalString(
          responseData, OAuth2Utils.TOKEN_RESPONSE_SCOPE, PARSE_ERROR_PREFIX);
  return AccessToken.newBuilder()
      .setExpirationTime(new Date(expiresAtMilliseconds))
      .setTokenValue(accessToken)
      .setScopes(scopes)
      .build();
}

private GenericData doRefreshAccessToken() throws IOException {
  if (refreshToken == null) {
    throw new IllegalStateException(
        "UserCredentials instance cannot refresh because there is no refresh token.");
  }
  GenericData tokenRequest = new GenericData();
  tokenRequest.set("client_id", clientId);
  tokenRequest.set("client_secret", clientSecret);
  tokenRequest.set("refresh_token", refreshToken);
  tokenRequest.set("grant_type", GRANT_TYPE);
  UrlEncodedContent content = new UrlEncodedContent(tokenRequest);

  HttpRequestFactory requestFactory = transportFactory.create().createRequestFactory();
  HttpRequest request = requestFactory.buildPostRequest(new GenericUrl(tokenServerUri), content);
  request.setParser(new JsonObjectParser(JSON_FACTORY));
  HttpResponse response;

  try {
    response = request.execute();
  } catch (HttpResponseException re) {
    throw GoogleAuthException.createWithTokenEndpointResponseException(re);
  } catch (IOException e) {
    throw GoogleAuthException.createWithTokenEndpointIOException(e);
  }

  return response.parseAs(GenericData.class);
}

5.API调用

POM依赖:

<dependency>
  <groupId>com.google.api-ads</groupId>
  <artifactId>google-ads</artifactId>
  <version>31.0.0</version>
</dependency>

配置文件 ~/ads.properties

api.googleads.clientId=xxx //云平台应用授权凭证id

api.googleads.clientSecret=xxx //云平台应用授权凭证secret

api.googleads.refreshToken=xxx //OAuth21授权token

api.googleads.developerToken=xxx //开发者令牌值

api.googleads.loginCustomerId=xxx //API 调用的经理的Google Ads客户 ID

创建一个GoogleAdsClient 客户端

GoogleAdsClient googleAdsClient = null;
try {
  googleAdsClient = GoogleAdsClient.newBuilder().fromPropertiesFile().build();
} catch (FileNotFoundException fnfe) {
  System.err.printf(
      "Failed to load GoogleAdsClient configuration from file. Exception: %s%n",
      fnfe);
  System.exit(1);
} catch (IOException ioe) {
  System.err.printf("Failed to create GoogleAdsClient. Exception: %s%n", ioe);
  System.exit(1);
}

创建简单的报告: GoogleAdsService.SearchStream

  private void runExample(GoogleAdsClient googleAdsClient, long customerId) {
  try (GoogleAdsServiceClient googleAdsServiceClient =
      googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
    String query = "SELECT campaign.id, campaign.name FROM campaign ORDER BY campaign.id";
    // Constructs the SearchGoogleAdsStreamRequest.
    SearchGoogleAdsStreamRequest request =
        SearchGoogleAdsStreamRequest.newBuilder()
            .setCustomerId(Long.toString(customerId))
            .setQuery(query)
            .build();

    // Creates and issues a search Google Ads stream request that will retrieve all campaigns.
    ServerStream<SearchGoogleAdsStreamResponse> stream =
        googleAdsServiceClient.searchStreamCallable().call(request);

    // Iterates through and prints all of the results in the stream response.
    for (SearchGoogleAdsStreamResponse response : stream) {
      for (GoogleAdsRow googleAdsRow : response.getResultsList()) {
        System.out.printf(
            "Campaign with ID %d and name '%s' was found.%n",
            googleAdsRow.getCampaign().getId(), googleAdsRow.getCampaign().getName());
      }
    }
  }
}

名词解释

表字段:

account_budget.adjusted_spending_limit_micros:调账后支出限额

account_budget.amount_served_micros:支出金额

account_budget.total_adjustments_micros:调整追加金额

account_budget.proposed_start_date_time:账户预算开始时间

account_budget.approved_start_date_time:账户预算批准开始时间

account_budget.approved_end_date_time:账户预算批准结束时间

customer.status:广告活动系列状态

customer.id:客户ID

customer.currency_code:币种

customer.status:客户状态

customer.resource_name:客户资源名称

customer_client.id: 客户的客户ID

customer_client.currency_code:客户的客户币种

customer_client.level:客户的客户等级

customer_client.manager:客户的客户是否是经理账号

customer_client.resource_name:客户的客户资源名称

customer_client.test_account:客户的客户是否是测试账户

customer_client.descriptive_name:客户的客户描述名称

Customer/Client status = CANCELED,CLOSED,ENABLED,SUSPENDED,UNKNOWN

campaign.id: 广告活动系列ID

campaign.name: 广告活动系列名称

ad_group_ad.ad.call_ad.country_code: 广告国家编码

维度:

segments.date : 制定统计数据日期范围

指标:

metrics.cost_micros:花费成本

metrics.average_cpc : 所有点击的总成本除以收到的点击总数

metrics.average_cost: 金额是你的广告总成本除以点击总数

metrics.average_cpm: 每千次展示的平均成本

metrics.average_cpv:所有广告观看的总成本除以观看次数定义的

metrics.average_cpe: 所有广告活动的总成本除以广告活动的总数

metrics.clicks: 点击次数

metrics.interactions : 展示量

metrics.ctr : 点击率 点击次数除以展示次数 

metrics.absolute_top_impression_percentage:绝对首页展示百分比

metrics.top_impression_percentage:首页展示百分比

客户账户信息SQL

查询经理账号客户列表:

https://googleads.googleapis.com/v16/customers:listAccessibleCustomers

返回经理账号的客户列表

账户效果数据SQL

查询客户账户预算信息

query 同demo标红部分

query = SELECT account_budget.adjusted_spending_limit_micros, account_budget.amount_served_micros, account_budget.approved_start_date_time, account_budget.id, account_budget.name, account_budget.pending_proposal.spending_limit_micros, account_budget.pending_proposal.start_date_time, account_budget.proposed_end_date_time, account_budget.proposed_spending_limit_micros, account_budget.proposed_start_date_time, account_budget.resource_name, account_budget.status, account_budget.total_adjustments_micros, customer.currency_code, customer.id, customer.manager, customer.resource_name, customer.status, customer.test_account, account_budget.approved_spending_limit_micros, account_budget.approved_end_date_time, customer.has_partners_badge FROM account_budget

查询2024-05-06号客户所有的点击数据  query 同demo标红部分

query = SELECT customer.resource_name, segments.date, metrics.average_cost, metrics.average_cpc, metrics.average_cpe, metrics.average_cpm, metrics.average_cpv, metrics.clicks, metrics.ctr, metrics.impressions, metrics.absolute_top_impression_percentage, metrics.top_impression_percentage,metrics.cost_micros FROM customer WHERE segments.date = '2024-05-06' ORDER BY metrics.clicks DESC, metrics.impressions DESC

扩展一个月的数据

segments.date  >= '2024-05-01' and segments.date  <= '2024-05-31'

扩展TOP-10的数据

LIMIT  10

广告系列效果数据SQL

查询2024-05-06号广告系列所有的点击数据  query 同demo标红部分

query = SELECT campaign.resource_name,campaign.name,campaign.amount_micros, segments.date, metrics.average_cost, metrics.average_cpc, metrics.average_cpe, metrics.average_cpm, metrics.average_cpv, metrics.clicks, metrics.ctr, metrics.impressions,metrics.cost_micros,campaign.campaign_budget FROM campaign WHERE segments.date = '2024-05-06' ORDER BY metrics.clicks DESC, metrics.impressions DESC

扩展一个月的数据

segments.date  >= '2024-05-01' and segments.date  <= '2024-05-31'

扩展TOP-10的数据

LIMIT  10

每日花费明细SQL

日维度下账号花费明细,可根据客户汇总  query 同demo标红部分

查询2024-05-06号客户的点击数据

query =  SELECT customer.resource_name, segments.date, metrics.average_cost, metrics.average_cpc, metrics.average_cpe, metrics.average_cpm, metrics.average_cpv, metrics.clicks, metrics.ctr, metrics.impressions,metrics.cost_micros FROM customer WHERE segments.date = '2024-05-06' ORDER BY metrics.clicks DESC, metrics.impressions DESC

扩展一个月的数据

segments.date  >= '2024-05-01' and segments.date  <= '2024-05-31'

扩展TOP-10的数据

LIMIT  10

地理位置数据SQL

查询2024-05-06号广告地理位置所有的点击数据,同一个国家可能会有多条,query 同demo标红部分

query =SELECT ad_group_ad.ad.call_ad.country_code, segments.date, metrics.average_cost, metrics.average_cpc, metrics.average_cpe, metrics.average_cpm, metrics.average_cpv, metrics.clicks, metrics.ctr, metrics.impressions,metrics.cost_micros FROM ad_group_ad WHERE segments.date = '2024-05-06' ORDER BY metrics.clicks DESC, metrics.impressions DESC

扩展一个月的数据

segments.date  >= '2024-05-01' and segments.date  <= '2024-05-31'

扩展TOP-10的数据

LIMIT  10

关键字数据SQL

查询2024-05-06号关键字所有的点击数据  query 同demo标红部分

query = SELECT keyword_view.resource_name, segments.date, metrics.average_cost, metrics.average_cpc, metrics.average_cpm, metrics.average_cpv, metrics.clicks, metrics.ctr, metrics.average_cpe, metrics.impressions,metrics.cost_micros, segments.day_of_week FROM keyword_view WHERE segments.date = '2024-05-06' ORDER BY metrics.clicks DESC, metrics.impressions DESC

扩展一个月的数据

segments.date  >= '2024-05-01' and segments.date  <= '2024-05-31'

扩展TOP-10的数据

LIMIT  10

6.应用上线申请

应用上线前测试阶段可添加测试账号用于访问Google Ads Api :

应用提交上线: 点击“发布应用程序”

点击“确认”

点击“准备验证”

应用首页,应用隐私权政策链接必填

并录制使用授权的scopes API的所有场景相关的视频,并上传Youtube, 获取链接并按照需求保存地址

Google 平台会发送邮件申请对你的应用及相关信息进行审核,此时需要回复Google 邮件,Google平台才会进行审核,审核周期4-6周左右,建议提前申请该流程,可能会多次沟通提交资料不通过的情况

参考资料

Coogle Ads API 接口说明文档链接:

https://developers.google.cn/google-ads/api/docs/start?hl=zh-cn

Google Cloud API 云平台管理后台链接:

https://console.cloud.google.com/apis/dashboard?hl=zh-cn

Google Ads 查询生成器 报告生成器

Google Ads Query Builder  |  Google Ads API  |  Google for Developers

Google Ads 开发者令牌申请

获取开发者令牌  |  Google Ads API  |  Google for Developers

Google Ads API 创建项目及凭证授权

设置 Google API 控制台项目  |  Google Ads API  |  Google for Developers

Google Ads API 接口令牌刷新及接口调用

进行 API 调用  |  Google Ads API  |  Google for Developers

Google Ads API 在线调用工具

https://developers.google.com/google-ads/api/rest/reference/rest/v16/customers.googleAds/searchStream

Google Ads 接口授权链接

https://www.googleapis.com/auth/adwords

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐