The Reddit SEO Opportunity Most People Miss
If you've searched Google recently, you've probably noticed Reddit showing up everywhere. Reddit threads now appear in the Discussion Box, get cited in AI Overviews, and regularly claim top organic positions.
These aren't just random appearances. For commercial keywords like "best CRM software" or "project management tools," Reddit threads can receive tens of thousands of monthly visits from Google alone.
Here's what makes this interesting for SEO automation: these discussions contain real user opinions about your brand and your competitors. People are actively discussing which products they recommend, which ones disappointed them, and why.
In this tutorial, we'll build a Python script that:
- Finds Reddit threads ranking on Google for any keyword
- Estimates monthly traffic to each thread
- Extracts competitor sentiment (praise and complaints)
- Identifies opportunities where your brand is missing from the conversation
What You'll Need
Before we start, make sure you have:
- Python 3.7+ installed on your machine
- The
requestslibrary (pip install requests) - Optional:
pandasfor data analysis (pip install pandas) - An API key from RapidAPI (free tier available)
Why an API?
You could scrape Google and Reddit directly, but you'd be dealing with rate limits, CAPTCHAs, and constantly breaking selectors. An API handles all that complexity and gives you clean, structured data. The free tier gives you 15 requests to test with.
The Discovery Script
Let's start with a simple script that discovers Reddit discussions for a keyword. This is the foundation we'll build on.
import requests import json def discover_reddit_threads(keyword, api_key): """ Find Reddit threads ranking on Google for a keyword. Args: keyword: The search term to analyze api_key: Your RapidAPI key Returns: dict: Thread data with traffic estimates and analysis """ url = "https://reddit-traffic-and-intelligence-api.p.rapidapi.com/api/v2/discover-threads" headers = { "Content-Type": "application/json", "x-rapidapi-host": "reddit-traffic-and-intelligence-api.p.rapidapi.com", "x-rapidapi-key": api_key } payload = { "keyword": keyword, "max_threads": 10 } response = requests.post(url, json=payload, headers=headers) return response.json() # Example usage if __name__ == "__main__": API_KEY = "your_api_key_here" result = discover_reddit_threads("crm software", API_KEY) print(f"Found {result['threads_discovered']} threads") print(f"Total estimated traffic: {result['summary']['estimated_monthly_traffic']:,}/month") for thread in result['threads']: print(f"\n[{thread['priority']}] {thread['title']}") print(f" Traffic: ~{thread['estimated_traffic']:,}/month") print(f" Source: {thread['source']} (Position {thread['position']})")
Run this and you'll see something like:
Sample Output
Found 8 threads Total estimated traffic: 134,705/month [HIGH] Best CRM for small business? Traffic: ~33,677/month Source: discussion_box (Position 0) [HIGH] HubSpot vs Salesforce - honest opinions? Traffic: ~16,838/month Source: organic (Position 3) [MEDIUM] Anyone using Pipedrive? Worth it? Traffic: ~8,419/month Source: organic (Position 5)
Adding Competitor Sentiment Analysis
Here's where it gets interesting. By passing in your brand and competitors, the API analyzes sentiment for each one across all discovered threads.
import requests def analyze_competitor_sentiment(keyword, your_brand, competitors, api_key): """ Discover Reddit threads and analyze sentiment for specific brands. Args: keyword: Search term your_brand: Your company/product name competitors: List of competitor names api_key: Your RapidAPI key Returns: dict: Threads with brand-specific sentiment analysis """ url = "https://reddit-traffic-and-intelligence-api.p.rapidapi.com/api/v2/discover-threads" headers = { "Content-Type": "application/json", "x-rapidapi-host": "reddit-traffic-and-intelligence-api.p.rapidapi.com", "x-rapidapi-key": api_key } payload = { "keyword": keyword, "your_brand": your_brand, "competitors": competitors, "max_threads": 10, "max_comments_per_thread": 10 } response = requests.post(url, json=payload, headers=headers) return response.json() def print_sentiment_report(data): """Print a formatted sentiment report.""" print("=" * 60) print(f"SENTIMENT ANALYSIS: {data['keyword']}") print("=" * 60) for thread in data['threads']: analysis = thread.get('analysis', {}) brands = analysis.get('brand_sentiments', {}) if not brands: continue print(f"\n--- {thread['title'][:50]}...") print(f" Traffic: ~{thread['estimated_traffic']:,}/month") for brand, sentiment in brands.items(): pos = sentiment.get('positive', 0) neg = sentiment.get('negative', 0) print(f"\n {brand}: +{pos} / -{neg}") if sentiment.get('praise'): print(f" Praise: {', '.join(sentiment['praise'][:3])}") if sentiment.get('complaints'): print(f" Complaints: {', '.join(sentiment['complaints'][:3])}") # Example usage if __name__ == "__main__": API_KEY = "your_api_key_here" result = analyze_competitor_sentiment( keyword="crm software", your_brand="Acme CRM", competitors=["HubSpot", "Salesforce", "Pipedrive"], api_key=API_KEY ) print_sentiment_report(result)
Sample Output
============================================================
SENTIMENT ANALYSIS: crm software
============================================================
--- Best CRM for small business?...
Traffic: ~33,677/month
HubSpot: +15 / -8
Praise: easy to use, good free tier, great integrations
Complaints: expensive at scale, pushy sales team
Salesforce: +4 / -12
Praise: powerful features, industry standard
Complaints: too complex, expensive, overkill for SMB
Pipedrive: +13 / -3
Praise: simple and focused, great for sales teams
Complaints: limited marketing features
Finding Opportunities: Where You're Missing
The real value is finding high-traffic threads where competitors are mentioned but you're not. These represent conversations happening about your market where your brand is absent.
def find_gaps(data, your_brand): """ Find high-traffic threads where your brand isn't mentioned but competitors are. Args: data: API response from discover_threads your_brand: Your brand name Returns: list: Threads representing opportunities """ opportunities = [] for thread in data.get('threads', []): analysis = thread.get('analysis', {}) brands = analysis.get('brand_sentiments', {}) # Check if your brand is mentioned your_brand_mentioned = your_brand.lower() in [b.lower() for b in brands.keys()] # Check if any competitors are mentioned has_competitor_mentions = len(brands) > 0 # High traffic + competitors mentioned + you're not = opportunity if not your_brand_mentioned and has_competitor_mentions: if thread.get('estimated_traffic', 0) > 1000: opportunities.append({ 'title': thread['title'], 'url': thread['url'], 'traffic': thread['estimated_traffic'], 'priority': thread['priority'], 'competitors_mentioned': list(brands.keys()), 'why_matters': thread.get('why_matters', '') }) # Sort by traffic (highest first) return sorted(opportunities, key=lambda x: x['traffic'], reverse=True) # Example usage if __name__ == "__main__": # Using data from previous example gaps = find_gaps(result, "Acme CRM") print(f"\nFound {len(gaps)} opportunities:\n") for gap in gaps: print(f"[{gap['priority']}] {gap['title']}") print(f" Traffic: ~{gap['traffic']:,}/month") print(f" Competitors: {', '.join(gap['competitors_mentioned'])}") print(f" URL: {gap['url']}\n")
Understanding the Results
Let's break down what the API returns and how to interpret it:
| Field | What It Means |
|---|---|
estimated_traffic |
Monthly visitors from Google. Calculated as search_volume x position_CTR. The CTR is included so you can verify. |
source |
Where the thread appears: discussion_box (highest visibility), ai_overview, or organic |
priority |
HIGH/MEDIUM/LOW based on traffic, position, and opportunity. HIGH = act on this first. |
brand_sentiments |
Positive/negative counts plus extracted praise and complaints for each brand. |
confidence |
How confident the sentiment analysis is (0-1). Higher = more data points. |
About Traffic Estimates
Traffic numbers are estimates based on keyword search volume and position-based CTR rates. They're directionally accurate for prioritization, but don't treat them as exact. A thread showing 30,000/month is definitely getting more traffic than one showing 500/month.
Practical Applications
1. Competitive Intelligence Reports
Run this weekly for your core keywords. Track how sentiment shifts over time. When a competitor starts getting more complaints about pricing, that's your opening.
2. Content Gap Analysis
The "opportunities" output shows you exactly where to focus. If a thread has 30K monthly visitors discussing CRM options and you're not mentioned, that's content waiting to be created.
3. Community Engagement Prioritization
Don't waste time on low-traffic threads. Focus your Reddit engagement on discussions that actually rank on Google and drive traffic.
4. Battle Card Generation
The extracted praise/complaints give you real quotes for sales battle cards. "Users say Salesforce is 'overkill for SMB' and 'too complex'" - that's straight from the data.
Complete Script
Here's everything combined into a single, runnable script:
""" Reddit SEO Discovery Script Find Reddit threads ranking on Google with traffic estimates and sentiment analysis. """ import requests import json from datetime import datetime class RedditSEODiscovery: def __init__(self, api_key): self.api_key = api_key self.base_url = "https://reddit-traffic-and-intelligence-api.p.rapidapi.com" self.headers = { "Content-Type": "application/json", "x-rapidapi-host": "reddit-traffic-and-intelligence-api.p.rapidapi.com", "x-rapidapi-key": api_key } def discover(self, keyword, your_brand=None, competitors=None, max_threads=10): """Discover Reddit threads ranking for a keyword.""" payload = { "keyword": keyword, "max_threads": max_threads, "max_comments_per_thread": 10 } if your_brand: payload["your_brand"] = your_brand if competitors: payload["competitors"] = competitors response = requests.post( f"{self.base_url}/api/v2/discover-threads", json=payload, headers=self.headers ) return response.json() def find_opportunities(self, data, your_brand): """Find threads where you're not mentioned but competitors are.""" opportunities = [] for thread in data.get('threads', []): brands = thread.get('analysis', {}).get('brand_sentiments', {}) your_mentioned = your_brand.lower() in [b.lower() for b in brands.keys()] if not your_mentioned and brands and thread.get('estimated_traffic', 0) > 1000: opportunities.append({ 'title': thread['title'], 'url': thread['url'], 'traffic': thread['estimated_traffic'], 'priority': thread['priority'], 'competitors': list(brands.keys()) }) return sorted(opportunities, key=lambda x: x['traffic'], reverse=True) def aggregate_sentiment(self, data): """Aggregate sentiment across all threads for each brand.""" brand_totals = {} for thread in data.get('threads', []): brands = thread.get('analysis', {}).get('brand_sentiments', {}) for brand, sentiment in brands.items(): if brand not in brand_totals: brand_totals[brand] = { 'positive': 0, 'negative': 0, 'neutral': 0, 'praise': [], 'complaints': [] } brand_totals[brand]['positive'] += sentiment.get('positive', 0) brand_totals[brand]['negative'] += sentiment.get('negative', 0) brand_totals[brand]['neutral'] += sentiment.get('neutral', 0) brand_totals[brand]['praise'].extend(sentiment.get('praise', [])) brand_totals[brand]['complaints'].extend(sentiment.get('complaints', [])) return brand_totals def print_report(self, data, your_brand=None): """Print a formatted discovery report.""" print("\n" + "="*60) print(f"REDDIT SEO DISCOVERY: {data['keyword']}") print(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')}") print("="*60) # Summary summary = data.get('summary', {}) print(f"\nThreads found: {data.get('threads_discovered', 0)}") print(f"Total estimated traffic: {summary.get('estimated_monthly_traffic', 0):,}/month") # Priority breakdown by_priority = summary.get('by_priority', {}) print(f"Priority: {by_priority.get('HIGH', 0)} HIGH / {by_priority.get('MEDIUM', 0)} MEDIUM / {by_priority.get('LOW', 0)} LOW") # Top threads print("\n--- TOP THREADS ---") for thread in data.get('threads', [])[:5]: print(f"\n[{thread['priority']}] {thread['title'][:60]}") print(f" Traffic: ~{thread['estimated_traffic']:,}/month | {thread['source']}") # Opportunities if your_brand: gaps = self.find_opportunities(data, your_brand) if gaps: print(f"\n--- OPPORTUNITIES ({len(gaps)} threads without {your_brand}) ---") for gap in gaps[:3]: print(f"\n {gap['title'][:50]}...") print(f" Traffic: ~{gap['traffic']:,}/month") print(f" Competitors present: {', '.join(gap['competitors'])}") # Aggregated sentiment sentiment = self.aggregate_sentiment(data) if sentiment: print("\n--- BRAND SENTIMENT SUMMARY ---") for brand, stats in sentiment.items(): total = stats['positive'] + stats['negative'] + stats['neutral'] if total > 0: print(f"\n {brand}: +{stats['positive']} / -{stats['negative']}") # Main execution if __name__ == "__main__": # Configuration API_KEY = "your_api_key_here" KEYWORD = "crm software" YOUR_BRAND = "Acme CRM" COMPETITORS = ["HubSpot", "Salesforce", "Pipedrive"] # Run discovery discovery = RedditSEODiscovery(API_KEY) result = discovery.discover(KEYWORD, YOUR_BRAND, COMPETITORS) # Print report discovery.print_report(result, YOUR_BRAND) # Save raw data with open("discovery_results.json", "w") as f: json.dump(result, f, indent=2) print("\nFull data saved to discovery_results.json")
Try It Yourself
The free tier includes 15 API calls - enough to test with your own keywords and competitors.
Get Free API KeyNext Steps
Now that you can discover discussions and analyze sentiment, the final step is putting it all together into automated reports that run on schedule.