Skip to content

SOP: Keyword Research Pipeline Fresh

This SOP covers the full cycle: seed keywords in, prioritized list out. Uses two API sections — Keywords Data for volume data and DataForSEO Labs for discovery.

Research Flow

flowchart TD
    A[Seed keywords from client brief] --> B[Keyword Ideas via Labs API]
    B --> C[Related Keywords via Labs API]
    A --> D[Search Volume via Keywords Data API]
    C --> D
    D --> E[Filter by volume + difficulty]
    E --> F[Group by intent]
    F --> G[Priority keyword list]
    G --> H[Export to tracking / content plan]

Step 1: Get Search Volume for Known Keywords

When you already have keywords and need to validate them with volume data, use the Keywords Data API.

python
import os
import requests
from requests.auth import HTTPBasicAuth

auth = HTTPBasicAuth(
    os.environ["DATAFORSEO_LOGIN"],
    os.environ["DATAFORSEO_PASSWORD"]
)

# Your seed / known keywords
seed_keywords = [
    "roofing contractor miami",
    "roof repair miami",
    "metal roof installation miami",
    "flat roof repair miami",
    "emergency roofing miami"
]

payload = [
    {
        "keywords": seed_keywords,
        "location_code": 2840,  # United States
        "language_code": "en",
        "date_from": "2024-01-01",
        "date_to": "2024-12-31"
    }
]

response = requests.post(
    "https://api.dataforseo.com/v3/keywords_data/google_ads/search_volume/live",
    auth=auth,
    json=payload
)

data = response.json()
task = data["tasks"][0]

volume_data = {}
for item in task["result"]:
    keyword = item["keyword"]
    avg_volume = item.get("search_volume", 0)
    competition = item.get("competition", "unknown")
    cpc = item.get("cpc", 0)
    
    volume_data[keyword] = {
        "volume": avg_volume,
        "competition": competition,
        "cpc": cpc,
        "monthly_searches": item.get("monthly_searches", [])
    }
    
    print(f"{keyword}: {avg_volume}/mo | CPC ${cpc:.2f} | Competition: {competition}")

Step 2: Discover New Keywords via Labs API

Use keywords_for_keywords to expand your list. This is the main keyword discovery endpoint.

python
def get_keyword_ideas(auth, seed_keywords, location_code=2840, limit=100):
    """Get keyword ideas based on seed keywords."""
    
    payload = [
        {
            "keywords": seed_keywords[:5],  # Labs accepts up to 5 seeds per call
            "location_code": location_code,
            "language_code": "en",
            "include_serp_info": True,
            "include_seed_keyword": False,
            "filters": [
                ["keyword_info.search_volume", ">", 100]  # min 100 searches/mo
            ],
            "order_by": ["keyword_info.search_volume,desc"],
            "limit": limit
        }
    ]
    
    response = requests.post(
        "https://api.dataforseo.com/v3/dataforseo_labs/google/keywords_for_keywords/live",
        auth=auth,
        json=payload
    )
    
    data = response.json()
    task = data["tasks"][0]
    
    ideas = []
    for item in task["result"][0].get("items", []):
        ideas.append({
            "keyword": item["keyword"],
            "volume": item["keyword_info"].get("search_volume", 0),
            "difficulty": item.get("keyword_properties", {}).get("keyword_difficulty", 0),
            "cpc": item["keyword_info"].get("cpc", 0),
            "intent": item.get("search_intent_info", {}).get("main_intent", "unknown")
        })
    
    return ideas

ideas = get_keyword_ideas(auth, seed_keywords)
print(f"Found {len(ideas)} keyword ideas")

Use related_keywords to find semantically related terms — good for topic clustering.

python
def get_related_keywords(auth, keyword, location_code=2840, limit=50):
    """Get related keywords for a single target keyword."""
    
    payload = [
        {
            "keyword": keyword,
            "location_code": location_code,
            "language_code": "en",
            "limit": limit,
            "filters": [
                ["keyword_info.search_volume", ">", 50]
            ],
            "order_by": ["keyword_info.search_volume,desc"]
        }
    ]
    
    response = requests.post(
        "https://api.dataforseo.com/v3/dataforseo_labs/google/related_keywords/live",
        auth=auth,
        json=payload
    )
    
    data = response.json()
    task = data["tasks"][0]
    
    related = []
    for item in task["result"][0].get("items", []):
        related.append({
            "keyword": item["keyword_data"]["keyword"],
            "volume": item["keyword_data"]["keyword_info"].get("search_volume", 0),
            "difficulty": item["keyword_data"].get("keyword_properties", {}).get("keyword_difficulty", 0)
        })
    
    return related

# Get related keywords for your top seed
related = get_related_keywords(auth, "roofing contractor miami")

Step 4: Filter and Prioritize

Apply business rules to trim the raw list to actionable targets.

python
def prioritize_keywords(all_keywords, min_volume=100, max_difficulty=60):
    """
    Filter and score keywords.
    
    Scoring formula:
    - High volume + low difficulty = best opportunity
    - Score = volume / (difficulty + 1)
    """
    
    filtered = [
        kw for kw in all_keywords
        if kw["volume"] >= min_volume
        and kw["difficulty"] <= max_difficulty
    ]
    
    # Calculate opportunity score
    for kw in filtered:
        difficulty = kw["difficulty"] or 1
        kw["opportunity_score"] = round(kw["volume"] / difficulty, 1)
    
    # Sort by opportunity score descending
    filtered.sort(key=lambda x: x["opportunity_score"], reverse=True)
    
    return filtered

# Merge all keyword sources
all_keywords = list(volume_data.values())  # from step 1
all_keywords.extend(ideas)                  # from step 2
all_keywords.extend(related)               # from step 3

# Deduplicate by keyword text
seen = set()
unique_keywords = []
for kw in all_keywords:
    key = kw.get("keyword", kw.get("kw", "")).lower().strip()
    if key and key not in seen:
        seen.add(key)
        unique_keywords.append(kw)

prioritized = prioritize_keywords(unique_keywords)

# Print top 20
print("\nTop 20 Keyword Opportunities:")
print(f"{'Keyword':<45} {'Volume':>8} {'KD':>6} {'Score':>8}")
print("-" * 70)
for kw in prioritized[:20]:
    kw_text = kw.get("keyword", "")[:44]
    print(f"{kw_text:<45} {kw['volume']:>8,} {kw['difficulty']:>6} {kw['opportunity_score']:>8.1f}")

Step 5: Export to CSV

python
import csv

def export_keywords_csv(keywords, filepath="keyword-research.csv"):
    """Export prioritized keywords to CSV."""
    
    fieldnames = ["keyword", "volume", "difficulty", "cpc", "intent", "opportunity_score"]
    
    with open(filepath, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")
        writer.writeheader()
        writer.writerows(keywords)
    
    print(f"Exported {len(keywords)} keywords to {filepath}")

export_keywords_csv(prioritized)

Keyword Difficulty Interpretation

KD ScoreInterpretationRecommended Action
0–20Very easyTarget immediately
21–40AchievableBuild content now
41–60ModerateGood for established sites
61–80HardLong-term play, need authority
81–100Very hardAvoid unless high-authority domain

Search Intent Categories

DataForSEO Labs returns intent classifications. Use them to route keywords to the right content type:

IntentMeaningContent Type
informationalUser wants to learnBlog posts, guides, FAQs
navigationalUser wants a specific siteBrand pages
commercialUser is comparing optionsComparison pages, reviews
transactionalUser wants to buy/hireService pages, landing pages

Internal SOP reference — not affiliated with DataForSEO.