Tutorial

How to Build Agency SEO Reports with an API

Automate monthly SEO client reports with rank data and competitor positions. Python pipeline for agencies at $0.005/query.

SEO agencies spend hours monthly screenshotting dashboards for client reports. An API pipeline generates them programmatically: pull rank data, competitor positions, and SERP features, then output formatted reports. At $0.005/query, a 100-keyword report costs $0.50 per client.

Prerequisites

  • Python 3.8+
  • requests library
  • A Scavio API key from scavio.dev
  • Client domains and keyword lists

Walkthrough

Step 1: Define client configs

Set up clients with domains, keywords, and competitors.

Python
import os, requests, json
from datetime import date

API_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}

CLIENTS = [{'name': 'Acme Corp', 'domain': 'acme.com',
    'competitors': ['comp1.com', 'comp2.com'],
    'keywords': ['widget manufacturing', 'custom widgets', 'widget supplier']}]

Step 2: Collect rankings for client and competitors

One SERP call per keyword captures all domain positions.

Python
def collect(client):
    report = []
    domains = [client['domain']] + client['competitors']
    for kw in client['keywords']:
        data = requests.post('https://api.scavio.dev/api/v1/search',
            headers=H, json={'query': kw, 'country_code': 'us'}).json()
        positions = {}
        for r in data.get('organic_results', []):
            for d in domains:
                if d in r.get('link', '') and d not in positions:
                    positions[d] = r['position']
        features = []
        if data.get('answer_box'): features.append('AB')
        if data.get('related_questions'): features.append('PAA')
        report.append({'keyword': kw, 'positions': positions, 'features': features})
    return report

Step 3: Generate summary metrics

Calculate average position, top 3/10 counts, and cost.

Python
def summary(client, data):
    positions = [r['positions'].get(client['domain']) for r in data if r['positions'].get(client['domain'])]
    avg = round(sum(positions) / len(positions), 1) if positions else None
    t3 = sum(1 for p in positions if p <= 3)
    t10 = sum(1 for p in positions if p <= 10)
    print(f"\n{client['name']}: {len(positions)}/{len(data)} ranking, avg={avg}, top3={t3}, top10={t10}")
    print(f'Cost: ${len(data) * 0.005:.3f}')

Step 4: Run all client reports

Generate and export for every client.

Python
for client in CLIENTS:
    data = collect(client)
    print(f"{'Keyword':25} {'Client':7} {'Comp1':7} {'Comp2':7} Features")
    for r in data:
        p = r['positions']
        print(f"{r['keyword']:25} {str(p.get(client['domain'], '-')):7} "
              f"{str(p.get(client['competitors'][0], '-')):7} "
              f"{str(p.get(client['competitors'][1], '-')):7} {', '.join(r['features']) or '-'}")
    summary(client, data)
    with open(f"report_{client['name'].lower().replace(' ','_')}.json", 'w') as f:
        json.dump({'client': client['name'], 'date': date.today().isoformat(), 'data': data}, f, indent=2)

Python Example

Python
import os, requests
API_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}

def report(domain, keywords, comps):
    for kw in keywords:
        data = requests.post('https://api.scavio.dev/api/v1/search',
            headers=H, json={'query': kw, 'country_code': 'us'}).json()
        pos = {}
        for r in data.get('organic_results', []):
            for d in [domain] + comps:
                if d in r.get('link', '') and d not in pos: pos[d] = r['position']
        print(f'{kw:25} You={pos.get(domain, "-"):4} {" ".join(f"{c}={pos.get(c,"-")}" for c in comps)}')

report('acme.com', ['widgets', 'widget supplier'], ['comp1.com'])

JavaScript Example

JavaScript
const API_KEY = process.env.SCAVIO_API_KEY;
const H = { 'x-api-key': API_KEY, 'Content-Type': 'application/json' };
async function report(domain, keywords, comps) {
  for (const kw of keywords) {
    const data = await fetch('https://api.scavio.dev/api/v1/search', {
      method: 'POST', headers: H, body: JSON.stringify({ query: kw, country_code: 'us' })
    }).then(r => r.json());
    const pos = {};
    for (const r of data.organic_results || []) {
      for (const d of [domain, ...comps]) if (r.link.includes(d) && !pos[d]) pos[d] = r.position;
    }
    console.log(`${kw}: You=${pos[domain]||'-'} ${comps.map(c=>`${c}=${pos[c]||'-'}`).join(' ')}`);
  }
}
report('acme.com', ['widgets'], ['comp1.com']).catch(console.error);

Expected Output

JSON
Keyword                   Client  Comp1   Comp2   Features
widget manufacturing      3       7       -       PAA
custom widgets            5       2       8       AB, PAA
widget supplier           1       4       6       -

Acme Corp: 3/3 ranking, avg=3.0, top3=2, top10=3
Cost: $0.015

Related Tutorials

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

Python 3.8+. requests library. A Scavio API key from scavio.dev. Client domains and keyword lists. A Scavio API key gives you 250 free credits per month.

Yes. The free tier includes 250 credits per month, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

Start Building

Automate monthly SEO client reports with rank data and competitor positions. Python pipeline for agencies at $0.005/query.