Google Ads

Generating Targeting Ideas  |  AdWords API  |  Google Developers

The Keyword Planner in the
Google Ads UI proposes new keyword ideas based on your
existing keywords and website. You can then retrieve historical
statistics for keywords (Average CPC, Monthly Search
Volume, etc.) to help you decide whether to use these keyword ideas or not.

You can achieve similar goals in the AdWords API with the
TargetingIdeaService,
that allows you to retrieve targeting ideas from your own
tool/platform to help automate account optimization.

Use case

TargetingIdeaService can be used to get new keyword ideas based on a number of
inputs, such as:

  • Seed Keywords
  • Seed Ad Group ID
  • Target Website
  • Location
  • Language
  • Product and Services Category
  • And many
    more

For example, if you’re creating a new campaign, or optimizing an existing
campaign, you can use the TargetingIdeaService to retrieve a list of
candidate keywords based on your existing taxonomy of keywords.

You can use the service to obtain results similar to the functions under
Find new keywords and get search volume data in Keyword Planner:

The Keyword Planner function Plan your budget and get forecasts is covered
in Estimating Traffic.

Retrieving keyword ideas

The primary input to the TargetingIdeaService is the
TargetingIdeaSelector.
The following is an example of
getting keyword ideas from the TargetingIdeaService by using a couple of seed
keywords.

Prepare the request

First, prepare the TargetingIdeaSelector with parameters that indicate the
request’s purpose is to retrieve keyword ideas:

Java

TargetingIdeaSelector selector = new TargetingIdeaSelector();
selector.setRequestType(RequestType.IDEAS);
selector.setIdeaType(IdeaType.KEYWORD);

C#

TargetingIdeaSelector selector = new TargetingIdeaSelector
{
    requestType = RequestType.IDEAS,
    ideaType = IdeaType.KEYWORD,

Python

selector = {
    'ideaType': 'KEYWORD',
    'requestType': 'IDEAS'
}

PHP

$selector = new TargetingIdeaSelector();
$selector->setRequestType(RequestType::IDEAS);
$selector->setIdeaType(IdeaType::KEYWORD);

Perl

my $selector = Google::Ads::AdWords::v201809::TargetingIdeaSelector->new({
  requestType => "IDEAS",
  ideaType    => "KEYWORD"
});

Ruby

selector = {
  :idea_type => 'KEYWORD',
  :request_type => 'IDEAS'
}

VB.NET

Dim selector As New TargetingIdeaSelector()
selector.requestType = RequestType.IDEAS
selector.ideaType = IdeaType.KEYWORD

Next, select the
attributes
that must be retrieved. Attributes can be thought of as individual columns/fields
that are related to the keyword:

Java

selector.setRequestedAttributeTypes(new AttributeType[] {
    AttributeType.KEYWORD_TEXT,
    AttributeType.SEARCH_VOLUME,
    AttributeType.AVERAGE_CPC,
    AttributeType.COMPETITION,
    AttributeType.CATEGORY_PRODUCTS_AND_SERVICES});

C#

    requestedAttributeTypes = new AttributeType[]
    {
        AttributeType.KEYWORD_TEXT,
        AttributeType.SEARCH_VOLUME,
        AttributeType.AVERAGE_CPC,
        AttributeType.COMPETITION,
        AttributeType.CATEGORY_PRODUCTS_AND_SERVICES
    }
};

Python

selector['requestedAttributeTypes'] = [
    'KEYWORD_TEXT', 'SEARCH_VOLUME', 'CATEGORY_PRODUCTS_AND_SERVICES']

PHP

$selector->setRequestedAttributeTypes(
    [
        AttributeType::KEYWORD_TEXT,
        AttributeType::SEARCH_VOLUME,
        AttributeType::AVERAGE_CPC,
        AttributeType::COMPETITION,
        AttributeType::CATEGORY_PRODUCTS_AND_SERVICES
    ]
);

Perl

$selector->set_requestedAttributeTypes([
  "KEYWORD_TEXT", "SEARCH_VOLUME",
  "AVERAGE_CPC",  "COMPETITION",
  "CATEGORY_PRODUCTS_AND_SERVICES"
]);

