I have recently been doing some work for a client building an automated task in python that accesses the Google Ads API using a Service Account and got stumped by a very persistent “NOT_ADS_USER” error.

Despite the fact that we only wanted to use the API for reporting purposes (generating and downloading aggregate campaign statistics), the process Google makes you navigate to access the API is… arduous. It involves creating the Service Account (fair enough), enabling an API and generating a developer token in Google Ads, then make a DOMAIN WIDE DELEGATION to the service account! Anyway, I won’t go into detail on those steps here as the documentation for those steps is decent, but let’s look at a key step which I couldn’t find mentioned in the documentation anywhere.

Where I got stuck, and if you are reading this I guess you did too, is the that when you make your requests, you get an “NOT_ADS_USER“, “User in the cookie is not a valid Ads user.” error. It turned out my previous experience with using a service account with Domain Wide Delegation to access a GMail account (which actually makes sense) provided the key.

Basically, a Domain Wide Delegation allows a service account to impersonate a another user’s account for a specific service (e.g. their email, or in this case, their Google Ads account). However, to do this, we have to add the subject parameter when we initialize the credentials object and provide the email of a user that has access to the Google Ads account.

In short, your code in python should look something like this:

from google.oauth2.service_account import Credentials
from google.ads.googleads.client import GoogleAdsClient

SCOPES = ['https://www.googleapis.com/auth/adwords']
QUERY = ''

credentials = Credentials.from_service_account_file(PATH_TO_SERVICE_ACCOUNT_JSON, scopes=SCOPES, subject="<AN ACTUAL USER'S EMAIL HERE>")
googleads_client = GoogleAdsClient(credentials=credentials, developer_token=DEVELOPER_TOKEN, version="v7")

ga_service = googleads_client.get_service("GoogleAdsService")
response = ga_service.search(customer_id=CUSTOMER_ID, query=QUERY)

I couldn’t find any examples anywhere showing this, so hopefully I can save people some time with the above code template for python.

P.S. Google, get your act together. How can it be a 17 step process that includes making a DOMAIN WIDE DELEGATION to access a reporting API? Just to programmatically download aggregate campaign statistics, the same ones that can be downloaded by anyone from the Google Ads dashboard.