ARTICLE AD BOX
I'm building an SEO reporting dashboard where I need to pull keyword data and backlink profiles from both Semrush and Ahrefs APIs. I'm running into two problems:
Both APIs have rate limits — I keep getting 429 errors when running bulk queries
Results are paginated — I have to manually track offsets and loop through pages to get complete data
What I've tried:
// Manual Semrush API call — no rate limiting, no pagination handling const response = await fetch( `https://api.semrush.com/?type=domain_organic&key=${API_KEY}&domain=example.com&limit=100` ); const text = await response.text(); // Parse CSV manually... // If I need more than 100 results, I have to manually handle pagination: let offset = 0; let allResults = []; while (true) { const res = await fetch(`...&offset=${offset}&limit=100`); const data = await res.text(); if (!data) break; allResults.push(...parse(data)); offset += 100; } // No error handling, no rate limiting, no TypeScript typesProblems with this approach:
No built-in rate limiting — hitting 429 errors under load
Manual pagination is repetitive and error-prone
Raw CSV parsing from Semrush — no typed response objects
Different auth patterns for Semrush (query param) vs Ahrefs (bearer token) — duplicating HTTP logic
What I need:
// Semrush — typed client with rate limiting
const semrush = createSemrushClient({ apiKey: process.env.SEMRUSH_API_KEY });
const overview = await semrush.getDomainOverview({ domain: 'example.com' });
console.log(overview.organicTraffic); // 12400
console.log(overview.organicKeywords); // 834
console.log(overview.backlinks); // 2341
// Auto-paginated keyword data — no manual offset tracking
const keywords = await semrush.getOrganicKeywords('example.com', { limit: 100 });
console.log(keywords.data); // SemrushKeywordData[]
console.log(keywords.hasMore); // false — already fetched all pages
// Ahrefs — same pattern, different provider
const ahrefs = createAhrefsClient({ apiKey: process.env.AHREFS_API_TOKEN });
const site = await ahrefs.getSiteOverview({ target: 'example.com' });
console.log(site.domainRating); // 47
console.log(site.organicTraffic); // 9800
const kd = await ahrefs.getKeywordDifficulty(['react seo', 'next.js seo']);
console.log(kd);
// [
// { keyword: 'react seo', difficulty: 42, searchVolume: 1200 },
// { keyword: 'next.js seo', difficulty: 38, searchVolume: 880 },
// ]
Error handling I need:
