Changing keyword-specific bid to ad group default bid via Ads API (Python)

81 views
Skip to first unread message

Michael Harkin

unread,
Mar 23, 2020, 2:47:28 PM3/23/20
to AdWords API and Google Ads API Forum
How do I go about removing one or more keyword-specific bids via the Google Ads API Python library? What I want to be able to do is perform the equivalent of changing the "Max. CPC" field to blank for a keyword in the Ads UI, thus allowing the ad group default bid to kick in for that keyword.

The first approach I took was retrieving the ad group criterion instance that I wanted to update via GoogleAdsService, then creating a new ad group criterion operation, copying the retrieved campaign onto the new ad group criterion operation's update field, mutating the new ad group criterion (by setting ad_group_criterion.cpc_bid_micros.value = 0), then creating a field mask and copying the field mask onto the operation's update_mask field.

from google.api_core import protobuf_helpers
from google.ads.google_ads.client import GoogleAdsClient

client
= GoogleAdsClient.load_from_storage()
google_ads_service
= client.get_service('GoogleAdsService', version='v3')
agc_operation
= client.get_type('AdGroupCriterionOperation',
                                               version
='v3')

query
= ("SELECT customer.id, ad_group.id, "
         
"ad_group_criterion.criterion_id, "
         "ad_group_criterion.cpc_bid_micros, "
         "ad_group_criterion.keyword.text, "
         "FROM ad_group_criterion "
         "WHERE campaign.status = 'ENABLED' "
         "AND ad_group.status = 'ENABLED' "
         "AND ad_group_criterion.type = 'KEYWORD' "
         "AND ad_group_criterion.status = 'ENABLED' "
         "AND ad_group_criterion.cpc_bid_micros > 0")

results
= google_ads_service.search(customer_id, query=query)

for row in results:    
    initial_ad_group_criterion
= row.ad_group_criterion
    agc_operation
.update.CopyFrom(initial_ad_group_criterion)
    updated_ad_group_criterion
= agc_operation.update
    updated_ad_group_criterion
.cpc_bid_micros.value = 0
    field_mask
= protobuf_helpers.field_mask(initial_ad_group_criterion,
                                             updated_ad_group_criterion
)
    agc_operation
.update_mask.CopyFrom(field_mask)

However, attempting to update/remove the keyword-specific bid in this way results in an INVALID_VALUE partial failure error, with the error message "The field's value is invalid." Digging in a bit further, it appears that 0 is not considered a valid Int64 value and thus cannot be accepted as an updated value for ad_group_criterion.cpc_bid_micros.


For my other approach, I created an empty AdGroupOperation object, retrieving an empty AdGroupCriterion object and updating that object to have ad_group_criterion.cpc_bid_micros.value = 0. I then created a new field mask that compares it to None, finally copying the field mask onto the operation's update_mask field.

from google.api_core import protobuf_helpers
from google.ads.google_ads.client import GoogleAdsClient

client
= GoogleAdsClient.load_from_storage()
google_ads_service
= client.get_service('GoogleAdsService',
                                        version
='v3')
ad_group_criterion_operation
= client.get_type('AdGroupCriterionOperation',
                                               version
='v3')

query
= ("SELECT customer.id, ad_group.id, "
         
"ad_group_criterion.criterion_id, "
         
"ad_group_criterion.cpc_bid_micros, "
         
"ad_group_criterion.keyword.text, "
         "FROM ad_group_criterion "
         "WHERE campaign.status = 'ENABLED' "
         "AND ad_group.status = 'ENABLED' "
         "AND ad_group_criterion.type = 'KEYWORD' "
         "AND ad_group_criterion.status = 'ENABLED' "
         "AND ad_group_criterion.cpc_bid_micros > 0 ")

results
= google_ads_service.search(customer_id, query=query)

for row in results:    
    initial_ad_group_criterion
= row.ad_group_criterion
    ad_group_criterion_operation
.update.CopyFrom(initial_ad_group_criterion)
    updated_ad_group_criterion
= ad_group_criterion_operation.update
    updated_ad_group_criterion
.cpc_bid_micros.value = 0
    field_mask
= protobuf_helpers.field_mask(initial_ad_group_criterion,
                                             updated_ad_group_criterion
)
    ad_group_criterion_operation
.update_mask.CopyFrom(field_mask)

