MCPcopy Index your code
hub / github.com/Opteo/google-ads-api

github.com/Opteo/google-ads-api @v23.0.1

Chat with this repo
repository ↗ · DeepWiki ↗ · release v23.0.1 ↗ · + Follow
814 symbols 1,469 edges 34 files 114 documented · 14% 1 cross-repo links
What it actually does AI analysis from the code graph — generated when you open this
loading…
README
Google Ads API

Unofficial Google Ads API client library for Node.js

Features

  • Simple and easy to use API
  • Uses REST and Protocol Buffers internally
  • Typescript definitions for all resources, enums, errors and services
  • Provides all API functionality

Installation

npm install google-ads-api

Usage

Create a client

import { GoogleAdsApi } from "google-ads-api";

const client = new GoogleAdsApi({
  client_id: "<CLIENT-ID>",
  client_secret: "<CLIENT-SECRET>",
  developer_token: "<DEVELOPER-TOKEN>",
});

Create a customer instance

const customer = client.Customer({
  customer_id: "1234567890",
  refresh_token: "<REFRESH-TOKEN>",
});

// Also supports login & linked customer ids
const customer = client.Customer({
  customer_id: "1234567890",
  login_customer_id: "<LOGIN-CUSTOMER-ID>",
  linked_customer_id: "<LINKED-CUSTOMER-ID>",
  refresh_token: "<REFRESH-TOKEN>",
});

List accessible customers

This is a special client method for listing the accessible customers for a given refresh token, and is equivalent to CustomerService.listAccessibleCustomers. It returns the resource names of available customer accounts.

const client = new GoogleAdsApi({
  client_id: "<CLIENT-ID>",
  client_secret: "<CLIENT-SECRET>",
  developer_token: "<DEVELOPER-TOKEN>",
});

const refreshToken = "<REFRESH-TOKEN>";

const customers = await client.listAccessibleCustomers(refreshToken);

Retrieve Campaigns with metrics

import { enums } from "google-ads-api";

const campaigns = await customer.report({
  entity: "campaign",
  attributes: [
    "campaign.id",
    "campaign.name",
    "campaign.bidding_strategy_type",
    "campaign_budget.amount_micros",
  ],
  metrics: [
    "metrics.cost_micros",
    "metrics.clicks",
    "metrics.impressions",
    "metrics.all_conversions",
  ],
  constraints: {
    "campaign.status": enums.CampaignStatus.ENABLED,
  },
  limit: 20,
});

Retrieve Campaigns using GAQL

If you prefer to use the Google Ads Query Language (GAQL) the query method is available. Internally report uses this function. More GAQL examples can be found here.

const campaigns = await customer.query(`
  SELECT 
    campaign.id, 
    campaign.name,
    campaign.bidding_strategy_type,
    campaign_budget.amount_micros,
    metrics.cost_micros,
    metrics.clicks,
    metrics.impressions,
    metrics.all_conversions
  FROM 
    campaign
  WHERE
    campaign.status = "ENABLED"
  LIMIT 20
`);

Retrieve Ad Group metrics by date

import { enums } from "google-ads-api";

const campaigns = await customer.report({
  entity: "ad_group",
  metrics: [
    "metrics.cost_micros",
    "metrics.clicks",
    "metrics.impressions",
    "metrics.all_conversions",
  ],
  segments: ["segments.date"],
  from_date: "2021-01-01",
  to_date: "2021-02-01",
});

Retrieve Keywords with an async iterator

Calls searchStream internally but returns the rows one by one in an async iterator.

import { enums } from "google-ads-api";

const stream = customer.reportStream({
  entity: "ad_group_criterion",
  attributes: [
    "ad_group_criterion.keyword.text", 
    "ad_group_criterion.status",
  ],
  constraints: {
    "ad_group_criterion.type": enums.CriterionType.KEYWORD,
  },
});

// Rows are streamed in one by one
for await (const row of stream) {
    // Break the loop to stop streaming
    if (someLogic) {
        break
    }
}

Or use a GAQL query.

const stream = customer.queryStream(`
  SELECT
    ad_group_criterion.keyword.text,
    ad_group_criterion.status
  FROM
    ad_group_criterion
  WHERE
    ad_group_criterion.type = "KEYWORD"
`);

// Rows are streamed in one by one
for await (const row of stream) {
    // Break the loop to stop streaming
    if (someLogic) {
        break
    }
}

Retrieve Keywords with a raw stream

Returns the raw stream so that events can be handled manually. For more information on Google's stream methods please consult their docs.

import { enums, parse } from "google-ads-api";

