I have recently been doing some work for a client trying to access 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. Oh, and also go ahead and 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.

Where I got stuck, and I guess you did too, is the actual implementation in your code where I kept getting the “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) was the key.

You see, a domain wide delegation essentially allows a service account to access real users’ personal accounts (e.g. their emails or in this case, their Google Ads account). Having remembered that, I added the subject parameter when I initialized the credentials, providing the email of an actual user that has access to our Google Ads account.

In short, I ended up with something that looked like this:

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

SCOPES = ['https://www.googleapis.com/auth/adwords']
PATH_TO_SERVICE_ACCOUNT_JSON = ''
CUSTOMER_ID = ''
DEVELOPER_TOKEN = ''
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)

And voila, that did the trick for me. Couldn’t find any examples anywhere showing this, so hopefully I can save people some time with this.

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.