API Documentation

Run 20 SEO checks on any URL with a single API call. Get a score, grade, and actionable recommendations in under 2 seconds.

On this page

📦
Postman CollectionDownload JSON and import into Postman to try every endpoint instantly.

Base URL

https://seopeek.web.app

All API endpoints live under /api/v1/. All requests and responses use JSON.

Authentication

The free-tier audit endpoint (GET) requires no authentication and is rate-limited. For higher limits, create an API key and include it in the x-api-key header:

curl -H "x-api-key: seo_your_key_here" \
  "https://seopeek.web.app/api/v1/audit?url=https://example.com"

API keys are prefixed with seo_ and tied to the email address used during registration. Keep your key secret and never expose it in client-side code.

Audit Endpoint

GET /api/v1/audit Free tier

Run a full SEO audit on any publicly accessible URL. Returns a score (0-100), letter grade (A-F), summary counts, and all 20 individual check results.

Query Parameters

ParameterTypeRequiredDescription
urlstringYesThe URL to audit. Must be publicly accessible. The https:// prefix is added automatically if omitted.

Restrictions: Private, internal, and localhost URLs are blocked (127.0.0.1, 192.168.*, 10.*, 172.*, *.local). Target URLs have a 10-second fetch timeout.

Get an API Key

POST /api/v1/keys No auth required

Register for an API key using your email address. You start on the free plan with 50 audits per day.

Request Body

FieldTypeRequiredDescription
emailstringYesA valid email address to associate with the key.
curl -X POST "https://seopeek.web.app/api/v1/keys" \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com"}'

Response:

{
  "apiKey": "seo_abc123def456...",
  "plan": "free",
  "limit": "50 audits/day"
}

Health Check

GET /api/health No auth required

Returns the service status, name, and version. Useful for monitoring uptime.

{
  "status": "ok",
  "service": "seopeek",
  "version": "1.0.0"
}

Response Format

A successful audit returns a JSON object with the following structure:

{
  "url": "https://example.com",
  "score": 82,
  "grade": "B",
  "summary": {
    "passed": 15,
    "warnings": 4,
    "failed": 1,
    "total": 20
  },
  "checks": [
    {
      "id": "title",
      "status": "pass",
      "message": "Title is good (52 chars)",
      "detail": "Example Domain - The Best Example Site"
    },
    {
      "id": "meta-description",
      "status": "fail",
      "message": "Missing meta description",
      "detail": "Add a compelling meta description (120-160 characters)."
    },
    // ... 18 more checks
  ],
  "meta": {
    "scanDuration": "847ms",
    "timestamp": "2026-03-28T14:22:01.000Z"
  }
}

Check Object Fields

FieldTypeDescription
idstringUnique identifier for the check (e.g. title, meta-description)
statusstringOne of pass, warn, or fail
messagestringHuman-readable summary of the result
detailstringAdditional context or the actionable recommendation

The 20 SEO Checks

Every audit runs these 20 checks against the target page. Each check returns pass, warn, or fail.

01

Title Tag

Checks for a <title> tag and validates its length. Optimal: 50-60 characters. Too short (<10) or too long (>70) triggers a warning.

02

Meta Description

Validates the meta[name="description"] tag exists and is 70-170 characters. Missing descriptions get a fail; too short or long gets a warning.

03

H1 Tag

Ensures exactly one <h1> tag exists. Missing H1 is a fail; multiple H1s trigger a warning.

04

Heading Hierarchy

Validates that heading levels (H1-H6) follow a sequential order without skipping levels (e.g. H1 directly to H3).

05

Open Graph Tags

Checks for og:title, og:description, and og:image. All three present is a pass; none is a fail; partial is a warning.

06

Twitter Card

Looks for meta[name="twitter:card"]. Missing Twitter Card meta tag triggers a warning.

07

Canonical URL

Checks for a link[rel="canonical"] tag. Missing canonical URL can cause duplicate content issues.

08

Meta Viewport

Validates the meta[name="viewport"] tag includes width=device-width. Missing viewport is a fail; incorrect config is a warning.

09

Image Alt Attributes

Counts images with and without alt attributes. More than 50% missing alt text is a fail; any missing is a warning.

10

Language Attribute

Checks for a lang attribute on the <html> element. Helps search engines serve the correct audience.

11

Structured Data (JSON-LD)

Detects script[type="application/ld+json"] blocks. Structured data enhances rich search result appearance.

12

Meta Robots

Checks the meta[name="robots"] tag. A noindex directive is flagged as a fail since it prevents indexing.

13

HTTPS

Verifies the URL uses https://. Non-HTTPS sites receive a fail as Google penalizes insecure connections.

14

Internal Links

Counts internal vs. external links on the page. No internal links triggers a warning; a healthy link structure passes.

