Generating Targeting Ideas

The Keyword Planner in the AdWords web interface 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::v201806::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::v201806::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<SearchParameter> 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::v201806::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<AttributeType, Attribute> 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<AttributeType, Google.Api.Ads.AdWords.v201806.Attribute> 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: %s\n",
            $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::v201806::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::v201806::NetworkSetting->new({
  targetGoogleSearch         => 1,
  targetSearchNetwork        => 0,
  targetContentNetwork       => 0,
  targetPartnerSearchNetwork => 0
});
my $network_setting_parameter =
  Google::Ads::AdWords::v201806::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):

Keyword Planner AdWords API
Your product or service RelatedToQuerySearchParameter
Your landing page RelatedToUrlSearchParameter
Your product category CategoryProductsAndServicesSearchParameter (refer to our Product and Services Categories taxonomy or IDs)
Targeting - Location LocationSearchParameter
Targeting - Language LanguageSearchParameter
Targeting - Network NetworkSearchParameter
Date Range (Monthly Search Volume) Select AttributeType.TARGETED_MONTHLY_SEARCHES
Keyword Filters - Average monthly searches SearchVolumeSearchParameter
Keyword Filters - Competition CompetitionSearchParameter
Include/Exclude Keywords IdeaTextFilterSearchParameter
ExcludedKeywordSearchParameter

Lastly, set the TargetingIdeaSelector.requestType to IDEAS.

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

Keyword Planner AdWords API
Enter keywords RelatedToQuerySearchParameter
Targeting - Location LocationSearchParameter
Targeting - Network NetworkSearchParameter
Date Range (Monthly Search Volume) Select AttributeType.TARGETED_MONTHLY_SEARCHES

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.

Keyword Planner AdWords API
List 1 and List 2 Programmatically combine the two lists and then use the RelatedToQuerySearchParameter
Targeting - Location LocationSearchParameter
Targeting - Network NetworkSearchParameter

Code examples

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

Wyślij opinię na temat...

Potrzebujesz pomocy? Odwiedź naszą stronę wsparcia.