Ruby

selector[:requested_attribute_types] = [
  'KEYWORD_TEXT',
  'SEARCH_VOLUME',
  'AVERAGE_CPC',
  'COMPETITION',
  'CATEGORY_PRODUCTS_AND_SERVICES',
]

VB.NET

selector.requestedAttributeTypes =
    New AttributeType() { _
                            AttributeType.KEYWORD_TEXT,
                            AttributeType.SEARCH_VOLUME,
                            AttributeType.CATEGORY_PRODUCTS_AND_SERVICES
                        }

Next, configure the selector’s Paging
to limit the number of results returned by a single request. Paging is a
required field of
TargetingIdeaSelector.

Java

// Set selector paging (required for targeting idea service).
Paging paging = new Paging();
paging.setStartIndex(0);
paging.setNumberResults(10);
selector.setPaging(paging);

C#

// Set selector paging (required for targeting idea service).
selector.paging = Paging.Default;

Python

offset = 0
selector['paging'] = {
    'startIndex': str(offset),
    'numberResults': str(PAGE_SIZE)
}

PHP

$paging = new Paging();
$paging->setStartIndex(0);
$paging->setNumberResults(10);
$selector->setPaging($paging);

Perl

# Set selector paging (required for targeting idea service).
my $paging = Google::Ads::AdWords::v201809::Paging->new({
  startIndex    => 0,
  numberResults => 10
});
$selector->set_paging($paging);

Ruby

selector[:paging] = {
  :start_index => 0,
  :number_results => PAGE_SIZE
}

VB.NET

' Set selector paging (required for targeting idea service).
selector.paging = Paging.Default

Finally, use the
RelatedToQuerySearchParameter
to specify a list of seed keywords from which to generate new ideas:

Java

List searchParameters = new ArrayList<>();
// Create related to query search parameter.
RelatedToQuerySearchParameter relatedToQuerySearchParameter =
    new RelatedToQuerySearchParameter();
relatedToQuerySearchParameter.setQueries(new String[] {"bakery", "pastries", "birthday cake"});
searchParameters.add(relatedToQuerySearchParameter);

C#

// Create related to query search parameter.
RelatedToQuerySearchParameter relatedToQuerySearchParameter =
    new RelatedToQuerySearchParameter
    {
        queries = new string[]
        {
            "bakery",
            "pastries",
            "birthday cake"
        }
    };
searchParameters.Add(relatedToQuerySearchParameter);

Python

selector['searchParameters'] = [{
    'xsi_type': 'RelatedToQuerySearchParameter',
    'queries': ['space cruise']
}]

PHP

$searchParameters = [];
// Create related to query search parameter.
$relatedToQuerySearchParameter = new RelatedToQuerySearchParameter();
$relatedToQuerySearchParameter->setQueries(
    [
        'bakery',
        'pastries',
        'birthday cake'
    ]
);
$searchParameters[] = $relatedToQuerySearchParameter;

Perl

# Create related to query search parameter.
my @search_parameters = ();
my $related_to_query_search_parameter =
  Google::Ads::AdWords::v201809::RelatedToQuerySearchParameter->new(
  {queries => ["bakery", "pastries", "birthday cake"]});
push @search_parameters, $related_to_query_search_parameter;

Ruby

search_parameters = []
search_parameters << {
    # The 'xsi_type' field allows you to specify the xsi:type of the object
    # being created. It's only necessary when you must provide an explicit
    # type that the client library can't infer.
    :xsi_type => 'RelatedToQuerySearchParameter',
    :queries => [keyword_text]
}

VB.NET

' Create related to query search parameter.
Dim relatedToQuerySearchParameter As New RelatedToQuerySearchParameter()
relatedToQuerySearchParameter.queries = New String() { _
                                                         "bakery", "pastries",
                                                         "birthday cake"
                                                     }
searchParameters.Add(relatedToQuerySearchParameter)

Once you’ve configured the TargetingIdeaSelector, send it through the get
operation to retrieve keyword ideas:

Java

// Get keyword ideas.
TargetingIdeaPage page = targetingIdeaService.get(selector);

C#