This resulted in a response containing the correct resourceName (customers/{customer_id}/adGroupCriteria/{ad_group_id}~{ad_group_criterion_id}), but the keyword-specific bid wasn't removed or updated -- it remained as it was.

Should I be going about this in a different way entirely? For instance, rather than trying to update the cpc_bid_micros value to "0" should I be using a "remove" mutate of some kind? Thanks for reading and for any help you can provide.

Google Ads API Forum Advisor Prod

unread,
Mar 24, 2020, 10:29:50 AM3/24/20
to mha...@simplepart.com, adwor...@googlegroups.com
Hi Michael,

Thank you for reaching out. You need to use a FieldMask to update this value to default. You should use this example and create a new FieldMask with the path "cpc_bid_micros" and add that to the AdGroupCriterionOperation.

The logs should look like this:
operations {
  update {
    resource_name: "customers/xxxxxxxxxx/adGroupCriteria/xxxxxxxxxx~xxxxxxxx"
    status: ENABLED
  }
  update_mask {
    paths: "cpc_bid_micros"
  }
}

Regards,
Mitchell
Google Ads API Team

ref:_00D1U1174p._5001UXWHab:ref

Michael Harkin

unread,
Mar 24, 2020, 12:22:24 PM3/24/20
to AdWords API and Google Ads API Forum
Thanks for your response Mitchell. I've tried what you suggested but it still fails to update. Here's the code I'm now trying out, based on the example you sent me:

import argparse
import sys

from google.api_core import protobuf_helpers
from google.ads.google_ads.client import GoogleAdsClient
from google.ads.google_ads.util import ResourceName

def main(client, customer_id, ad_group_id, criterion_id):
    agc_service
= client.get_service('AdGroupCriterionService', version='v3')


    ad_group_criterion_operation
= client.get_type('AdGroupCriterionOperation',
                                                   version
='v3')


    ad_group_criterion
= ad_group_criterion_operation.update
    ad_group_criterion
.resource_name = agc_service.ad_group_criteria_path(
        customer_id, ResourceName.format_composite(ad_group_id, criterion_id))
    ad_group_criterion.cpc_bid_micros.value = 0
    fm
= protobuf_helpers.field_mask(None, ad_group_criterion)
    ad_group_criterion_operation
.update_mask.CopyFrom(fm)

     
try:
         agc_response
= agc_service.mutate_ad_group_criteria(
             customer_id
, [ad_group_criterion_operation])
     
except google.ads.google_ads.errors.GoogleAdsException as ex:
         
print('Request with ID "%s" failed with status "%s" and includes the '
               
'following errors:' % (ex.request_id, ex.error.code().name))
         
for error in ex.failure.errors:
             
print('\tError with message "%s".' % error.message)
             
if error.location:
                 
for field_path_element in error.location.field_path_elements:
                     
print('\t\tOn field: %s' % field_path_element.field_name)
         sys
.exit(1)


if __name__ == '__main__':
    google_ads_client
= GoogleAdsClient.load_from_storage()
    parser
= argparse.ArgumentParser(
        description
=('Pauses an ad in the specified customer\'s ad group.'))
    parser
.add_argument('-c', '--customer_id', type=str,
                        required
=True, help='The Google Ads customer ID.')
    parser
.add_argument('-a', '--ad_group_id', type=str,
                        required
=True, help='The ad group ID.')
    parser
.add_argument('-k', '--criterion_id', type=str,
                        required
=True, help='The criterion ID, or keyword ID.')
    args
= parser.parse_args()

    main
(google_ads_client, args.customer_id, args.ad_group_id,
        args
.criterion_id)

Here's what the log says after I run this for an update for a single keyword:

results{
  resource_name
: "customers/{customer_id}/adGroupCriteria/{ad_group_id}~{criterion_id}"

}

Looking at the keyword in the Ads UI after running this Python file, the keyword-specific bid is still there and unchanged. Is setting cpc_bid_micros to 0 in the field mask an incorrect way of going about removing these bids? Do I need to set it to a "default" or "None"-type value? Thanks.

Google Ads API Forum Advisor Prod

unread,
Mar 24, 2020, 4:38:08 PM3/24/20
to mha...@simplepart.com, adwor...@googlegroups.com
Hey Michael,

Please check out this forum post about adding the path to your fieldMask. It looks like you need to add the code: "operation.update_mask.paths.append('cpc_bid_micros')". You don't need to set any new value to the ad_group_criterion.cpc_bid_micros.value.
Reply all
Reply to author
Forward
0 new messages