Posts under category Google

I have two issues:

I'm calling G-Ads API to bulk remove ads (code)

for error_detail in error_details:             # Retrieve an instance of the google_ads_failure class from the client             failure_message = gAdsServiceWrapper.client.get_type("google_ads_failure")             # Parse the string into a google_ads_failure message instance.             # To access class-only methods on the message we retrieve its type.             google_ads_failure = type(failure_message)             failure_object = google_ads_failure.deserialize(error_detail.value)             for error in failure_object.errors:                 # Construct and print a string that details which element in                 # the above ad_group_operations list failed (by index number)                 # as well as the error message and error code.                 print("A partial failure at index "                       f"{error.location.field_path_elements[0].index} occurred "                       f"\nError message: {error.message}\nError code: "                       f"{error.error_code}")                 index_array.append(error.location.field_path_elements[0].index)                 error_array.append({"error_message": error.message, "error_code": error.error_code}) 
  1. I get a partial error
  2. And the code fails to parse it (taken form the official website)

My terminal shows:

Partial failures occurred. Details will be shown below.

Traceback (most recent call last):   File "D:\projects\bowling\venv\lib\site-packages\google\ads\googleads\client.py", line 426, in get_type     message_class = getattr(type_classes, name)   File "D:\projects\bowling\venv\lib\site-packages\google\ads\googleads\v8\__init__.py", line 1753, in __getattr__     raise AttributeError(f"unknown type {name!r}.") AttributeError: unknown type 'google_ads_failure'. During handling of the above exception, another exception occurred: Traceback (most recent call last):   File "D:\projects\bowling\src\main.py", line 535, in <module>     main(args.top_id)   File "D:\projects\bowling\src\main.py", line 141, in main     removed_ads_count = remove_disapproved_ads_for_account(account)   File "D:\projects\bowling\src\main.py", line 206, in remove_disapproved_ads_for_account     remove_ads(ad_removal_operations, ads_to_remove_json, account_id)   File "D:\projects\bowling\src\main.py", line 300, in remove_ads     index_array, error_array = _print_results(response_chunk)   File "D:\projects\bowling\src\main.py", line 439, in _print_results     failure_message = gAdsServiceWrapper.client.get_type("google_ads_failure")   File "D:\projects\bowling\venv\lib\site-packages\google\ads\googleads\client.py", line 428, in get_type     raise ValueError( ValueError: Specified type 'google_ads_failure' does not exist in Google Ads API v8 

I'm trying to access Google Ads campaing reports from Python folowing this tutorial.

I've requested my Developer Token with Basic Access. I think it has enough privileges to execute the script. I Can see my token active when I go to "API Center" in google ads.

I've created a project in google cloud and an Oauth Token.

In google Cloud:

  • Created a new project
  • Activated the Google Ads API.
  • When I go to Manage-> Credentials I see that the Oauth token is compatible with that API.
  • I have successfully created a refresh token.

I'm using this script as proof of concept:

import os import json import sys from google.ads.google_ads.errors import GoogleAdsException # Put an account id to download stats from. Note: not MCC, no dash lines CUSTOMER_ID = "xxxxxxxxxx" def get_account_id(account_id, check_only=False):     """     Converts int to str, checks if str has dashes. Returns 10 chars str or raises error     :check_only - if True, returns None instead of Error     """     if isinstance(account_id, int) and len(str(account_id)) == 10:         return str(account_id)     if isinstance(account_id, str) and len(account_id.replace("-", "")) == 10:         return account_id.replace("-", "")     if check_only:         return None     raise ValueError(f"Couldn't recognize account id from {account_id}") def micros_to_currency(micros):     return micros / 1000000.0 def main(client, customer_id):          ga_service = client.get_service("GoogleAdsService")#     , version="v5")     query = """         SELECT           campaign.id,           campaign.name,           ad_group.id,           ad_group.name,           ad_group_criterion.criterion_id,           ad_group_criterion.keyword.text,           ad_group_criterion.keyword.match_type,           metrics.impressions,           metrics.clicks,           metrics.cost_micros         FROM keyword_view         WHERE           segments.date DURING LAST_7_DAYS           AND campaign.advertising_channel_type = 'SEARCH'           AND ad_group.status = 'ENABLED'           AND ad_group_criterion.status IN ('ENABLED', 'PAUSED')         ORDER BY metrics.impressions DESC         LIMIT 50"""     # Issues a search request using streaming.     response = ga_service.search_stream(customer_id, query) #THIS LINE GENERATES THE ERROR     keyword_match_type_enum = client.get_type(         "KeywordMatchTypeEnum"     ).KeywordMatchType     try:         for batch in response:             for row in batch.results:                 campaign = row.campaign                 ad_group = row.ad_group                 criterion = row.ad_group_criterion                 metrics = row.metrics                 keyword_match_type = keyword_match_type_enum.Name(                     criterion.keyword.match_type                 )                 print(                     f'Keyword text "{criterion.keyword.text}" with '                     f'match type "{keyword_match_type}" '                     f"and ID {criterion.criterion_id} in "                     f'ad group "{ad_group.name}" '                     f'with ID "{ad_group.id}" '                     f'in campaign "{campaign.name}" '                     f"with ID {campaign.id} "                     f"had {metrics.impressions} impression(s), "                     f"{metrics.clicks} click(s), and "                     f"{metrics.cost_micros} cost (in micros) during "                     "the last 7 days."                 )     except GoogleAdsException as ex:         print(             f'Request with ID "{ex.request_id}" failed with status '             f'"{ex.error.code().name}" and includes the following errors:'         )         for error in ex.failure.errors:             print(f'\tError with message "{error.message}".')             if error.location:                 for field_path_element in error.location.field_path_elements:                     print(f"\t\tOn field: {field_path_element.field_name}")         sys.exit(1) if __name__ == "__main__":     # credentials dictonary     creds = {"google_ads": "googleads.yaml"}     if not os.path.isfile(creds["google_ads"]):         raise FileExistsError("File googleads.yaml doesn't exists. ")     resources = {"config": "config.json"}     # This logging allows to see additional information on debugging     import logging     logging.basicConfig(level=logging.INFO, format='[%(asctime)s - %(levelname)s] %(message).5000s')     logging.getLogger('google.ads.google_ads.client').setLevel(logging.DEBUG)     # Initialize the google_ads client     from google.ads.google_ads.client import GoogleAdsClient     gads_client = GoogleAdsClient.load_from_storage(creds["google_ads"])     id_to_load = get_account_id(CUSTOMER_ID)      main(gads_client, id_to_load) 
  • I've changed CUSTOMER_ID to the account number that appears on the upper left corner
  • I've created a googleads.yaml and I've loaded the aforementioned information.

When I execute the script I get this error:

Traceback (most recent call last):  File "download_keywords_from_account.py", line 138, in <module>    main(gads_client, id_to_load)  File "download_keywords_from_account.py", line 70, in main    response = ga_service.search_stream(customer_id, query)  File "google/ads/google_ads/v6/services/google_ads_service_client.py", line 366, in search_stream    return self._inner_api_calls['search_stream'](request, retry=retry, timeout=timeout, metadata=metadata)  File google/api_core/gapic_v1/method.py", line 145, in __call__    return wrapped_func(*args, **kwargs)  File "google/api_core/retry.py", line 281, in retry_wrapped_func    return retry_target(  File "google/api_core/retry.py", line 184, in retry_target    return target()  File "google/api_core/timeout.py", line 214, in func_with_timeout    return func(*args, **kwargs)  File "google/api_core/grpc_helpers.py", line 152, in error_remapped_callable    six.raise_from(exceptions.from_grpc_error(exc), exc)  File "<string>", line 3, in raise_from google.api_core.exceptions.PermissionDenied: 403 Request had insufficient authentication scopes

The googleads.yaml file looks like this:

  #############################################################################   # Required Fields                                                           #   #############################################################################   developer_token: {developer token as seen in google ads -> tools -> api center}   #############################################################################   # Optional Fields                                                           #   #############################################################################   login_customer_id: {Id from the top left corner in google ads, only numbers}   # user_agent: INSERT_USER_AGENT_HERE   # partial_failure: True   validate_only: False   #############################################################################   # OAuth2 Configuration                                                      #   # Below you may provide credentials for either the installed application or #   # service account flows. Remove or comment the lines for the flow you're    #   # not using.                                                                #   #############################################################################   # The following values configure the client for the installed application   # flow.   client_id: {Oauth client id taken from gcloud -> api -> credentials} ends with apps.googleusercontent.com   client_secret: {got it while generating the token}   refresh_token:  1//0hr.... made with generate_refresh_token.py    # The following values configure the client for the service account flow.   path_to_private_key_file: ads.json   # delegated_account: INSERT_DOMAIN_WIDE_DELEGATION_ACCOUNT   #############################################################################   # ReportDownloader Headers                                                  #   # Below you may specify boolean values for optional headers that will be    #   # applied to all requests made by the ReportDownloader utility by default.  #   #############################################################################   # report_downloader_headers:     # skip_report_header: False     # skip_column_header: False     # skip_report_summary: False     # use_raw_enum_values: False 

NOTES:

The file ads.json contains the private key downloaded from the credentials page in gcloud.

I've seen some posts on this issue but none of them are Python + GoogleADs and I couldn't find a solution there either.

I have also tried other Python + GoogleAds examples getting the same error. This makes me think that I must be configuring something wrong in gcloud / google ads. But I don't understand what.

Please help me make the query I'm really stuck.

Thanks a lot!

I am having a hard time to find a documentation for web conversion tracking for Google Ads.

I would like to understand more about the HTTP POST request that is sent to Google. I can see there is a good documentation for mobile apps: https://developers.google.com/app-conversion-tracking/api/request-response-specs?hl=en#conversion_tracking_request

Is there similar documentation for web? I would like to understand more how i could send conversions to Google creating manually my HTTP request.

I am aware of the Offline conversions API (https://developers.google.com/google-ads/api/docs/samples/upload-offline-conversion), but it doesn't support the new parameters as wbraid

We are using the BigQuery Data Transfer Service that is based on the AdWords API, but we're missing some of the campaigns. If we write a custom transfer for Google Ads we can get around the issue, but was wondering if there is a timeline yet for a Google Ads transfer seeing as Adwords is being discontinued in April 2022.

Just trying to work out whether to write something custom or hang in there if the new transfer service is imminent. Is there any news on this please?