How to Build a Website SEO Audit Tool in JavaScript (Free APIs)

# javascript# seo# webdev# tutorial
How to Build a Website SEO Audit Tool in JavaScript (Free APIs)Ozor

Ever wanted to quickly check a website's SEO health without paying for expensive tools like Ahrefs or...

Ever wanted to quickly check a website's SEO health without paying for expensive tools like Ahrefs or Semrush? You can build your own basic SEO auditor in under 100 lines of JavaScript using free APIs.

In this tutorial, we'll build a CLI tool that:

  • Scrapes any page for meta tags, headings, and links
  • Checks DNS records and hosting info
  • Takes a visual screenshot
  • Generates a clean audit report

What You'll Need

  • Node.js 18+
  • A free API key from Agent Gateway (200 free credits, no card required)

Step 1: Get Your API Key

curl -X POST https://api.frostbyte.world/api/keys/create
Enter fullscreen mode Exit fullscreen mode

Save the key from the response. Each API call costs 1 credit, so one full audit uses ~4 credits.

Step 2: The SEO Audit Script

Create seo-audit.js:

const API_KEY = process.env.FROSTBYTE_KEY || 'your-key-here';
const BASE = 'https://api.frostbyte.world';

async function api(path) {
  const res = await fetch(`${BASE}${path}`, {
    headers: { 'x-api-key': API_KEY }
  });
  return res.json();
}

async function auditSEO(url) {
  const domain = new URL(url).hostname;
  console.log(`\n🔍 SEO Audit: ${url}\n${'='.repeat(50)}`);

  // 1. Scrape the page for meta tags and structure
  console.log('\n📄 Page Analysis...');
  const page = await api(`/api/scraper/scrape?url=${encodeURIComponent(url)}`);

  if (page.metadata) {
    const m = page.metadata;
    console.log(`  Title: ${m.title || '❌ MISSING'}`);
    console.log(`  Title length: ${(m.title || '').length}/60 ${(m.title || '').length > 60 ? '⚠️ Too long' : ''}`);
    console.log(`  Description: ${m.description ? m.description.slice(0, 80) + '...' : '❌ MISSING'}`);
    console.log(`  Desc length: ${(m.description || '').length}/160 ${(m.description || '').length > 160 ? '⚠️ Too long' : ''}`);
    console.log(`  Canonical: ${m.canonical || '⚠️ Not set'}`);
    console.log(`  OG Image: ${m.ogImage ? '' : '❌ MISSING'}`);
    console.log(`  Robots: ${m.robots || 'Not set (defaults to index)'}`);
  }

  // Check headings structure
  if (page.content) {
    const h1s = (page.content.match(/<h1[^>]*>/gi) || []).length;
    const h2s = (page.content.match(/<h2[^>]*>/gi) || []).length;
    console.log(`\n  Headings:`);
    console.log(`    H1 tags: ${h1s} ${h1s === 1 ? '' : h1s === 0 ? '❌ Missing H1' : '⚠️ Multiple H1s'}`);
    console.log(`    H2 tags: ${h2s} ${h2s > 0 ? '' : '⚠️ No H2 tags'}`);
  }

  // Count links
  if (page.links) {
    const internal = page.links.filter(l => l.includes(domain)).length;
    const external = page.links.length - internal;
    console.log(`\n  Links: ${page.links.length} total (${internal} internal, ${external} external)`);
  }

  // 2. Check DNS records
  console.log('\n🌐 DNS & Hosting...');
  const dns = await api(`/api/dns/lookup?domain=${domain}`);

  if (dns.records) {
    const aRecords = dns.records.filter(r => r.type === 'A');
    const cnameRecords = dns.records.filter(r => r.type === 'CNAME');
    const mxRecords = dns.records.filter(r => r.type === 'MX');
    console.log(`  A Records: ${aRecords.map(r => r.value).join(', ') || 'None'}`);
    console.log(`  CNAME: ${cnameRecords.map(r => r.value).join(', ') || 'None'}`);
    console.log(`  MX Records: ${mxRecords.length > 0 ? '✅ Email configured' : '⚠️ No MX records'}`);
  }

  // 3. Check hosting IP info
  if (dns.records) {
    const ip = dns.records.find(r => r.type === 'A')?.value;
    if (ip) {
      const geo = await api(`/api/ip/geo?ip=${ip}`);
      if (geo.country) {
        console.log(`  Server: ${geo.city || '?'}, ${geo.country} (${geo.isp || geo.org || '?'})`);
        console.log(`  Hosting: ${geo.org || geo.isp || 'Unknown'}`);
      }
    }
  }

  // 4. Take a screenshot
  console.log('\n📸 Screenshot...');
  const screenshot = await api(`/api/screenshot/take?url=${encodeURIComponent(url)}&width=1280&height=800`);
  if (screenshot.url) {
    console.log(`  Saved: ${screenshot.url}`);
  }

  // Generate score
  console.log(`\n${'='.repeat(50)}`);
  console.log('📊 Quick Score:');
  let score = 0;
  let total = 0;

  const checks = [
    [!!page.metadata?.title, 'Has title tag'],
    [(page.metadata?.title || '').length <= 60, 'Title under 60 chars'],
    [!!page.metadata?.description, 'Has meta description'],
    [(page.metadata?.description || '').length <= 160, 'Description under 160 chars'],
    [!!page.metadata?.ogImage, 'Has OG image'],
    [!!page.metadata?.canonical, 'Has canonical URL'],
    [(page.content?.match(/<h1[^>]*>/gi) || []).length === 1, 'Exactly one H1'],
    [(page.content?.match(/<h2[^>]*>/gi) || []).length > 0, 'Has H2 headings'],
    [dns.records?.some(r => r.type === 'MX'), 'MX records configured'],
    [!!screenshot?.url, 'Page renders successfully'],
  ];

  checks.forEach(([pass, label]) => {
    total++;
    if (pass) score++;
    console.log(`  ${pass ? '' : ''} ${label}`);
  });

  console.log(`\n  Score: ${score}/${total} (${Math.round(score/total*100)}%)`);
}

