Setting Empty Message Objects as Fields

  • Some Google Ads API message fields are defined as empty or only have optional fields, requiring specific handling to indicate the intended bidding strategy.

  • To set a bidding strategy using an empty message field (like manual_cpm), you need to copy a separate empty instance of the corresponding class onto the campaign object.

  • Nested fields within messages (like campaign.manual_cpc.enhanced_cpc_enabled) can be updated directly like normal Python object attributes.

  • When using empty message objects, ensure the field is added to the request's update_mask manually, as the field mask helper cannot automatically detect this.

In the Google Ads API some message fields are defined as empty message objects, such as campaign.manual_cpm, or they may only have optional fields that don't need to be set, for example campaign.manual_cpc. Setting these fields is important to tell the API which bidding strategy to use for the given Campaign, but it's not intuitive when the messages are empty.

When updating the campaign.name field, which is a string, we set the field by updating it directly as if it were a normal Python object attribute:

campaign.name = "Test campaign value"

campaign.manual_cpc is a nested field, meaning it contains another protobuf message and not a primitive type, like a string. You can update its fields directly as well:

campaign.manual_cpc.enhanced_cpc_enabled = True

This will tell the API that this Campaign has a bidding strategy of manual_cpc with enhanced CPC enabled.

But what if you want to use manual_cpm, which is empty? Or manual_cpc without enabling enhanced cpc? To do this you will need to copy a separate empty instance of the class onto the campaign, for example:

client = GoogleAdsClient.load_from_storage()

empty_cpm = client.get_type('ManualCpm')
client.copy_from(campaign.manual_cpm, empty_cpm)

Note how manual_cpm is specified for the campaign object:

name {
  value: "Test campaign value"
}
manual_cpm {
}

The manual_cpm field is set, but none of its fields have values. When sending request to the API that use this pattern, you can verify that you're setting the empty message object correctly by enabling logging and inspecting the request payload.

Lastly, you'll need to manually add this field to the request object's update_mask. The field mask helper has no mechanism to determine the difference between a field that's been explicitly set to an empty object, and a field that hasn't been set.

from google.api_core.protobuf_helpers import field_mask

campaign_operation.create = campaign
campaign_operation.update_mask = field_mask(None, campaign)
# Here we manually add the "manual_cpm" field
campaign_operation.update_mask.append("manual_cpm")