Updates Using Field Masks

In the Google Ads API, updates are done using a field mask. The field mask lists all the fields you intend to change with the update, and any specified fields that aren't in the field mask are ignored, even if sent to the server.

FieldMaskUtil

The recommended way to generate field masks is using our built-in field mask utility which hides a lot of the specific details and lets you generate field masks automatically by monitoring the changes you make to the entity's fields.

Here's how you could generate a field mask for updating a campaign:

campaign = client.resource.campaign
campaign.resource_name = client.path.campaign(customer_id, campaign_id)

mask = client.field_mask.with campaign do
  campaign.status = :PAUSED
  campaign.network_settings = client.resource.network_settings do |ns|
    ns.target_search_network = false
  end
end

The code first creates an empty Campaign object, then sets its resource name to inform the API of the campaign being updated.

This example uses the client.field_mask.with method on the campaign to begin the block encompassing the updates. At the end of this block, the utility compares the current status of the campaign after the block with the initial status of the campaign before the block, and automatically produces a field mask enumerating the changed fields. You can provide that field mask to the operation when constructing it for the mutate call as follows:

operation = client.operation.campaign
operation.update = campaign
operation.update_mask = mask

This method is recommended when you're making a complicated operation and want fine control over every step. However, for most cases, you can use the simpler Ruby library utility:

operation = client.operation.update_resource.campaign do |c|
  c.status = :PAUSED
  c.network_settings = client.resource.network_settings do |ns|
    ns.target_search_network = false
  end
end

This method automatically creates a new empty campaign resource, constructs the field mask based on changes you make within the block, builds the update operation, and returns the final operation with update and update_mask already populated. You can also pass a campaign to the campaign method to specify the starting state of the campaign as well. This pattern works for all resources that support the update operation.

Manually creating a mask

To create a field mask from scratch, without using any library utilities, you would first create a Google::Protobuf::FieldMask, then make an array populated with the names of all the fields you intend to change, and finally assign the array to the field mask's path field.

mask = Google::Protobuf::FieldMask.new
mask.path = ["status", "name"]

Updating message fields and their subfields

MESSAGE fields can have subfields (such as MaximizeConversions which has three: target_cpa_micros, cpc_bid_ceiling_micros, and cpc_bid_floor_micros), or they can have none at all (such as ManualCpm).

Message fields with no defined subfields

When updating a MESSAGE field that is not defined with any subfields, use the FieldMaskUtil to generate a field mask, as presented earlier.

Message fields with defined subfields

When updating a MESSAGE field that is defined with subfields without explicitly setting any of the subfields on that message, you must manually add each of the mutable MESSAGE subfields to the FieldMask, similar to the earlier example that created a field mask from scratch.

One common example is updating a campaign's bidding strategy without setting any of the fields on the new bidding strategy. The following example demonstrates how to update a campaign to use the MaximizeConversions bidding strategy without setting any of the subfields on the bidding strategy.

For this example, using the built-in comparison of the FieldMaskUtil does not achieve the intended goal.

The following code generates a field mask that includes maximize_conversions. However, the Google Ads API doesn't allow this behavior in order to prevent accidentally clearing fields and produces a FieldMaskError.FIELD_HAS_SUBFIELDS error.

# Creates a campaign with the proper resource name.
campaign = client.resource.campaign do |c|
  c.resource_name = client.path.campaign(customer_id, campaign_id)
end

# Update the maximize conversions field within the update block, so it's
# captured in the field mask
operation = client.operation.update_resource.campaign(campaign) do |c|
  c.maximize_conversions = client.resource.maximize_conversions
end

# Sends the operation in a mutate request that will result in a
# FieldMaskError.FIELD_HAS_SUBFIELDS error because empty MESSAGE fields cannot
# be included in a field mask.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation],
)

The following code demonstrates how to properly update a campaign to use the MaximizeConversions bidding strategy without setting any of its subfields.

# Create the operation directly from the campaign's resource name. Don't do
# anything in the block so that the field mask is empty. You could modify other
# fields in this block, just not the message field that is intended to have a
# blank subfield. We'll add that below.
campaign_resource_name = client.path.campaign(customer_id, campaign_id)
operation = client.operation.update_resource.campaign(campaign_resource_name) {}

# Manually add the maximize conversions subfield to the field mask so the API
# knows to clear it.
operation.update_mask.paths << "maximize_conversions.target_cpa_micros"

# This operation succeeds.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation],
)

Clearing fields

Some fields can be explicitly cleared. Similar to the previous example, you must explicitly add these fields to the field mask. For example, assume you have a campaign that uses a MaximizeConversions bidding strategy and that the target_cpa_micros field is set with a value that is greater than 0.

The following code runs; however, the maximize_conversions.target_cpa_micros won't be added to the field mask and so no changes are made to the target_cpa_micros field:

# Create a campaign object representing the campaign you want to change.
campaign = client.resource.campaign do |c|
  c.resource_name = client.path.campaign(customer_id, campaign_id)
end

# The field mask in this operation will include 'maximize_conversions',
# but not 'maximize_conversions.target_cpa_micros', so it will result in an
# error.
operation = client.operation.update_resource.campaign(campaign) do |c|
  c.maximize_conversions = client.resource.maximize_conversions do |mc|
    mc.target_cpa_micros = 0
  end
end

# Operation will fail since field mask is incorrect.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation],
end

The following code demonstrates how to properly clear the target_cpa_micros field on the MaximizeConversions bidding strategy.

# Create a campaign including the maximize conversions fields right away, since
# we're going to manually add them to the field mask.
campaign = client.resource.campaign do |c|
  c.resource_name = client.path.campaign(customer_id, campaign_id)
  c.maximize_conversions = client.resource.maximize_conversions do |mc|
    mc.target_cpa_micros = 0
  end
end

# Create the operation with an empty field mask. You may add a block here with
# other changes that will automatically get added to the field mask.
operation = client.operation.update_resource.campaign(campaign) {}

# Add the field to the field mask so the API knows to clear it.
operation.update_mask.paths << 'maximize_conversions.target_cpa_micros'

# Operation will succeed since we specified the correct field mask.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation],
end

Note that the "incorrect" code does work as intended for fields that are defined as optional in the Google Ads API protocol buffers. But since the target_cpa_micros is not an optional field, the "incorrect" code does not update the bidding strategy to clear the target_cpa field.