// Get related keywords.
page = targetingIdeaService.get(selector);

Python

page = targeting_idea_service.get(selector)

PHP

// Get keyword ideas.
$page = $targetingIdeaService->get($selector);

Perl

# Get keyword ideas.
my $page = $client->TargetingIdeaService()->get({selector => $selector});

Ruby

begin
  # Perform request. If this loop executes too many times in quick suggestion,
  # you may get a RateExceededError. See here for more info on handling these:
  # https://developers.google.com/adwords/api/docs/guides/rate-limits
  page = targeting_idea_srv.get(selector)
  results += page[:entries] if page and page[:entries]

  # Prepare next page request.
  offset += PAGE_SIZE
  selector[:paging][:start_index] = offset
end while offset < page[:total_num_entries]

VB.NET

' Get related keywords.
page = targetingIdeaService.get(selector)

Process the response

The response is composed of a list of
TargetingIdea
objects. Each TargetingIdea object contains a map of
AttributeType
associated with an
Attribute.
It's easier to think of each TargetingIdea object as a data row, each
AttributeType as a field/column of the row, and the corresponding Attribute
as the value for that data cell.

Java

// Display keyword ideas.
for (TargetingIdea targetingIdea : page.getEntries()) {
  Map data = Maps.toMap(targetingIdea.getData());
  StringAttribute keyword = (StringAttribute) data.get(AttributeType.KEYWORD_TEXT);

  IntegerSetAttribute categories =
      (IntegerSetAttribute) data.get(AttributeType.CATEGORY_PRODUCTS_AND_SERVICES);
  String categoriesString = "(none)";
  if (categories != null && categories.getValue() != null) {
    categoriesString = Joiner.on(", ").join(Ints.asList(categories.getValue()));
  }
  Long averageMonthlySearches =
      ((LongAttribute) data.get(AttributeType.SEARCH_VOLUME))
          .getValue();
  Money averageCpc =
      ((MoneyAttribute) data.get(AttributeType.AVERAGE_CPC)).getValue();
  Double competition =
      ((DoubleAttribute) data.get(AttributeType.COMPETITION)).getValue();
  System.out.printf("Keyword with text '%s', average monthly search volume %d, "
      + "average CPC %d, and competition %.2f "
      + "was found with categories: %s%n", keyword.getValue(), averageMonthlySearches,
      averageCpc.getMicroAmount(), competition,
      categoriesString);
}

C#

// Display related keywords.
if (page.entries != null && page.entries.Length > 0)
{
    foreach (TargetingIdea targetingIdea in page.entries)
    {
        Dictionary
            ideas = targetingIdea.data.ToDict();

        string keyword =
            (ideas[AttributeType.KEYWORD_TEXT] as StringAttribute).value;
        IntegerSetAttribute categorySet =
            ideas[AttributeType.CATEGORY_PRODUCTS_AND_SERVICES] as
                IntegerSetAttribute;

        string categories = "";

        if (categorySet != null && categorySet.value != null)
        {
            categories = string.Join(", ", categorySet.value);
        }

        long averageMonthlySearches =
            (ideas[AttributeType.SEARCH_VOLUME] as LongAttribute).value;

        Money averageCpc =
            (ideas[AttributeType.AVERAGE_CPC] as MoneyAttribute).value;
        double competition =
            (ideas[AttributeType.COMPETITION] as DoubleAttribute).value;
        Console.WriteLine(
            "Keyword with text '{0}', average monthly search volume {1}, " +
            "average CPC {2}, and competition {3:F2} was found with " +
            "categories: {4}", keyword, averageMonthlySearches,
            averageCpc?.microAmount, competition, categories);

        Console.WriteLine(
            "Keyword with text '{0}', and average monthly search volume " +
            "'{1}' was found with categories: {2}", keyword,
            averageMonthlySearches, categories);
        i++;
    }
}

Python

for result in page['entries']:
  attributes = {}
  for attribute in result['data']:
    attributes[attribute['key']] = getattr(
        attribute['value'], 'value', '0')
  print('Keyword with "%s" text and average monthly search volume '
        '"%s" was found with Products and Services categories: %s.'
        % (attributes['KEYWORD_TEXT'],
            attributes['SEARCH_VOLUME'],
            attributes['CATEGORY_PRODUCTS_AND_SERVICES']))