// Run it
const url = process.argv[2] || 'https://example.com';
auditSEO(url).catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Step 3: Run Your Audit

export FROSTBYTE_KEY="your-api-key"
node seo-audit.js https://dev.to
Enter fullscreen mode Exit fullscreen mode

Output:

🔍 SEO Audit: https://dev.to
==================================================

📄 Page Analysis...
  Title: DEV Community
  Title length: 13/60 ✅
  Description: A constructive and inclusive social network for software develo...
  Desc length: 95/160 ✅
  Canonical: https://dev.to/
  OG Image: ✅
  Robots: Not set (defaults to index)

  Headings:
    H1 tags: 1 ✅
    H2 tags: 12 ✅

  Links: 87 total (64 internal, 23 external)

🌐 DNS & Hosting...
  A Records: 151.101.1.38, 151.101.65.38
  CNAME: None
  MX Records: ✅ Email configured
  Server: San Francisco, US (Fastly)
  Hosting: Fastly, Inc

📸 Screenshot...
  Saved: https://api.frostbyte.world/screenshots/dev.to-1709...png

==================================================
📊 Quick Score:
  ✅ Has title tag
  ✅ Title under 60 chars
  ✅ Has meta description
  ✅ Description under 160 chars
  ✅ Has OG image
  ✅ Has canonical URL
  ✅ Exactly one H1
  ✅ Has H2 headings
  ✅ MX records configured
  ✅ Page renders successfully

  Score: 10/10 (100%)
Enter fullscreen mode Exit fullscreen mode

Extending It

This basic auditor covers the fundamentals. Here are ideas to make it more powerful:

Add response time checking

const start = Date.now();
const res = await fetch(url);
const loadTime = Date.now() - start;
console.log(`  Load time: ${loadTime}ms ${loadTime < 1000 ? '' : '⚠️ Slow'}`);
Enter fullscreen mode Exit fullscreen mode

Batch audit multiple pages

const pages = [
  'https://example.com',
  'https://example.com/about',
  'https://example.com/blog',
];

for (const page of pages) {
  await auditSEO(page);
}
Enter fullscreen mode Exit fullscreen mode

Save results as JSON

const results = {
  url,
  timestamp: new Date().toISOString(),
  score: `${score}/${total}`,
  checks: checks.map(([pass, label]) => ({ pass, label })),
};
require('fs').writeFileSync('audit.json', JSON.stringify(results, null, 2));
Enter fullscreen mode Exit fullscreen mode

How It Works Under the Hood

Each audit makes 4 API calls:

API What It Does Credits
/api/scraper/scrape Extracts HTML, meta tags, links, headings 1
/api/dns/lookup Resolves DNS records (A, CNAME, MX, TXT) 1
/api/ip/geo Looks up server location and hosting provider 1
/api/screenshot/take Takes a full-page screenshot 1

That's 4 credits per audit. With 200 free credits, you can audit 50 websites before needing to top up.

Why Build Your Own?

Commercial SEO tools charge $99-449/month. If you only need basic checks — meta tags, headings, DNS, screenshots — a DIY solution with free APIs gets you 90% of the value at zero cost. Plus you own the data and can customize the checks.

For automated monitoring, wrap this in a cron job or GitHub Action to audit your site daily and catch regressions before they hurt your rankings.


Get your free API key at agent-gateway-kappa.vercel.app — 200 credits, no signup, no credit card. The API supports 40+ endpoints including IP geolocation, crypto prices, DNS, screenshots, web scraping, and more.