Back to Blog

Build a Keyword Tool With PAA Data

Build a keyword research tool from People Also Ask data. Learn how to collect PAA questions, cluster intent, and turn SERP data into content briefs faster.

April 21, 2026
By SerpBase Teampeople also askkeyword researchcontent strategypython

People Also Ask API: Build a Keyword Research Tool Using Google's PAA Data

When you search on Google, you will often see a box labeled "People also ask" below the first few organic results. It contains 4-6 questions related to your query, each expandable to show a featured answer snippet.

This box is a gold mine for keyword research. Unlike tools that estimate search volume from historical data, PAA questions come directly from Google — they reflect real user intent, real language, and real information gaps that Google has decided are worth surfacing. Extracting PAA data at scale gives you a question intelligence layer that no static keyword database can replicate.

This guide shows how to extract PAA data using a SERP API and build practical keyword research tools on top of it.

What PAA Data Looks Like

A SERP API returns PAA questions in a people_also_ask array. Each entry includes the question, a snippet answer, and the source URL:

{
  "people_also_ask": [
    {
      "question": "What is the difference between a SERP API and a web scraper?",
      "snippet": "A SERP API returns structured JSON from Google search results without requiring you to parse HTML or manage proxies. A web scraper...",
      "link": "https://example.com/serp-api-guide",
      "displayed_link": "example.com"
    },
    {
      "question": "How much does a SERP API cost?",
      "snippet": "SERP API pricing varies widely. Budget options start at $0.30 per 1,000 queries...",
      "link": "https://example.com/pricing",
      "displayed_link": "example.com"
    }
  ]
}

Basic PAA Extraction

import requests

API_KEY = "your_api_key"

def get_paa(query: str, country: str = "us", lang: str = "en") -> list:
    resp = requests.post(
        "https://api.serpbase.dev/google/search",
        headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
        json={"q": query, "gl": country, "hl": lang, "page": 1},
        timeout=15,
    )
    resp.raise_for_status()
    data = resp.json()
    return data.get("people_also_ask", [])

# Extract PAA for a seed keyword
questions = get_paa("serp api")
for q in questions:
    print(f"Q: {q['question']}")
    print(f"   Source: {q.get('displayed_link', '')}")
    print()

Use Case 1: Question Expansion for Keyword Research

PAA questions are not just content ideas — they are actual search queries people type into Google. Collecting PAA for a seed keyword and then recursively pulling PAA for each question can produce hundreds of real, related queries in minutes.

import time
from collections import deque

def expand_questions(seed: str, depth: int = 2, max_questions: int = 50) -> dict:
    """
    BFS expansion: get PAA for seed, then PAA for each question found,
    up to a max depth and total question count.
    """
    seen = set()
    result = {}  # question -> source URL
    queue = deque([(seed, 0)])

    while queue and len(result) < max_questions:
        query, level = queue.popleft()

        if query in seen or level > depth:
            continue
        seen.add(query)

        questions = get_paa(query)
        for q in questions:
            text = q["question"]
            if text not in result:
                result[text] = q.get("link", "")
                if level + 1 <= depth:
                    queue.append((text, level + 1))

        time.sleep(0.3)

    return result

# Expand from one seed keyword
all_questions = expand_questions("content marketing", depth=2)
print(f"Found {len(all_questions)} unique questions:")
for question in list(all_questions.keys())[:20]:
    print(f"  - {question}")

A depth-2 expansion from a single seed typically yields 50-200 unique questions, all of them real Google PAA entries.

Use Case 2: Content Brief Generator

Every piece of content should answer the questions real users are asking. PAA data gives you an exact list of those questions for any topic.

def generate_content_brief(topic: str) -> dict:
    questions = get_paa(topic)
    related_resp = requests.post(
        "https://api.serpbase.dev/google/search",
        headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
        json={"q": topic, "gl": "us", "hl": "en"},
        timeout=15,
    ).json()

    related_searches = [
        r["query"] for r in related_resp.get("related_searches", [])
    ]
    top_urls = [
        r["link"] for r in related_resp.get("organic", [])[:5]
    ]

    return {
        "topic": topic,
        "faq_section": [q["question"] for q in questions],
        "related_keywords": related_searches,
        "competitor_urls_to_analyze": top_urls,
        "recommended_h2s": [
            f"What is {topic}?",
            f"How to use {topic}",
            f"Best practices for {topic}",
        ] + [q["question"] for q in questions[:3]],
    }

brief = generate_content_brief("serp api")
print("=== Content Brief ===")
print(f"FAQ Questions to answer:")
for q in brief["faq_section"]:
    print(f"  ? {q}")
print(f"\nRelated keywords to include:")
for kw in brief["related_keywords"][:5]:
    print(f"  - {kw}")

Use Case 3: FAQ Schema Generation

FAQ schema markup can earn your page extra space in Google search results. PAA data is a perfect source for FAQ content because it is drawn directly from real user questions.

import json

def generate_faq_schema(topic: str) -> dict:
    questions = get_paa(topic)

    faq_items = [
        {
            "@type": "Question",
            "name": q["question"],
            "acceptedAnswer": {
                "@type": "Answer",
                "text": q.get("snippet", "")
            }
        }
        for q in questions if q.get("snippet")
    ]

    schema = {
        "@context": "https://schema.org",
        "@type": "FAQPage",
        "mainEntity": faq_items
    }

    return schema

