Change Event service

Change Event provides specific field-by-field breakdowns of exactly what changed in your account. When reporting on a create operation, all new field values are returned, and when reporting on an update operation, both the new and the old values are returned so you can get a complete picture of individual changes.

Additionally, you can see which interface was used to make the change (such as the Google Ads API or the web UI), as well as what user made the change (assuming that information would be visible in the Change History of the web UI as well).

Change Event types

The Change Event service currently tracks changes of the following resource types:

Resource type Value
Ad AD
Ad group AD_GROUP
Ad group bid modifier AD_GROUP_BID_MODIFIER
Ad group criterion AD_GROUP_CRITERION
Campaign CAMPAIGN
Campaign budget CAMPAIGN_BUDGET
Campaign criterion CAMPAIGN_CRITERION

Getting changes

The list of changes must be filtered by date, and the query must include a LIMIT clause. The date range must be within the past 30 days. The limit must be at most 10,000 rows. If you're interested in more than 10,000 results, make a note of the timestamp of the last entry in the returned result set, and then set your date range on the following query to start after that time. This will allow you to continue processing where you left off.

The following example demonstrates how to fetch change events and process them, including determining who made the change, which interface they used to make the change, and the old and new values of each field in the change:

Ruby

def get_value_from_path(path, object)
  path.split(".").inject(object) {|obj, key| obj.send(key)}
end

client = Google::Ads::GoogleAds::GoogleAdsClient.new

# The LIMIT clause is required for the change_event resource.
# The maximum size is 10000, but a low limit was set here for demonstrative
# purposes.
# The WHERE clause on change_date_time is also required. It must specify a
# window of at most 30 days within the past 30 days.
query = <<~QUERY
  SELECT
    change_event.resource_name,
    change_event.change_date_time,
    change_event.change_resource_name,
    change_event.user_email,
    change_event.client_type,
    change_event.change_resource_type,
    change_event.old_resource,
    change_event.new_resource,
    change_event.resource_change_operation,
    change_event.changed_fields
  FROM
    change_event
  WHERE
    change_event.change_date_time <= '#{(Date.today + 1).to_s}'
    AND change_event.change_date_time >= '#{(Date.today - 14).to_s}'
  ORDER BY
    change_event.change_date_time DESC
  LIMIT 5
QUERY

response = client.service.google_ads.search(
  customer_id: customer_id,
  query: query,
  # The page size is superfluous with the default limit set above, but it's
  # shown here since it's a good practice to use a reasonable page size when
  # you set a higher limit.
  page_size: PAGE_SIZE
)

response.each do |row|
  event = row.change_event
  old_resource, new_resource = case event.change_resource_type
  when :AD
    [event.old_resource.ad, event.new_resource.ad]
  when :AD_GROUP
    [event.old_resource.ad_group, event.new_resource.ad_group]
  when :AD_GROUP_CRITERION
    [event.old_resource.ad_group_criterion, event.new_resource.ad_group_criterion]
  when :AD_GROUP_BID_MODIFIER
    [event.old_resource.ad_group_bid_modifier, event.new_resource.ad_group_bid_modifier]
  when :CAMPAIGN
    [event.old_resource.campaign, event.new_resource.campaign]
  when :CAMPAIGN_BUDGET
    [event.old_resource.campaign_budget, event.new_resource.campaign_budget]
  when :CAMPAIGN_CRITERION
    [event.old_resource.campaign_criterion, event.new_resource.campaign_criterion]
  else
    puts "Unknown change_resource_type #{event.change_resource_type}."
    next
  end
  puts "On #{event.change_date_time}, user #{event.user_email} used interface " \
    "#{event.client_type} to perform a(n) #{event.resource_change_operation} " \
    "operation on a #{event.change_resource_type} with resource name " \
    "#{event.change_resource_name}."
  if [:UPDATE, :CREATE].include? event.resource_change_operation
    event.changed_fields.paths.each do |changed_field|
      new_value = get_value_from_path(changed_field, new_resource)
      if :CREATE == event.resource_change_operation
        puts "\t#{changed_field} set to '#{new_value}'."
      else
        old_value = get_value_from_path(changed_field, old_resource)
        puts "\t#{changed_field} changed from '#{old_value}' to '#{new_value}'."
      end
    end
  end
end
   

Keeping synchronized locally

If your goal is to get a current picture of your account and all its fields, you can use the change status to get a list of change resources and then query each of them to get its current state. However, if your goal is to get a complete picture of exact changes within a given window, use Change Event as outlined above.

Though changes made through the API or the web UI are recorded by Change Event service, there are some other ways changes can be made that are not. So Change Status service is still the best way to get a comprehensive view of what changes have been made in your account.