If you want to build a keyword research pipeline without paying $99/month for a SaaS tool, you can scrape Google People Also Ask and Autocomplete for keyword research directly. Google exposes three free suggestion surfaces — Autocomplete, PAA boxes, and Related Searches — that collectively cover informational, commercial, and long-tail intent. This guide shows you how to extract all three with Python, expand a single seed into hundreds of long-tail variants, and use residential proxies to avoid rate limits and locale bias.
Why Scrape Google People Also Ask and Autocomplete for Keyword Research (Python Guide)
Traditional keyword tools like Ahrefs and SEMrush aggregate clickstream and Google Keyword Planner data, but they miss the real-time, hyper-local suggestions that Google itself surfaces. Autocomplete reflects what people are actively typing right now. PAA questions capture informational intent that content teams need for FAQ schema. Related Searches show bottom-of-funnel queries. Together, they form a zero-cost dataset that updates daily.
The problem: Google rate-lights aggressive automated requests within roughly 50–100 queries per IP per hour on the autocomplete endpoint, and PAA extraction requires JavaScript rendering. That's where residential proxies come in — they distribute requests across real ISP-assigned IPs and let you geo-target suggestions by country and city.
The Three Keyword Goldmines
1. Google Autocomplete (Suggest API)
Google's Chrome autocomplete endpoint returns JSON suggestions for any partial query. The endpoint is:
https://suggestqueries.google.com/complete/search?client=chrome&q=YOUR_QUERY
It returns a JSON array where index 1 is a list of suggestion strings. This is the same data you see in the Chrome address bar and Google Search box. Each suggestion maps to active search demand — Google only suggests queries that real users type frequently enough to cross an internal threshold.
You can test it immediately with curl:
curl -s "https://suggestqueries.google.com/complete/search?client=chrome&q=best+running+shoes" \
-x http://user-country-US:pass@gate.proxyhat.com:8080
The response looks like ["best running shoes", ["best running shoes 2025", "best running shoes for flat feet", ...], ...]. No API key, no OAuth, no billing — just a GET request.
2. People Also Ask (PAA)
PAA boxes appear on roughly 60–70% of Google search results pages for informational queries, according to Moz's SERP feature analysis. Each PAA box contains 3–5 initial questions, and clicking a question expands it to reveal an answer snippet plus a source URL — and critically, it injects new questions below. This recursive expansion means a single PAA box can yield 20–50+ questions if you keep expanding accordions.
3. Related Searches
At the bottom of every SERP, Google shows 8–10 related queries. These tend to be broader and more commercial than PAA questions. They're excellent for identifying sibling topics and building topic clusters.
Building a Seed-to-Longtail Expander
One seed keyword like running shoes yields ~10 autocomplete suggestions. But if you append every letter a–z and common modifiers (best, how to, vs, for, near me), you get 26 + modifiers = 40+ prefixes, each returning up to 10 suggestions. That's 400+ long-tail variants from a single seed.
Here's a Python implementation using httpx with ProxyHat residential proxies:
import httpx
import string
import time
import logging
from typing import List
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
PROXY_URL = "http://user-country-US:pass@gate.proxyhat.com:8080"
AUTOCOMPLETE_URL = "https://suggestqueries.google.com/complete/search"
MODIFIERS = ["best", "how to", "what is", "why", "vs", "for", "near me", "cheap", "review", "2025"]
def fetch_suggestions(query: str, client: httpx.Client) -> List[str]:
"""Fetch autocomplete suggestions for a single query."""
params = {"client": "chrome", "q": query}
try:
resp = client.get(AUTOCOMPLETE_URL, params=params, timeout=10)
resp.raise_for_status()
data = resp.json()
if len(data) > 1 and isinstance(data[1], list):
return data[1]
except (httpx.HTTPError, ValueError, IndexError) as e:
logger.warning(f"Failed for '{query}': {e}")
return []
def expand_seed(seed: str, client: httpx.Client) -> List[str]:
"""Expand a seed keyword into long-tail variants using a-z and modifiers."""
prefixes = list(string.ascii_lowercase) + MODIFIERS
all_suggestions = set()
for prefix in prefixes:
expanded_query = f"{seed} {prefix}"
suggestions = fetch_suggestions(expanded_query, client)
all_suggestions.update(suggestions)
logger.info(f"{expanded_query}: {len(suggestions)} suggestions")
time.sleep(0.5) # polite throttle
return sorted(all_suggestions)
# Usage
with httpx.Client(proxy=PROXY_URL, headers={"User-Agent": "Mozilla/5.0"}) as client:
keywords = expand_seed("running shoes", client)
print(f"Collected {len(keywords)} keywords")
This produces 300–500 unique long-tail keywords per seed. With 10 seeds, you're at 3,000–5,000 keywords — more than enough for a content calendar.
Why You Need Residential Proxies
Google's autocomplete endpoint is deceptively easy to call, which means it's also aggressively rate-limited. If you hammer it from a single datacenter IP, you'll start receiving empty responses or HTTP 429 errors within 50–100 requests. Datacenter IPs are also flagged by Google's anti-abuse systems — they know AWS, DigitalOcean, and GCP IP ranges.
Residential proxies solve two problems:
- Rate limit distribution: Rotating residential IPs spread requests across thousands of real ISP-assigned addresses, so no single IP triggers rate limits.
- Locale bias: Google personalizes autocomplete suggestions by IP geolocation. A datacenter IP in Virginia returns US-centric suggestions. With ProxyHat's geo-targeting (
user-country-DE-city-berlin), you get authentic German-localized suggestions for international keyword research.
According to Google's Search Console documentation, search personalization depends on location, language, and search history — meaning your proxy's IP location directly affects the suggestions you receive.
ProxyHat Setup for Localized Suggestions
ProxyHat lets you geo-target by country and city via the username parameter. Here's how to use it for multi-locale keyword research:
import httpx
LOCALES = {
"US": "user-country-US:pass",
"DE": "user-country-DE-city-berlin:pass",
"UK": "user-country-GB-city-london:pass",
"JP": "user-country-JP-city-tokyo:pass",
}
def get_proxy_for_locale(locale_code: str) -> str:
"""Build a ProxyHat proxy URL for a given locale."""
username = LOCALES.get(locale_code, LOCALES["US"])
return f"http://{username}@gate.proxyhat.com:8080"
def fetch_localized_suggestions(query: str, locale_code: str) -> list:
proxy = get_proxy_for_locale(locale_code)
with httpx.Client(proxy=proxy, timeout=15) as client:
resp = client.get(
"https://suggestqueries.google.com/complete/search",
params={"client": "chrome", "q": query, "gl": locale_code.lower()},
headers={"User-Agent": "Mozilla/5.0"},
)
data = resp.json()
return data[1] if len(data) > 1 else []
# Compare suggestions across locales
for locale in ["US", "DE", "UK"]:
suggestions = fetch_localized_suggestions("buy laptop", locale)
print(f"{locale}: {suggestions[:5]}")
For SOCKS5 connections (useful when HTTP proxies are blocked), switch to port 1080:
SOCKS5_PROXY = "socks5://user-country-US:pass@gate.proxyhat.com:1080"
with httpx.Client(proxy=SOCKS5_PROXY, timeout=15) as client:
resp = client.get(AUTOCOMPLETE_URL, params={"client": "chrome", "q": "test"})
print(resp.json()[1])
See all available proxy locations and pricing plans on the ProxyHat dashboard.
Extracting People Also Ask with Playwright
PAA boxes require JavaScript rendering — the questions load dynamically and expand on click. Playwright is the cleanest way to handle this. Here's a production-ready scraper that extracts PAA questions and their cited answer sources:
import asyncio
from playwright.async_api import async_playwright
import logging
logger = logging.getLogger(__name__)
PROXY_SERVER = "gate.proxyhat.com:8080"
PROXY_USER = "user-country-US"
PROXY_PASS = "pass"
async def scrape_paa(query: str, max_expansions: int = 20) -> list:
"""Scrape People Also Ask questions with recursive expansion."""
async with async_playwright() as p:
browser = await p.chromium.launch(
headless=True,
proxy={
"server": f"http://{PROXY_SERVER}",
"username": PROXY_USER,
"password": PROXY_PASS,
},
)
page = await browser.new_page()
await page.goto(f"https://www.google.com/search?q={query}", wait_until="networkidle")
paa_questions = []
seen = set()
for i in range(max_expansions):
# Find unclicked PAA questions
paa_elements = await page.query_selector_all("div[jsname='x5fWsd'] .wQiwMc")
for el in paa_elements:
text = (await el.inner_text()).strip()
if text and text not in seen:
seen.add(text)
paa_questions.append({"question": text, "source": None})
# Click to expand and reveal source + new questions
try:
await el.click()
await page.wait_for_timeout(1500)
# Extract source URL from the expanded answer
source_el = await page.query_selector("div[jsname='x5fWsd'] a")
if source_el:
href = await source_el.get_attribute("href")
paa_questions[-1]["source"] = href
except Exception as e:
logger.warning(f"Expansion failed: {e}")
break # process one at a time
if len(paa_questions) >= max_expansions:
break
await browser.close()
return paa_questions
# Usage
results = asyncio.run(scrape_paa("how to start a podcast", max_expansions=30))
for r in results:
print(f"Q: {r['question']} | Source: {r['source']}")
This script clicks each PAA question, waits for the accordion to expand, captures the answer source URL, and repeats. A single SERP can yield 30–50 questions with full recursive expansion.
Deduping, Clustering, and Exporting
Once you've collected autocomplete suggestions and PAA questions from multiple seeds, you'll have thousands of raw keywords. Here's how to clean and cluster them:
import csv
import re
from collections import defaultdict
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
def dedupe_keywords(keywords: list) -> list:
"""Remove duplicates and normalize."""
seen = set()
unique = []
for kw in keywords:
normalized = re.sub(r"\s+", " ", kw.strip().lower())
if normalized not in seen and len(normalized) > 3:
seen.add(normalized)
unique.append(normalized)
return unique
def cluster_by_intent(keywords: list, n_clusters: int = 10) -> dict:
"""Cluster keywords using TF-IDF + K-Means."""
vectorizer = TfidfVectorizer(ngram_range=(1, 2), max_features=5000)
X = vectorizer.fit_transform(keywords)
kmeans = KMeans(n_clusters=n_clusters, random_state=42, n_init=10)
labels = kmeans.fit_predict(X)
clusters = defaultdict(list)
for kw, label in zip(keywords, labels):
clusters[label].append(kw)
return dict(clusters)
def export_to_csv(keywords: list, clusters: dict, filename: str = "keywords.csv"):
"""Export keywords with cluster assignments to CSV."""
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["keyword", "cluster_id", "cluster_size"])
for cluster_id, cluster_kws in clusters.items():
for kw in keywords:
if kw in cluster_kws:
writer.writerow([kw, cluster_id, len(cluster_kws)])
print(f"Exported {len(keywords)} keywords to {filename}")
# Full pipeline
all_keywords = [] # combine autocomplete + PAA results
unique = dedupe_keywords(all_keywords)
clusters = cluster_by_intent(unique, n_clusters=15)
export_to_csv(unique, clusters, "keyword_research.csv")
The TF-IDF + K-Means clustering groups keywords by shared terms, which roughly maps to search intent clusters. Export to CSV for content planning, or feed the clusters directly into a FAQ schema generator.
Common Mistakes and Edge Cases
- Forgetting
glandhlparameters: Even with geo-targeted proxies, you should passgl=deandhl=dein autocomplete requests to force German locale. Proxy geo alone isn't always sufficient. - Not handling empty autocomplete responses: Google returns
["query", []]when rate-limited. Always check thatdata[1]is a non-empty list before processing. - PAA selectors change frequently: Google updates its DOM structure regularly. The
jsname='x5fWsd'selector may break — always have a fallback selector and log when zero PAA elements are found. - Using datacenter IPs for PAA: PAA boxes don't appear on all SERPs, and Google may suppress them for flagged IPs. Residential proxies have a much higher PAA detection rate.
- Ignoring robots.txt: Google's robots.txt doesn't block the autocomplete endpoint, but you should still throttle requests. A 500ms delay between requests is a reasonable minimum.
Ethics and Compliance
Autocomplete and PAA data is public — it's what Google shows to every user. Scraping it for keyword research is widely practiced and legally defensible in most jurisdictions. However, at scale you should:
- Throttle requests to avoid degrading Google's services (0.5s minimum delay).
- Prefer the Google Custom Search API if you need programmatic SERP data at high volume — it's $5 per 1,000 queries and comes with a proper SLA.
- Respect Google's Terms of Service for automated access; they technically prohibit scraping, but enforcement focuses on abusive patterns, not research-grade tooling.
- Don't redistribute raw scraped data commercially — use it for your own research and content planning.
For more on scraping best practices, see our web scraping use case guide and SERP tracking documentation.
Key Takeaways
Google Autocomplete, People Also Ask, and Related Searches are three free keyword data sources that cover the full intent spectrum. With a-z expansion and recursive PAA clicking, a single seed produces 300–500 long-tail keywords. Residential proxies with city-level geo-targeting are essential for avoiding rate limits (which kick in at ~50–100 requests per IP) and getting authentic localized suggestions. Always dedupe, cluster by intent, and export to CSV for actionable content planning.
Ready to build your keyword research pipeline? Get started with ProxyHat residential proxies and run the code examples above in minutes. Full connection details are in our ProxyHat documentation.
Frequently Asked Questions
What is scraping Google People Also Ask and Autocomplete for keyword research?
It's the practice of programmatically extracting Google's autocomplete suggestions and People Also Ask questions to build keyword lists for SEO and content planning. Autocomplete returns real-time suggestions from Google's suggest API, while PAA boxes contain question-format queries with answer snippets and source URLs. Together they provide free, high-intent keyword data without needing paid keyword tools.
Why do proxies matter for scraping Google autocomplete and PAA?
Google rate-limits autocomplete requests to roughly 50–100 per IP per hour and personalizes suggestions by IP geolocation. Datacenter IPs get flagged quickly and return US-centric results regardless of your target market. Residential proxies distribute requests across real ISP-assigned IPs and support country/city-level geo-targeting, giving you clean localized data and avoiding rate-limit blocks.
Which proxy type works best for scraping Google suggestions?
Residential proxies are the best choice for Google autocomplete and PAA scraping. They use real ISP IP addresses that Google trusts, support granular geo-targeting (country and city level), and rotate naturally to avoid rate limits. Datacenter proxies are faster but get flagged by Google's anti-abuse systems. Mobile proxies work well but are more expensive and unnecessary for suggestion scraping.
How do you avoid blocks when scraping Google PAA and autocomplete?
Use rotating residential proxies with geo-targeting, throttle requests to at least 0.5 seconds between calls, set realistic User-Agent headers, and pass the gl and hl parameters to match your proxy's locale. For PAA scraping with Playwright, add random delays between accordion clicks and limit expansion depth to 20–30 questions per SERP. If you need high-volume SERP data, consider the Google Custom Search API at $5 per 1,000 queries.
Can you scrape Google autocomplete without JavaScript rendering?
Yes. The autocomplete endpoint at suggestqueries.google.com/complete/search?client=chrome&q=QUERY returns plain JSON and requires no JavaScript or browser. This makes it much faster and cheaper to scrape than PAA boxes, which do require a headless browser like Playwright to render and interact with accordions. Most keyword research pipelines should start with autocomplete and add PAA as a secondary enrichment step.





