Documentation

SEO Loop answers SEO questions about any public URL, over plain HTTP. No signup, no API key.

Quick start

curl seoloop.in/audit/example.com
curl -fsSL https://seoloop.in/install | sh   # optional CLI
seoloop audit example.com

Targets

A target is a domain or URL: example.com, https://example.com/pricing. If you leave out the scheme, https:// is assumed. Only http and https on ports 80 and 443 are allowed, and the host must resolve to a public address. Anything else is refused with HTTP 422.

Endpoints

Every endpoint is GET /<endpoint>/<target>. The answer is short plain text by default.

EndpointReturns
/audit/<target>26 checks in 4 categories, a 0-100 score and a grade. See The audit.
/compare/<a>?vs=<b>Both sites audited side by side, with the checks one passes and the other fails, and the score gap.
/indexable/<target>indexable: yes or NO with reasons: HTTP status, X-Robots-Tag and meta noindex, robots.txt rules (longest match wins, wildcards, $), canonical pointing elsewhere.
/links/<target>Checks the first 30 unique links on the page (internal first) and lists broken ones. HEAD requests with a GET fallback.
/schema/<target>JSON-LD blocks, the types found, and required properties that are missing for common types.
/status/<target>HTTP status after redirects.
/title/<target>The page title.
/meta/<target>Title, description, canonical, robots, viewport, language, Open Graph, headings, image alt gaps, word count.
/headers/<target>Final response headers.
/redirects/<target>Every hop from the URL you gave to the page you land on.
/ttfb/<target>Time to first byte, with DNS, connect and TLS timings.
/ssl/<target>Certificate subject, issuer, validity, days left, trust, protocol and cipher.
/robots/<target>robots.txt for the site, parsed: sitemaps, rule count, whether everything is blocked.
/sitemap/<target>Finds the sitemap (robots.txt first, then /sitemap.xml) and counts entries.
/ip, /uaYour IP address and user agent.

Output options

OptionEffect
?json · Accept: application/json · /v1/<endpoint>/<target>Full JSON instead of text.
?field=days_leftJust one top-level scalar value from the JSON, as text.
?min=80 (audit)HTTP 412 if the score is below 80. With curl -f that fails a script or build.
?only=seo,security · ?skip=hsts,sitemap (audit)Include or exclude categories or check ids. The score is recomputed.
?format=csv|md (audit)CSV rows, or Markdown for PR comments and job summaries.
?color (audit)ANSI colours for PASS and FAIL.

Audits return an X-SeoLoop-Score header. Machine-readable descriptions: /openapi.json and /llms.txt.

The audit

Each check is weighted by importance (high 10, medium 5, low 2). The score is the weighted share of checks that pass; grades are A 90+, B 80+, C 70+, D 60+, otherwise F.

CategoryCheck idImportanceWhat it checks
seotitlehighTitle tag present
seotitle_lengthmediumTitle 10-60 characters
seodescriptionhighMeta description present
seodescription_lengthmediumDescription 50-160 characters
seoh1mediumExactly one H1
seocanonicalmediumCanonical link
seoindexablehighPage is indexable
seolanglowhtml lang attribute
seoh2lowHas H2 subheadings
seoimg_altmediumImages have alt attributes
seocontentmediumAt least 300 words of content
seoopen_graphlowOpen Graph title + image
performancestatushighResponds 200 OK
performancettfbmediumTTFB under 800 ms
performanceviewporthighMobile viewport meta
performancecompressionmediumCompressed response (gzip/br)
performancehtml_sizelowHTML under 500 KB
securityhttpshighServed over HTTPS
securitytls_validhighValid TLS certificate
securityhttp_redirectmediumHTTP redirects to HTTPS
securityhstsmediumHSTS header
securitynosnifflowX-Content-Type-Options
securityframinglowClickjacking protection
crawlabilityrobots_txtmediumrobots.txt exists
crawlabilityrobots_openhighrobots.txt does not block everything
crawlabilitysitemapmediumXML sitemap found

CLI

curl -fsSL https://seoloop.in/install | sh

seoloop audit example.com
seoloop audit example.com --only seo --format md
seoloop audit example.com --min 80          # exit code 3 below 80
seoloop audit example.com --diff            # what changed since last run
seoloop compare a.com b.com
seoloop ssl example.com --field days_left
seoloop indexable example.com --json

Exit codes: 0 success, 1 error, 2 bad usage, 3 audit score below --min, 4 rate limited. --diff keeps its state in ~/.cache/seoloop. Set SEOLOOP_URL to use your own server.

GitHub Action

- uses: mehranshahmiri/seoloop-action@v1
  with:
    url: https://staging.example.com
    min-score: 80
    skip: sitemap          # optional
    only: seo,security     # optional

Listed on the GitHub Marketplace. Outputs score and grade, writes the Markdown report to the job summary, and fails the job below min-score. The target must be publicly reachable from the internet, so use a deployed preview or staging URL.

MCP server

A remote MCP server (Streamable HTTP, stateless, JSON responses) exposes every endpoint as a tool, so AI agents can run the checks themselves.

claude mcp add --transport http seoloop https://seoloop.in/mcp

Most other MCP clients that support remote servers take a URL: https://seoloop.in/mcp. Tools: audit, compare, indexable, links, schema, status, title, meta, headers, redirects, ttfb, ssl, robots, sitemap. All are read-only. Results include both text and structured content.

Limits & errors

  • Rate limits are per IP: 30 requests a minute in general, 6 a minute for /audit and /compare, 20 a minute for /mcp. Over the limit you get HTTP 429.
  • Results are cached for 5 minutes (10 for audits), so repeating a request is fast. Look for X-Cache: HIT.
  • Each request has a 25 second budget, at most 6 redirects, and a 1.5 MB response cap.
StatusMeaning
400Missing or unusable parameter (for example /compare without ?vs=).
412Audit score below ?min=.
422Target refused: invalid, non-public, or a disallowed port or scheme.
429Rate limited.
502 / 504The target could not be reached, or timed out.

Errors are plain text (error: ...) or {"error": "...", "status": 422} as JSON.

Self-hosting

PHP 8.2+ with curl, dom, openssl, mbstring and intl, plus nginx and PHP-FPM. The repository includes example configs for nginx, a dedicated PHP-FPM pool and rate limits, and a Dockerfile.

git clone https://github.com/mehranshahmiri/seoloop
php -S 127.0.0.1:8099 -t public public/index.php    # try it locally

Environment: SEOLOOP_BASE_URL (public URL), SEOLOOP_CACHE_DIR. Full steps are in the README.

Security model

The service fetches URLs that strangers type in, so all outbound requests go through one hardened function: public IPs only (every address a name resolves to is checked), the validated IP is pinned into the connection, redirects are followed manually and re-validated at every hop, ports are limited to 80 and 443, and size, time and redirect counts are capped. Found a problem? See the security policy.