15

Content Length

Measures word count of the page body. Under 100 words is thin content (warning); under 300 is light content; 300+ passes.

16

Favicon

Looks for link[rel="icon"], shortcut icon, or apple-touch-icon. Missing favicons hurt brand recognition.

17

Character Encoding

Checks for meta[charset] or a Content-Type meta with charset. Missing encoding can cause rendering issues.

18

Content-Type Header

Validates the HTTP Content-Type response header contains text/html. Unexpected types trigger a warning.

19

Render-Blocking Resources

Counts CSS without media/preload and JS without async/defer/module. 1-3 is a warning; 4+ is a fail.

20

Deprecated HTML

Scans for obsolete elements: <font>, <center>, <marquee>, <blink>, <frame>, <frameset>. Any found triggers a warning.

Scoring Methodology

The overall score is calculated from the results of all 20 checks using a weighted formula:

// Score calculation
const score = Math.round(
  ((passed + warnings * 0.5) / total) * 100
);

With 20 checks, a perfect score of 100 requires all 20 to pass. A page with 15 passes, 4 warnings, and 1 fail scores ((15 + 4*0.5) / 20) * 100 = 85.

Grade Scale

GradeScore RangeMeaning
A90 - 100Excellent SEO. Minor optimizations at most.
B80 - 89Good SEO. A few checks need attention.
C70 - 79Fair. Several issues should be addressed.
D60 - 69Poor. Significant SEO problems detected.
F0 - 59Failing. Critical SEO issues require immediate action.

Code Examples

# Basic audit (free tier, no auth)
curl "https://seopeek.web.app/api/v1/audit?url=https://example.com"

# With API key for higher limits
curl -H "x-api-key: seo_your_key_here" \
  "https://seopeek.web.app/api/v1/audit?url=https://example.com"

# Pretty-print the JSON output
curl -s "https://seopeek.web.app/api/v1/audit?url=https://example.com" | jq .

# Register for an API key
curl -X POST "https://seopeek.web.app/api/v1/keys" \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com"}'
// Node.js (native fetch, v18+)
const auditUrl = async (url, apiKey) => {
  const endpoint = `https://seopeek.web.app/api/v1/audit?url=${encodeURIComponent(url)}`;
  const headers = apiKey ? { 'x-api-key': apiKey } : {};

  const res = await fetch(endpoint, { headers });
  const data = await res.json();

  console.log(`Score: ${data.score}/100 (Grade: ${data.grade})`);
  console.log(`Passed: ${data.summary.passed} | Warnings: ${data.summary.warnings} | Failed: ${data.summary.failed}`);

  // Log any failing checks
  data.checks
    .filter(c => c.status === 'fail')
    .forEach(c => console.log(`  FAIL: ${c.message}`));

  return data;
};

auditUrl('https://example.com', 'seo_your_key_here');
# Python 3 with requests
import requests

def audit_url(url, api_key=None):
    endpoint = "https://seopeek.web.app/api/v1/audit"
    headers = {"x-api-key": api_key} if api_key else {}
    params = {"url": url}

    resp = requests.get(endpoint, headers=headers, params=params)
    resp.raise_for_status()
    data = resp.json()

    print(f"Score: {data['score']}/100 (Grade: {data['grade']})")
    print(f"Passed: {data['summary']['passed']} | "
          f"Warnings: {data['summary']['warnings']} | "
          f"Failed: {data['summary']['failed']}")

    # Show failing checks
    for check in data["checks"]:
        if check["status"] == "fail":
            print(f"  FAIL: {check['message']}")

    return data

result = audit_url("https://example.com", api_key="seo_your_key_here")

Pricing Tiers

Free

$0
50 audits/day
Rate-limited GET endpoint
No API key required
Community support

Pro

$29/mo
10,000 audits/month
Priority rate limits
Webhook notifications
Priority support

Rate Limits

PlanDaily LimitMonthly LimitPer-Minute
Free5050010 req/min
Starter1001,00030 req/min
Pro50010,00060 req/min

Limits reset daily at midnight UTC and monthly on the 1st. When you exceed a limit, the API returns a 429 status code.

Error Codes

200Audit completed successfully. Returns JSON with score and checks.
400Bad request. Missing url parameter, invalid URL format, or private/internal URL.
401Unauthorized. Missing or invalid API key (paid endpoints only).
429Rate limit exceeded. Upgrade your plan or wait for the limit to reset.
502Bad gateway. The target URL could not be fetched. Check the URL is valid and publicly accessible.
504Gateway timeout. The target URL took longer than 10 seconds to respond.

All error responses return JSON with an error field:

{
  "error": "Missing required parameter: url",
  "example": "/api/v1/audit?url=https://example.com"
}