Back to all recipes
Python for SEOMarch 25, 2026

How to categorize 10,000 keywords by Intent using Python in 30 seconds

Master AI Automation 2026 and Generative Engine Optimization. Automate keyword intent classification with Python for AI Automation 2026 and Generative Engine Optimization, saving hours of manual data entry.

Search intent is the single most important signal in modern SEO. Google explicitly assigns keywords to one of four intent buckets — and if your content doesn't match the intent, you simply won't rank, no matter how technically perfect your page is.
The problem? Manually labeling a list of 10,000 keywords is a nightmare. Spreadsheet formulas break. Outsourcing it is expensive. SaaS tools charge per-credit.
This recipe uses Python to do it in under 30 seconds, completely for free, on your machine — and you keep full control of the logic.

The Four Intent Categories

Before we write a single line of code, understand what we're classifying:
IntentDefinitionExample Keywords
InformationalUser wants to learn something"what is keyword clustering", "how does SEO work"
NavigationalUser is looking for a specific brand/page"ahrefs login", "semrush pricing page"
CommercialUser is comparing options before buying"best SEO tools 2026", "ahrefs vs semrush"
TransactionalUser is ready to buy or take action"buy ahrefs subscription", "semrush discount code"
Our Python script will automatically assign one of these four tags to every keyword in your CSV.

What You'll Need

The only dependency is pandas for reading and writing CSV files. No LLM API, no cloud, no account:
bash
pip install pandas
That's it. Python's standard library handles the rest.

Part 1: The Basic Rule-Based Classifier

This is the foundation. Start with this script — it works on any keyword list out of the box.
Save it as intent_classifier.py:
python
import pandas as pd
import time

# ─── Keyword Signal Maps ───────────────────────────────────────────────────────
# Customize these lists for your niche. The more specific, the more accurate.

TRANSACTIONAL = [
    'buy', 'cheap', 'price', 'pricing', 'discount', 'purchase',
    'coupon', 'near me', 'order', 'deal', 'offer', 'promo', 'free trial',
    'get started', 'sign up', 'subscribe', 'download'
]

COMMERCIAL = [
    'best', 'top', 'vs', 'versus', 'review', 'reviews', 'compare',
    'alternative', 'alternatives', 'software', 'tool', 'tools',
    'recommend', 'worth it', 'pros and cons', 'ranking', 'ranked'
]

NAVIGATIONAL = [
    'login', 'log in', 'sign in', 'website', 'app', 'contact',
    'support', 'help center', 'official', 'homepage', 'portal', 'dashboard'
]

# ─── Core Classification Logic ─────────────────────────────────────────────────

def classify_intent(keyword: str) -> str:
    """
    Rule-based keyword intent classifier.
    Priority order: Transactional > Commercial > Navigational > Informational
    """
    kw = str(keyword).lower().strip()

    if any(signal in kw for signal in TRANSACTIONAL):
        return 'Transactional'

    if any(signal in kw for signal in COMMERCIAL):
        return 'Commercial'

    if any(signal in kw for signal in NAVIGATIONAL):
        return 'Navigational'

    return 'Informational'  # Default fallback

# ─── Main Processing Function ───────────────────────────────────────────────────

def process_keywords(input_csv: str, output_csv: str, keyword_col: str = 'keyword'):
    print(f"\n🔍 Loading '{input_csv}'...")
    start = time.time()

    df = pd.read_csv(input_csv)

    if keyword_col not in df.columns:
        raise ValueError(f"Column '{keyword_col}' not found. Available: {list(df.columns)}")

    count = len(df)
    print(f"   Found {count:,} keywords. Classifying...")

    df['intent'] = df[keyword_col].apply(classify_intent)

    # ─── Summary Stats ───────────────────────────────────────────────────────
    dist = df['intent'].value_counts()
    print("\n📊 Intent Distribution:")
    for intent, n in dist.items():
        pct = (n / count) * 100
        bar = '█' * int(pct / 2)
        print(f"   {intent:<20} {n:>6,}  ({pct:4.1f}%)  {bar}")

    df.to_csv(output_csv, index=False)
    elapsed = time.time() - start
    print(f"\n✅ Done! Saved {count:,} classified keywords to '{output_csv}' in {elapsed:.2f}s\n")

# ─── Entry Point ────────────────────────────────────────────────────────────────

if __name__ == '__main__':
    process_keywords(
        input_csv='keywords.csv',
        output_csv='intent_output.csv',
        keyword_col='keyword'   # Change if your column header is different
    )

How to Use It

