Most developers assume keyword volume data costs money. DataForSEO charges a $50 minimum deposit. Semrush is $499/month. But Google's own Keyword Planner API is completely free - it just takes more setup than it should.
This guide covers every single step in the exact order you need to do them. Follow it top to bottom and you won't miss anything.
What You Need Before Starting
- A Google account
- A Google Cloud project (free to create)
- A publicly accessible website with a privacy policy page
Part 1 - Google Ads Setup
Step 1: Create a Manager Account
A regular Google Ads account won't work. The API Center is only available to Manager Accounts (also called MCC - My Client Center). This is a free account type that sits above regular Ads accounts.
- Go to ads.google.com/home/tools/manager-accounts
- Click Create a Manager Account
- Fill in: account name (anything), primary use set to Manage my accounts, billing country, and currency
- Complete the CAPTCHA and click Submit
Note down the account ID shown at the top - it looks like XXX-XXX-XXXX. You will need it later.
Step 2: Create a Sub-Account
The Manager Account needs at least one active sub-account linked to it for Keyword Planner to work.
- Inside your Manager Account, click Accounts in the left sidebar
- Click the blue + button and select Create new account
- Fill in a name and click Create
Save this sub-account ID too. You will need both IDs when making API calls.
Step 3: Add Billing to the Sub-Account
The sub-account needs a payment method on file to be fully active. You will not be charged - the card just needs to exist.
- Switch to your sub-account using the dropdown at the top left
- Click Billing → Add payment method
- Add a card and save
Step 4: Create and Immediately Pause a Dummy Campaign
Without at least one campaign, the sub-account stays in "Setup in progress" state. Every API call returns CUSTOMER_NOT_ENABLED until you fix this.
- Click the blue + button and select Search campaign
- Fill in any dummy details - any URL, any keywords, any ad text
- Set daily budget to the minimum and click Publish
- Immediately go to Campaigns and pause it
The account is now fully active. The paused campaign will never run and you will never be charged.
Important: Keep the campaign paused permanently - do not delete it. If you delete it, the account may revert to "Setup in progress" state and break your API access again.
Part 2 - Google Cloud Setup
Step 5: Enable the Google Ads API
- Go to console.cloud.google.com and select your project
- Go to APIs & Services → Library
- Search for Google Ads API and click Enable
Step 6: Create OAuth Credentials
- Go to APIs & Services → Credentials
- Click Create Credentials → OAuth 2.0 Client ID
- Application type: Desktop app
- Copy and save your Client ID and Client Secret
Step 7: Add Yourself as a Test User
Before generating a refresh token you must add your own Gmail as a test user - otherwise Google blocks the OAuth flow with an "Access blocked" error.
- Go to APIs & Services → Branding → Audience
- Scroll down to Test users and click + Add users
- Enter the Gmail address that owns your Ads Manager Account
- Click Save
Step 8: Get a Refresh Token
Option A - OAuth Playground (no terminal needed):
- Go to developers.google.com/oauthplayground
- Click the settings gear ⚙️ and check Use your own OAuth credentials
- Enter your Client ID and Client Secret from Step 6
- In the left panel, type
adwordsand selecthttps://www.googleapis.com/auth/adwords - Click Authorize APIs and sign in with your Google account
- Click Allow on the permissions screen
- Click Exchange authorization code for tokens
- Find refresh_token in the response panel on the right and copy it
Option B - curl (terminal):
First, open this URL in your browser, sign in, and copy the authorization code shown on screen:
https://accounts.google.com/o/oauth2/auth ?client_id=YOUR_CLIENT_ID &redirect_uri=urn:ietf:wg:oauth:2.0:oob &scope=https://www.googleapis.com/auth/adwords &response_type=code &access_type=offline Then immediately run this in your terminal - the authorization code expires in minutes:
curl -X POST https://oauth2.googleapis.com/token \ -d client_id=YOUR_CLIENT_ID \ -d client_secret=YOUR_CLIENT_SECRET \ -d code=YOUR_AUTHORIZATION_CODE \ -d grant_type=authorization_code \ -d redirect_uri=urn:ietf:wg:oauth:2.0:oob Copy the refresh_token from the response. Save it - you will only see it once.
Step 9: Set Up the OAuth Consent Screen
- Go to APIs & Services → Branding
- Fill in app name, homepage URL, privacy policy URL, and developer email
- Under Authorised domains, add your domain
- Click Save
Important: The app name must be consistent with your website homepage. A mismatch causes an instant rejection during brand verification.
Step 10: Add a Google Ads API Note to Your Privacy Policy
Your privacy policy must explicitly mention Google Ads API usage. Add this to your privacy page:
This site owner uses a personal tool that accesses the Google Ads API to retrieve keyword search volume data for research purposes. This tool does not collect, store, or share any personal user data. It does not create, modify, or run any Google Ads campaigns. Step 11: Switch to In Production
- Go to the Audience tab in the OAuth consent screen
- Change publishing status from Testing to In production
- Confirm
You cannot submit for brand verification while in Testing mode. Once in production, your refresh token never expires.
Part 3 - API Access Approval
Step 12: Get Your Developer Token
- Go to ads.google.com and switch to your Manager Account
- Click Tools → API Center
- Copy and save the developer token shown on the page
Step 13: Understand the Access Levels
This is what nobody explains upfront. The Google Ads API has three tiers - and the Keyword Planner endpoint only works at Basic Access or above.
- Test - auto-granted, only works on test accounts, useless for real data
- Explorer - approved in minutes, but
generateKeywordHistoricalMetricsis not allowed - Basic - 15,000 operations/day, Keyword Planner allowed, requires brand verification
Apply for Explorer first as a stepping stone. You need it before you can apply for Basic.
Step 14: Apply for Explorer Access
- In API Center, click Apply for Basic Access
- Describe your use: I am building a personal tool that uses the Keyword Planner to retrieve search volume data for research. No ads will be created or run.
- Submit - Explorer Access is usually approved within minutes
Step 15: Submit for Brand Verification
- Go to console.cloud.google.com → APIs & Services → Branding → Verification centre
- Click Submit for verification and follow any prompts
- Wait for Google's email - typically 1 to 5 business days
Step 16: Apply for Basic Access
- Once brand verification is approved, go to ads.google.com/aw/apicenter
- Click Apply for Basic Access, use the same description, and submit
Basic Access is typically approved within a few hours of brand verification. You will receive a confirmation email.
Part 4 - Making API Calls
Step 17: Get an Access Token
Your refresh token is long-lived but the access token expires every hour. Fetch a fresh one before each session:
POST https://oauth2.googleapis.com/token Body (form-urlencoded): client_id = YOUR_CLIENT_ID client_secret = YOUR_CLIENT_SECRET refresh_token = YOUR_REFRESH_TOKEN grant_type = refresh_token Copy the access_token from the response. Valid for 60 minutes.
Step 18: Call the Keyword Planner API
POST https://googleads.googleapis.com/v25/customers/YOUR_CUSTOMER_ID:generateKeywordHistoricalMetrics Headers: Authorization: Bearer YOUR_ACCESS_TOKEN developer-token: YOUR_DEVELOPER_TOKEN login-customer-id: YOUR_MANAGER_ACCOUNT_ID Content-Type: application/json Body: { "keywords": ["keyword one", "keyword two", "keyword three"], "geoTargetConstants": ["geoTargetConstants/2840"], "language": "languageConstants/1000", "keywordPlanNetwork": "GOOGLE_SEARCH" } - Both customer IDs: digits only, no dashes
geoTargetConstants/2840= United StateslanguageConstants/1000= English- Send as many keywords as you want in one request
Step 19: Read the Response
{ "results": [ { "text": "excel practice", "keywordMetrics": { "avgMonthlySearches": 1000, "competition": "LOW" } } ] } Each result gives you avgMonthlySearches and competition (LOW, MEDIUM, or HIGH) per keyword.
Step 20: Full Working Python Example
import requests CLIENT_ID = "YOUR_CLIENT_ID" CLIENT_SECRET = "YOUR_CLIENT_SECRET" REFRESH_TOKEN = "YOUR_REFRESH_TOKEN" DEVELOPER_TOKEN = "YOUR_DEVELOPER_TOKEN" CUSTOMER_ID = "YOUR_SUB_ACCOUNT_ID" LOGIN_CUSTOMER_ID = "YOUR_MANAGER_ACCOUNT_ID" def get_access_token(): res = requests.post( "https://oauth2.googleapis.com/token", data={ "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "refresh_token": REFRESH_TOKEN, "grant_type": "refresh_token", } ) return res.json()["access_token"] def get_keyword_volumes(keywords): access_token = get_access_token() url = f"https://googleads.googleapis.com/v25/customers/{CUSTOMER_ID}:generateKeywordHistoricalMetrics" headers = { "Authorization": f"Bearer {access_token}", "developer-token": DEVELOPER_TOKEN, "login-customer-id": LOGIN_CUSTOMER_ID, "Content-Type": "application/json", } body = { "keywords": keywords, "geoTargetConstants": ["geoTargetConstants/2840"], "language": "languageConstants/1000", "keywordPlanNetwork": "GOOGLE_SEARCH", } res = requests.post(url, headers=headers, json=body) results = {} for item in res.json().get("results", []): kw = item["text"] metrics = item.get("keywordMetrics", {}) results[kw] = { "volume": metrics.get("avgMonthlySearches", 0), "competition": metrics.get("competition", ""), } return results keywords = ["excel practice", "learn excel", "ai code assistant"] volumes = get_keyword_volumes(keywords) for kw, data in volumes.items(): print(f"{kw}: {data['volume']} searches/month, competition: {data['competition']}") Using This API in n8n
If you are calling this API from n8n, there is one critical gotcha: Code nodes do not support fetch, axios, or $http - all three are blocked. Use HTTP Request nodes instead and wire them like this:
- Code node - collect and prepare your keywords array
- HTTP Request node - POST to the token endpoint to get an access token
- HTTP Request node - POST to the keyword API using the token from the previous node
- Code node - parse the response and map volumes back to your rows
Common Errors and Fixes
- API Center not available - you are in a regular Ads account. Create a Manager Account.
- CUSTOMER_NOT_ENABLED - sub-account has no billing or campaign. Add both. Do not delete the dummy campaign after pausing.
- DEVELOPER_TOKEN_NOT_APPROVED - Explorer access cannot use Keyword Planner. Apply for Basic Access.
- Basic Access rejected - brand not yet verified. Complete brand verification first.
- Brand verification rejected - app name doesn't match your homepage. Make them consistent.
- Access blocked on OAuth Playground - your email not added as a test user. Add it under Audience → Test users.
- Cannot submit for verification - app still in Testing mode. Switch to In Production first.
- Refresh token expires after 7 days - app in Testing mode. Switch to In Production.
- 404 on API endpoint - wrong URL path. Colon goes directly after customer ID:
customers/{id}:generateKeyword... - fetch is not defined in n8n - Code nodes block fetch/axios/$http. Use HTTP Request nodes instead.
Summary - Everything You Need
By the end you should have saved all six of these:
- Manager Account ID - from ads.google.com
- Sub-account ID - from ads.google.com
- Developer Token - from API Center
- Client ID - from Google Cloud Console
- Client Secret - from Google Cloud Console
- Refresh Token - from OAuth Playground or curl
Basic Access gives you 15,000 free API operations per day. One request handles as many keywords as you want. The refresh token never expires in production mode.
The whole process takes about half a day the first time - mostly waiting on verification emails. But every error has a specific fix, and the end result is real keyword volume data that most developers assume they have to pay for.