From serpapi-pack
Manages SerpApi rate limits and credits with monitoring, Python/Node.js throttling, and cached search retrieval to optimize API usage.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin serpapi-packThis skill is limited to using the following tools:
SerpApi uses credit-based pricing (each search = 1 credit) plus per-second rate limits. Retrieving cached/archived searches does not consume credits. Plans range from 100 searches/month (free) to unlimited (enterprise).
Optimizes SerpApi costs using Python strategies: Redis caching, archive retrieval, Google Light API, reduced results, and monthly cost calculator.
Implements Exa API rate limiting with exponential backoff, jitter for 429 retries, and PQueue queuing for 10 QPS concurrency control.
Documents Glean Indexing (~100 req/min/token) and Search API (~60/min) rate limits with backoff, p-queue concurrency=3, and bulk indexing advice.
Share bugs, ideas, or general feedback.
SerpApi uses credit-based pricing (each search = 1 credit) plus per-second rate limits. Retrieving cached/archived searches does not consume credits. Plans range from 100 searches/month (free) to unlimited (enterprise).
| Plan | Searches/Month | Rate Limit | Price |
|---|---|---|---|
| Free | 100 | 1/second | $0 |
| Developer | 5,000 | 5/second | $75/mo |
| Business | 15,000 | 10/second | $200/mo |
| Enterprise | 50,000+ | 15/second | Custom |
import serpapi, os
client = serpapi.Client(api_key=os.environ["SERPAPI_API_KEY"])
# Check remaining credits before batch operations
account = client.account()
remaining = account["plan_searches_left"]
used = account["this_month_usage"]
total = account["total_searches_left"]
print(f"Used: {used}, Remaining: {remaining}")
if remaining < 100:
print("WARNING: Low credits remaining")
import time
from threading import Semaphore
class ThrottledSerpApi:
def __init__(self, api_key: str, max_per_second: int = 5):
self.client = serpapi.Client(api_key=api_key)
self.semaphore = Semaphore(max_per_second)
self.last_request = 0
def search(self, **params) -> dict:
with self.semaphore:
# Enforce minimum interval
elapsed = time.time() - self.last_request
if elapsed < 0.2: # 5/sec max
time.sleep(0.2 - elapsed)
self.last_request = time.time()
return self.client.search(**params)
# Retrieve a previous search result by ID (FREE, no credit charge)
archived = client.search(engine="google", search_id="previous_search_id")
# Check if a query was recently searched before spending a credit
# Store search IDs in your database keyed by query+params hash
import PQueue from 'p-queue';
import { getJson } from 'serpapi';
const queue = new PQueue({
concurrency: 3, // Max parallel requests
interval: 1000, // Per second
intervalCap: 5, // Max 5 per second
});
async function throttledSearch(params: Record<string, any>) {
return queue.add(() => getJson({
...params,
api_key: process.env.SERPAPI_API_KEY,
}));
}
// Batch search with automatic throttling
const queries = ['query1', 'query2', 'query3'];
const results = await Promise.all(
queries.map(q => throttledSearch({ engine: 'google', q }))
);
| Error | Cause | Solution |
|---|---|---|
429 Too Many Requests | Rate limit exceeded | Slow down, check plan tier |
Searches exhausted | Monthly credits used up | Cache results, upgrade plan |
Account disabled | Payment issue or abuse | Contact SerpApi support |
For security configuration, see serpapi-security-basics.