Step 1: Export your keyword list from Ahrefs, Semrush, or Google Search Console. The file needs at least one column — your keywords.
Step 2: Rename the column header to keyword (or change keyword_col in the script).
Step 3: Run it:
bash
python intent_classifier.py
You'll see output like this directly in the terminal:
text
🔍 Loading 'keywords.csv'...
   Found 10,432 keywords. Classifying...

📊 Intent Distribution:
   Informational        6,821  (65.4%)  █████████████████████████████████
   Commercial           2,108  (20.2%)  ██████████
   Transactional          987   (9.5%)  ████
   Navigational           516   (4.9%)  ██

✅ Done! Saved 10,432 classified keywords to 'intent_output.csv' in 0.31s
Step 4: Open intent_output.csv. Every row now has an intent column. Filter by Transactional and you instantly know which keywords to prioritize for your product pages.

Part 2: Segment by Volume & Intent Together

Knowing intent is just the first step. The real power comes from combining it with search volume to prioritize what to work on first.
If your CSV already has a volume column (it will if you export from Ahrefs), extend the script with this block:
python
def priority_segment(row) -> str:
    """
    Creates a priority tier based on intent and monthly search volume.
    """
    volume = row.get('volume', 0) or 0
    intent = row.get('intent', 'Informational')

    if intent == 'Transactional' and volume >= 1000:
        return '🔥 High Priority'
    elif intent == 'Commercial' and volume >= 500:
        return '⚡ Medium Priority'
    elif intent == 'Informational' and volume >= 2000:
        return '📝 Content Opportunity'
    else:
        return '🧊 Low Priority'

# Add this line after the intent classification:
df['priority'] = df.apply(priority_segment, axis=1)
Your output now gives you a fully prioritized content roadmap — not just intent tags.

Part 3: Export a Separate File Per Intent

For large teams, you often need to hand off specific intent groups to different people (e.g., editorial team gets Informational; performance team gets Transactional). Add this after the main output:
python
def export_by_intent(df: pd.DataFrame, output_dir: str = '.'):
    """
    Splits the classified dataframe into separate CSV files by intent type.
    """
    import os
    os.makedirs(output_dir, exist_ok=True)

    for intent_type in df['intent'].unique():
        subset = df[df['intent'] == intent_type]
        filename = f"{output_dir}/{intent_type.lower()}_keywords.csv"
        subset.to_csv(filename, index=False)
        print(f"   Exported {len(subset):,} {intent_type} keywords → {filename}")
Then call it after your main processing:
python
export_by_intent(df, output_dir='intent_splits')

Part 4: Customizing for Your Niche

The script above is generic. To make it dramatically more accurate, add niche-specific signals to the lists at the top of the file.
Example: SaaS tooling niche:
python
COMMERCIAL = [
    # ...existing signals...
    'plan', 'pricing plan', 'enterprise', 'startup', 'agency',
    'integration', 'api', 'limit', 'feature comparison'
]

TRANSACTIONAL = [
    # ...existing signals...
    'upgrade', 'cancel', 'refund', 'trial', 'demo', 'book a demo'
]
Example: E-commerce niche:
python
TRANSACTIONAL = [
    # ...existing signals...
    'in stock', 'ships fast', 'free shipping', 'next day delivery',
    'size chart', 'returns policy', 'add to cart'
]
The more targeted your signal lists, the closer to 95%+ accuracy you'll get — without paying for a single API call.

Common Mistakes to Avoid

Mistake 1: Relying on this for head terms only. This script is especially powerful for long-tail keywords (4+ words) where intent is crystal clear. For 1–2 word head terms, manual review is still worth it.
Mistake 2: Forgetting to lowercase. The script already handles this with .lower().strip(), but don't remove it when editing.
Mistake 3: Not customizing the signal lists. The default lists are a starting point. Ten minutes of customization will dramatically improve accuracy.

The Meta Effect

By automating keyword intent classification, you enable a compounding productivity advantage:
  1. You can now run this daily against new keyword data from GSC exports — zero effort.
  2. Every keyword you rank for is labeled, so you know exactly what intent Google associates your pages with.
  3. You can A/B test content strategy by checking if switching a page's angle (e.g., from Informational to Commercial) correlates with rank changes.
In future recipes, we'll pipe this output directly into an LLM API to auto-generate content briefs grouped by intent — turning a 10-hour content strategy session into a 2-minute script run.
Advertisement

Ready to automate more?

Explore our directory of over 546 autonomous AI tools and platforms to drastically increase your output.

Browse AI Tools Directory