schema = generate_faq_schema("serp api")
print(json.dumps(schema, indent=2))
# Embed this in your page's <head> as application/ld+json

Use Case 4: Search Intent Clustering

PAA questions reveal the different angles users care about for a topic. Clustering them by intent type helps you plan content that covers a topic completely.

def classify_intent(question: str) -> str:
    q = question.lower()
    if any(w in q for w in ["what is", "what are", "what does", "define", "meaning"]):
        return "informational"
    if any(w in q for w in ["how to", "how do", "how can", "steps to", "guide"]):
        return "how-to"
    if any(w in q for w in ["best", "top", "which", "vs", "versus", "compare"]):
        return "comparative"
    if any(w in q for w in ["price", "cost", "cheap", "free", "buy", "pricing"]):
        return "commercial"
    return "other"

def cluster_by_intent(topic: str) -> dict:
    questions = expand_questions(topic, depth=1)
    clusters = {"informational": [], "how-to": [], "comparative": [], "commercial": [], "other": []}

    for question in questions:
        intent = classify_intent(question)
        clusters[intent].append(question)

    return clusters

clusters = cluster_by_intent("project management software")
for intent, qs in clusters.items():
    if qs:
        print(f"\n{intent.upper()} ({len(qs)} questions):")
        for q in qs[:3]:
            print(f"  - {q}")

Use Case 5: Content Gap Analysis

Compare PAA questions for your brand versus competitors to spot topics you have not written about yet.

def find_content_gaps(my_keyword: str, competitor_keyword: str) -> dict:
    my_questions = {q["question"] for q in get_paa(my_keyword)}
    time.sleep(0.5)
    comp_questions = {q["question"] for q in get_paa(competitor_keyword)}

    return {
        "only_mine": my_questions - comp_questions,
        "only_competitor": comp_questions - my_questions,
        "shared": my_questions & comp_questions,
    }

gaps = find_content_gaps("serpbase api", "serpapi alternative")
print("Questions competitors answer but you don't:")
for q in gaps["only_competitor"]:
    print(f"  - {q}")

Combining PAA with Related Searches

The related_searches field in a SERP response complements PAA well. PAA gives you questions; related searches give you noun phrases. Together they form a comprehensive keyword map.

def full_keyword_map(seed: str) -> dict:
    resp = requests.post(
        "https://api.serpbase.dev/google/search",
        headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
        json={"q": seed, "gl": "us", "hl": "en"},
        timeout=15,
    ).json()

    return {
        "seed": seed,
        "paa_questions": [q["question"] for q in resp.get("people_also_ask", [])],
        "related_terms": [r["query"] for r in resp.get("related_searches", [])],
        "top_ranking_urls": [r["link"] for r in resp.get("organic", [])[:5]],
    }

keyword_map = full_keyword_map("python web scraping")
print(f"PAA questions: {len(keyword_map['paa_questions'])}")
print(f"Related terms: {len(keyword_map['related_terms'])}")

Cost at Scale

PAA-based keyword research is query-efficient because each search returns multiple questions:

TaskQueries neededCost at SerpBase
PAA for 100 seed keywords100$0.03
Depth-2 expansion (100 seeds)~1,500$0.45
Content briefs for 50 topics50$0.015
Weekly gap analysis (20 topics)40$0.012

At $0.30/1,000 queries, even aggressive PAA research costs less than a cup of coffee.

Tips for Better PAA Data

  • PAA varies by query phrasing — "how to lose weight" and "weight loss tips" can return different PAA sets. Test multiple phrasings.
  • PAA changes over time — Run the same queries monthly to catch new questions Google adds.
  • PAA is geographic — Use gl=gb for UK questions, gl=de for Germany. PAA varies significantly by market.
  • Combine with organic rankings — A question that appears in PAA AND has low-authority pages ranking for it is a high-opportunity target.

Summary

People Also Ask data is one of the most underused signals in SEO. Every PAA entry is a confirmed user question that Google has validated as relevant and searchable. With a SERP API, you can collect thousands of these questions programmatically, cluster them by intent, use them for content briefs, generate FAQ schema, and identify content gaps — all without any browser automation or proxy infrastructure.

With SerpBase at $0.30 per 1,000 queries, a full keyword research workflow for a 100-keyword project costs less than $0.50 in API calls.

Get your free API key at SerpBase — 100 searches included, no credit card required.

Product Workflow: Turning PAA Into a Keyword Tool

A useful People Also Ask workflow is not just a list of questions. The better version groups questions by intent, tracks repeated questions across seed terms, and records the search location used to collect them.

StepOutput
Collect seed keywordsA controlled keyword list from GSC, ads, or customer language
Pull PAA resultsQuestions, source URLs, and SERP context
Cluster questionsIntent groups for guides, FAQs, and comparisons
Map to pagesNew article, existing page update, or support doc
Refresh monthlyDetect changed questions and new source pages

Related reading: People Also Ask API for content research, People Also Ask API for keyword research, and Google Search Results JSON API.

FAQ

Should PAA questions be copied directly? No. Use them as intent signals, then answer in your own structure.

What makes this useful for SEO tools? Repetition across queries shows which questions are durable enough to prioritize.