An r/microsaas post warned about building into saturated markets. The problem: most validation frameworks focus on finding demand, not checking for oversupply. This tutorial builds a negative validation pipeline that searches for existing solutions and quantifies market saturation before you commit.
Prerequisites
- Scavio API key
- Python 3.8+
Walkthrough
Step 1: Define saturation signals
What indicates a market is too crowded.
saturation_signals = {
'ad_heavy': 0, # Number of ads on SERP
'established_players': 0, # Funded companies in results
'review_sites': 0, # G2/Capterra listicles
'alternative_pages': 0, # 'X alternatives' pages
'reddit_complaints': 0, # Complaints about existing tools
}Step 2: Search for existing solutions
Multiple queries to gauge market density.
import requests, os
H = {'x-api-key': os.environ['SCAVIO_API_KEY']}
def check_saturation(product_idea):
queries = [
f'best {product_idea} software',
f'{product_idea} tools comparison',
f'{product_idea} alternatives',
f'{product_idea} pricing',
]
all_results = []
for q in queries:
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=H, json={'platform': 'google', 'query': q}).json()
all_results.extend(data.get('organic_results', []))
return all_resultsStep 3: Score saturation level
Count signals from search results.
def score_saturation(results, idea):
score = {'ads': 0, 'listicles': 0, 'funded': 0, 'alternatives_pages': 0}
funded_indicators = ['series a', 'series b', 'raised', 'backed by', 'yc']
for r in results:
snippet = (r.get('snippet', '') + r.get('title', '')).lower()
if 'alternative' in snippet: score['alternatives_pages'] += 1
if any(f in snippet for f in funded_indicators): score['funded'] += 1
if any(s in snippet for s in ['g2.com', 'capterra', 'top 10', 'best 10']): score['listicles'] += 1
total = sum(score.values())
return {'score': total, 'breakdown': score,
'verdict': 'Saturated' if total > 15 else 'Competitive' if total > 8 else 'Open'}Step 4: Check Reddit for unmet needs
Even saturated markets may have underserved niches.
def find_unmet_needs(idea):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=H,
json={'platform': 'reddit', 'query': f'{idea} frustrating OR missing OR wish'}).json()
complaints = data.get('results', [])
print(f'Found {len(complaints)} complaint threads')
for c in complaints[:5]:
print(f" - {c.get('title', '')}")
return complaintsPython Example
import os, requests
H = {'x-api-key': os.environ['SCAVIO_API_KEY']}
def validate_not_to_build(idea):
for q in [f'best {idea}', f'{idea} alternatives', f'{idea} comparison']:
data = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
json={'platform': 'google', 'query': q}).json()
alts = sum(1 for r in data.get('organic_results', []) if 'alternative' in r.get('title', '').lower())
print(f'{q}: {len(data.get("organic_results", []))} results, {alts} alternatives pages')
validate_not_to_build('project management tool')JavaScript Example
const res = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: {'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json'},
body: JSON.stringify({platform: 'google', query: `best ${idea} software`})
});
const data = await res.json();
const saturation = data.organic_results?.filter(r => r.title.toLowerCase().includes('alternative')).length;Expected Output
Saturation report: ad density, funded competitor count, alternatives page count, listicle coverage, and verdict (Saturated/Competitive/Open). 4 Google + 1 Reddit query = $0.025.