const reportOptions = {
  entity: "ad_group_criterion",
  attributes: [
    "ad_group_criterion.keyword.text", 
    "ad_group_criterion.status",
  ],
  constraints: {
    "ad_group_criterion.type": enums.CriterionType.KEYWORD,
  },
};

const stream = customer.reportStreamRaw(reportOptions);

// Rows are streamed in 10,000 row chunks
stream.on("data", (chunk) => {
  const parsedResults = parse({
    results: chunk.results,
    reportOptions,
  });
});

stream.on("error", (error) => {
  throw new Error(error);
});

stream.on("end", () => {
  console.log("stream has finished");
});

Create an expanded text ad

import { resources, enums, ResourceNames } from "google-ads-api";

const ad = new resources.Ad({
  expanded_text_ad: {
    headline_part1: "Cruise to Mars",
    headline_part2: "Best Space Cruise Line",
    description: "Buy your tickets now!",
    path1: "cruises",
    path2: "mars",
  },
  final_urls: ["https://example.com"],
  type: enums.AdType.EXPANDED_TEXT_AD,
});

const adGroup = ResourceNames.adGroup(cus.credentials.customerId, "123");

const adGroupAd = new resources.AdGroupAd({
  status: enums.AdGroupAdStatus.PAUSED,
  ad_group,
  ad,
});

// Returns an array of newly created resource names if successful
const { results } = await cus.adGroupAds.create([adGroupAd]);

Create a Campaign & Budget atomically

import {
  resources,
  enums,
  toMicros,
  ResourceNames,
  MutateOperation,
} from "google-ads-api";

// Create a resource name with a temporary resource id (-1)
const budgetResourceName = ResourceNames.campaignBudget(
  customer.credentials.customer_id,
  "-1"
);

const operations: MutateOperation<
  resources.ICampaignBudget | resources.ICampaign
>[] = [
  {
    entity: "campaign_budget",
    operation: "create",
    resource: {
      // Create a budget with the temporary resource id
      resource_name: budgetResourceName,
      name: "Planet Express Budget",
      delivery_method: enums.BudgetDeliveryMethod.STANDARD,
      amount_micros: toMicros(500),
    },
  },
  {
    entity: "campaign",
    operation: "create",
    resource: {
      name: "Planet Express",
      advertising_channel_type: enums.AdvertisingChannelType.SEARCH,
      status: enums.CampaignStatus.PAUSED,
      manual_cpc: {
        enhanced_cpc_enabled: false,
      },
      // Use the temporary resource id which will be created in the previous operation
      campaign_budget: budgetResourceName,
      network_settings: {
        target_google_search: true,
        target_search_network: true,
      },
    },
  },
];

const result = await customer.mutateResources(operations);

Add Policy Exemption Rules

import {
  resources,
  enums,
  toMicros,
  ResourceNames,
  MutateOperation,
} from "google-ads-api";

// Ad Group to which you want to add the keyword
const adGroupResourceName = "customers/123/adGroups/456";

const keyword = "24 hour locksmith harlem";

const operations: MutateOperation<
  resources.IAdGroupCriterion & {
    exempt_policy_violation_keys?: google.ads.googleads.v23.common.IPolicyViolationKey[];
  }
>[] = [
  {
    entity: "ad_group_criterion",
    operation: "create",
    resource: {
      // Keyword with policy violation exemptions
      ad_group: adGroupResourceName,
      keyword: {
        text: "24 hour locksmith harlem",
        match_type: enums.KeywordMatchType.PHRASE,
      },
      status: enums.AdGroupStatus.ENABLED,
    },
    exempt_policy_violation_keys: [
      {
        policy_name: "LOCAL_SERVICES",
        violating_text: keyword,
      },
    ],
  },
];

const result = await customer.mutateResources(operations);

Uploading Click Conversions

const clickConversion = {
  gclid: "<GOOGLE-CLICK-ID>",
  conversion_action: "customers/1234567890/conversionActions/111222333",
  conversion_date_time: "2022-01-11 00:00:00",
  conversion_value: 123,
  currency_code: "GBP",
};

const request = new services.UploadClickConversionsRequest({
  customer_id: customerId,
  conversions: [clickConversion],
});

await customer.conversionUploads.uploadClickConversions(request);

Summary Row

If a summary row is requested in the report method, it will be included as the first row of the results.

const [summaryRow, ...response] = await customer.report({
  entity: "campaign",
  metrics: ["metrics.clicks", "metrics.all_conversions"],
  search_settings: {
    return_summary_row: true,
  },
});

If a summery row is requested in the reportStream method, it will be included as the final iterated row of the results.