PHP

// Print out some information for each targeting idea.
$entries = $page->getEntries();
if ($entries !== null) {
    foreach ($entries as $targetingIdea) {
        $data = MapEntries::toAssociativeArray($targetingIdea->getData());
        $keyword = $data[AttributeType::KEYWORD_TEXT]->getValue();
        $searchVolume = ($data[AttributeType::SEARCH_VOLUME]->getValue() !== null)
            ? $data[AttributeType::SEARCH_VOLUME]->getValue() : 0;
        $averageCpc = $data[AttributeType::AVERAGE_CPC]->getValue();
        $competition = $data[AttributeType::COMPETITION]->getValue();
        $categoryIds = ($data[AttributeType::CATEGORY_PRODUCTS_AND_SERVICES]->getValue() === null)
            ? $categoryIds = ''
            : implode(
                ', ',
                $data[AttributeType::CATEGORY_PRODUCTS_AND_SERVICES]->getValue()
            );
        printf(
            "Keyword with text '%s', average monthly search volume %d, "
            . "average CPC %d, and competition %.2f was found with categories: %sn",
            $keyword,
            $searchVolume,
            ($averageCpc === null) ? 0 : $averageCpc->getMicroAmount(),
            $competition,
            $categoryIds
        );
    }
}

Perl

foreach my $targeting_idea (@{$page->get_entries()}) {
  my $data =
    Google::Ads::Common::MapUtils::get_map($targeting_idea->get_data());
  my $keyword = $data->{"KEYWORD_TEXT"}->get_value();
  my $search_volume =
      $data->{"SEARCH_VOLUME"}->get_value()
    ? $data->{"SEARCH_VOLUME"}->get_value()
    : 0;
  my $categories =
      $data->{"CATEGORY_PRODUCTS_AND_SERVICES"}->get_value()
    ? $data->{"CATEGORY_PRODUCTS_AND_SERVICES"}->get_value()
    : [];
  my $average_cpc =
    $data->{"AVERAGE_CPC"}->get_value()->get_microAmount();
  my $competition = $data->{"COMPETITION"}->get_value();
  printf "Keyword with text '%s', monthly search volume %d, average CPC" .
    " %d, and competition %.2f was found with categories: '%s'n", $keyword,
    $search_volume, $average_cpc, $competition, join(", ", @{$categories});
}

Ruby

# Display results.
results.each do |result|
  data = result[:data]
  keyword = data['KEYWORD_TEXT'][:value]
  average_cpc = data['AVERAGE_CPC'][:value]
  competition = data['COMPETITION'][:value]
  products_and_services = data['CATEGORY_PRODUCTS_AND_SERVICES'][:value]
  average_monthly_searches = data['SEARCH_VOLUME'][:value]
  puts ("Keyword with text '%s', average monthly search volume %d, " +
      "average CPC %d, and competition %.2f was found with categories: %s") %
      [
        keyword,
        average_monthly_searches,
        average_cpc[:micro_amount],
        competition,
        products_and_services
      ]
end

VB.NET

                        'Display the results.
                        If Not page.entries Is Nothing AndAlso page.entries.Length > 0 Then
                            For Each targetingIdea As TargetingIdea In page.entries
                                For Each entry As Type_AttributeMapEntry In targetingIdea.data
                                    ' Preferred: Use targetingIdea.data.ToDict() if you are not on
                                    ' Mono.
                                    Dim ideas As Dictionary(Of AttributeType, Attribute) =
                                            MapEntryExtensions.ToDict (Of AttributeType, Attribute)(
                                                targetingIdea.data)

                                    Dim keyword As String =
                                            DirectCast(ideas(AttributeType.KEYWORD_TEXT),
                                                       StringAttribute).value
                                    Dim categorySet As IntegerSetAttribute =
                                            DirectCast(
                                                ideas(AttributeType.CATEGORY_PRODUCTS_AND_SERVICES),
                                                IntegerSetAttribute)

                                    Dim categories As String = ""

                                    If _
                                        (Not categorySet Is Nothing) AndAlso
                                        (Not categorySet.value Is Nothing) Then
                                        categories = String.Join(", ", categorySet.value)
                                    End If

                                    Dim averageMonthlySearches As Long =
                                            DirectCast(ideas(AttributeType.SEARCH_VOLUME),
                                                       LongAttribute).value


                                    Dim averageCpcMoney As Money =
                                            DirectCast(ideas(AttributeType.AVERAGE_CPC),
                                                       MoneyAttribute).value
                                    Dim averageCpc As Long
                                    If (Not averageCpcMoney Is Nothing) Then
                                        averageCpc = averageCpcMoney.microAmount
                                    End If

                                    Dim competition As Double =
                                            DirectCast(ideas(AttributeType.COMPETITION),
                                                       DoubleAttribute).value
                                    Console.WriteLine(
                                        "Keyword with text '{0}', average monthly search " +
                                        "volume {1}, average CPC {2}, and competition {3:F2} was " &
                                        "found with categories: {4}", keyword,
                                        averageMonthlySearches, averageCpc,
                                        competition, categories)
                                Next
                                i = i + 1
                            Next
                        End If
                        selector.paging.IncreaseOffset()
                    Loop While (selector.paging.startIndex < page.totalNumEntries)
                    Console.WriteLine("Number of related keywords found: {0}", page.totalNumEntries)
                Catch e As Exception
                    Throw New System.ApplicationException("Failed to retrieve related keywords.", e)
                End Try
            End Using
        End Sub
    End Class
End Namespace

The example request selected four attributes, so a sample response may look
like this:

KEYWORD_TEXT SEARCH_VOLUME AVERAGE_CPC COMPETITION
cake bakery 170 0.485384 0.41
bakery story 390 0.069918 0.12
... ... ... ...

Retrieving keyword stats

Retrieving historical keyword statistics is very similar to retrieving keyword
ideas. The only difference is that the RequestType must be set to STATS
instead.

Seeding with an ad group ID

If you already have an existing campaign and ad group, you can retrieve
targeting ideas by providing the ad group ID with the
SeedAdGroupIdSearchParameter.

Java

SeedAdGroupIdSearchParameter seedAdGroupIdSearchParameter =
    new SeedAdGroupIdSearchParameter();
seedAdGroupIdSearchParameter.setAdGroupId(adGroupId);
searchParameters.add(seedAdGroupIdSearchParameter);

C#

SeedAdGroupIdSearchParameter seedAdGroupIdSearchParameter =
    new SeedAdGroupIdSearchParameter
    {
        adGroupId = adGroupId.Value
    };
searchParameters.Add(seedAdGroupIdSearchParameter);

Python

# Use an existing ad group to generate ideas (optional)
if ad_group_id is not None:
  selector['searchParameters'].append({
      'xsi_type': 'SeedAdGroupIdSearchParameter',
      'adGroupId': ad_group_id
  })

PHP

$seedAdGroupIdSearchParameter = new SeedAdGroupIdSearchParameter();
$seedAdGroupIdSearchParameter->setAdGroupId($adGroupId);
$searchParameters[] = $seedAdGroupIdSearchParameter;

Perl

my $seed_ad_group_id_search_parameter =
  Google::Ads::AdWords::v201809::SeedAdGroupIdSearchParameter->new({
    adGroupId => $ad_group_id
  });
push @search_parameters, $seed_ad_group_id_search_parameter;

Ruby

search_parameters << {
  :xsi_type => 'SeedAdGroupIdSearchParameter',
  :ad_group_id => ad_group_id
}

VB.NET

Dim seedAdGroupIdSearchParameter As New SeedAdGroupIdSearchParameter()
seedAdGroupIdSearchParameter.adGroupId = adGroupId.Value
searchParameters.Add(seedAdGroupIdSearchParameter)

Mapping to Keyword Planner

One of the most frequently asked questions about the TargetingIdeaService is:
"Why do the TargetingIdeaService results differ from those of the Keyword
Planner tool?"

The reason is that a TargetingIdeaSelector can be configured with more than one different
SearchParameter,
and the returned results may differ significantly when a different SearchParameter is used.

Select the right network

One of the most common mistakes is not specifying the
NetworkSearchParameter.
For example, the Keyword Planner may only be searching keyword ideas for
the Google Search network, but not for other networks. In this case, make sure to
set the NetworkSearchParameter in the TargetingIdeaSelector.
For example, to retrieve ideas only for the Search network, set the
NetworkSearchParameter like this:

Java

// Create network search parameter (optional).
NetworkSetting networkSetting = new NetworkSetting();
networkSetting.setTargetGoogleSearch(true);
networkSetting.setTargetSearchNetwork(false);
networkSetting.setTargetContentNetwork(false);
networkSetting.setTargetPartnerSearchNetwork(false);

NetworkSearchParameter networkSearchParameter = new NetworkSearchParameter();
networkSearchParameter.setNetworkSetting(networkSetting);
searchParameters.add(networkSearchParameter);

C#

// Add network search parameter (optional).
NetworkSetting networkSetting = new NetworkSetting
{
    targetGoogleSearch = true,
    targetSearchNetwork = false,
    targetContentNetwork = false,
    targetPartnerSearchNetwork = false
};

NetworkSearchParameter networkSearchParameter = new NetworkSearchParameter
{
    networkSetting = networkSetting
};
searchParameters.Add(networkSearchParameter);

Python

# Network search parameter (optional)
selector['searchParameters'].append({
    'xsi_type': 'NetworkSearchParameter',
    'networkSetting': {
        'targetGoogleSearch': True,
        'targetSearchNetwork': False,
        'targetContentNetwork': False,
        'targetPartnerSearchNetwork': False
    }
})

PHP

// Create network search parameter (optional).
$networkSetting = new NetworkSetting();
$networkSetting->setTargetGoogleSearch(true);
$networkSetting->setTargetSearchNetwork(false);
$networkSetting->setTargetContentNetwork(false);
$networkSetting->setTargetPartnerSearchNetwork(false);

$networkSearchParameter = new NetworkSearchParameter();
$networkSearchParameter->setNetworkSetting($networkSetting);
$searchParameters[] = $networkSearchParameter;

Perl

# Create network search paramter (optional).
my $network_setting = Google::Ads::AdWords::v201809::NetworkSetting->new({
  targetGoogleSearch         => 1,
  targetSearchNetwork        => 0,
  targetContentNetwork       => 0,
  targetPartnerSearchNetwork => 0
});
my $network_setting_parameter =
  Google::Ads::AdWords::v201809::NetworkSearchParameter->new(
  {networkSetting => $network_setting});
push @search_parameters, $network_setting_parameter;

Ruby

search_parameters << {
  # Network search parameter (optional).
  :xsi_type => 'NetworkSearchParameter',
  :network_setting => {
    :target_google_search => true,
    :target_search_network => false,
    :target_content_network => false,
    :target_partner_search_network => false
  }
}

VB.NET

' Add network search parameter (optional).
Dim networkSetting As New NetworkSetting()
networkSetting.targetGoogleSearch = True
networkSetting.targetSearchNetwork = False
networkSetting.targetContentNetwork = False
networkSetting.targetPartnerSearchNetwork = False

Dim networkSearchParameter As New NetworkSearchParameter()
networkSearchParameter.networkSetting = networkSetting
searchParameters.Add(networkSearchParameter)

It's important to configure the NetworkSearchParameter consistent with how the potential
campaign will be configured.

Search for new keywords using a phrase, website, or category

To implement something similar to this Keyword Planner functionality, each
of the input fields can be mapped to a corresponding TargetingIdeaSelector
configuration (for example, SearchParameter):

Lastly, set the TargetingIdeaSelector.requestType to IDEAS.

The parameters mapping is similar to other functions of this kind:

Lastly, set the TargetingIdeaSelector.requestType to STATS.

Multiply keyword lists to get new keyword

The AdWords API does not automatically calculate keyword combinations. To
achieve the same functionality, you need to programmatically determine the
combined keywords list, and then set up the TargetingIdeaSelector accordingly.

Code examples

Each client library contains a complete code example in the Optimization
folder:

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button
Close