const stream = customer.reportStream({
  entity: "campaign",
  metrics: ["metrics.clicks", "metrics.all_conversions"],
  search_settings: {
    return_summary_row: true,
  },
});

const accumulator = [];
for await (const row of stream) {
  accumulator.push(row);
}

const summaryRow = accumulator.slice(-1)[0];

Total Results Count

The reportCount method acts like report but returns the total number of rows that the query would have returned (ignoring the limit). This replaces the return_total_results_count report option. Hooks are not called in this function to avoid cacheing conflicts.

const totalRows = await customer.reportCount({
  entity: "search_term_view",
  attributes: ["search_term_view.resource_name"],
});

Report Results Order

There are 2 methods of sorting the results of report. The prefered method is to use the order key, which should be an array of objects with a field key and an optional sort_order key. The order of the items in the array will map to the order of the sorting keys in the GAQL query, and hence the priorities of the sorts.

const response = await customer.report({
  entity: "campaign",
  attributes: ["campaign.id"],
  metrics: ["metrics.clicks"],
  segments: ["segments.date"],
  order: [
    { field: "metrics.clicks", sort_order: "DESC" },
    { field: "segments.date", sort_order: "ASC" },
    { field: "campaign.id" }, // default sort_order is descending
  ],
});

The other method is to use the order_by and sort_order keys, however this will be deprecated in a future version of the API.

const response = await customer.report({
  entity: "campaign",
  attributes: ["campaign.id"],
  metrics: ["metrics.clicks"],
  segments: ["segments.date"],
  order_by: "metrics.clicks",
  sort_order: "DESC",
});

Resource Names

The library provides a set of helper methods under the ResourceNames export. These are used for compiling resource names from ids. Arguments can be of the type string, number, or a mix of both. If you have a client.Customer instance available, you can get the customer id with customer.credentials.customerId.

import { ResourceNames } from "google-ads-api";

const customerId = "1234567890";
const campaignId = "3218318373";

ResourceNames.campaign(customerId, campaignId);
// "customers/1234567890/campaigns/3218318373"

ResourceNames.adGroup(123, 123);
// "customers/123/adGroups/123"

ResourceNames.adGroupAd("1", "2", "3");
// "customers/1/adGroupAds/2~3"

const amsterdamLocationId = 1010543;
ResourceNames.geoTargetConstant(amsterdamLocationId);
// "geoTargetConstants/1010543"

ResourceNames.accountBudget(customer.credentials.customer_id, 123);
// "customers/1234567890/accountBudgets/123"

Hooks

The library provides hooks that can be executed before, after or on error of a query, stream or a mutation.

Query/stream hooks:

  • onQueryStart
  • onQueryError
  • onQueryEnd
  • onStreamStart
  • onStreamError

These hooks have access to the customerCredentials argument, containing the `custo

Extension points exported contracts — how you extend this code

ClientOptions (Interface)
(no doc)
src/client.ts
Hooks (Interface)
(no doc)
src/hooks.ts
CallHeaders (Interface)
(no doc)
src/service.ts
CustomerOptions (Interface)
(no doc)
src/types.ts
PathTemplate (Interface)
(no doc)
scripts/resourceName.ts
TestData (Interface)
(no doc)
scripts/resourceName.spec.ts
ProtoDefinition (Interface)
(no doc)
scripts/services.ts
Resource (Interface)
(no doc)
scripts/fields.ts

Core symbols most depended-on inside this repo

decodePartialFailureError
called by 309
src/service.ts
getGoogleAdsError
called by 271
src/service.ts
buildOperations
called by 185
src/service.ts
buildRequest
called by 185
src/service.ts
loadService
called by 115
src/service.ts
newCustomer
called by 60
src/testUtils.ts
querier
called by 14
src/customer.ts
validateConstraintKeyAndValue
called by 14
src/query.ts

Shape

Enum 362
Function 284
Method 144
Interface 16
Class 8

Languages

TypeScript100%

Modules by API surface

src/protos/autogen/enums.ts360 symbols
src/protos/autogen/resourceNames.ts182 symbols
src/protos/autogen/serviceFactory.ts110 symbols
src/testUtils.ts23 symbols
src/customer.ts21 symbols
src/query.ts18 symbols
src/service.ts17 symbols
scripts/services.ts15 symbols
scripts/fields.ts13 symbols
scripts/resourceName.ts9 symbols
src/utils.ts8 symbols
src/parserRest.ts8 symbols

Used by 1 indexed graphs manifest dependencies, hub-wide

For agents

$ claude mcp add google-ads-api \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact