api
POST /api/public/audit
Lancia un audit SEO anonimo one-shot senza chiave API. Risposta sincrona sotto i 60s, 1 audit per IP ogni 24h, senza Core Web Vitals.
Cosa fa questo endpoint
POST /api/public/audit lancia un audit SEO sincrono su qualsiasi URL pubblico senza chiave API. Restituisce la busta completa dell’audit nella stessa risposta: punteggio totale, punteggi per modulo e findings a livello di regola. PageSpeed Insights è saltato per mantenere la chiamata economica e la risposta sotto i 60 secondi.
- Sincrono: blocca fino alla fine dell’audit, senza polling.
- Anonimo: identificato dall’IP del client, limitato a 1 audit per IP ogni 24h.
- Salta Core Web Vitals (LCP, CLS, INP). Per dati PSI, usa il
POST /api/auditsautenticato. - Il risultato non è persistito su un account utente: una riga di rate-limit è salvata sulla tabella audits con
user_id = NULL.
Perché è importante
L’audit anonimo è il percorso di minor frizione per il widget “free audit” della home page e per strumenti di terze parti che vogliono mostrare il punteggio MetricSpot prima di chiedere all’utente di iscriversi. Niente OAuth, niente generazione di chiave, niente piano: solo un POST HTTPS.
Flussi concreti:
- Un builder di landing page incorpora un form “testa il tuo sito” che chiama l’endpoint direttamente dal browser dell’utente e renderizza il punteggio inline.
- Un bot Slack accetta
/audit example.comda qualsiasi collega e riposta il punteggio senza che nessuno nel workspace si debba autenticare contro MetricSpot.
Come usarlo
Invia un POST con un body JSON contenente url. L’URL deve essere assoluto (https://...), parsabile e al massimo 2000 caratteri.
Richiesta
POST /api/public/audit HTTP/1.1
Host: app.metricspot.com
Content-Type: application/json
{ "url": "https://example.com" }
curl
curl -X POST https://app.metricspot.com/api/public/audit \
-H "content-type: application/json" \
-d '{"url": "https://example.com"}'
Node fetch
const res = await fetch("https://app.metricspot.com/api/public/audit", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ url: "https://example.com" }),
});
const { audit } = await res.json();
console.log(`Punteggio ${audit.total_score} per ${audit.domain}`);
Python httpx
import httpx
r = httpx.post(
"https://app.metricspot.com/api/public/audit",
json={"url": "https://example.com"},
timeout=90.0,
)
print(r.json()["audit"]["total_score"])
Risposta
200 OK con la busta completa dell’audit:
{
"audit": {
"url": "https://example.com",
"domain": "example.com",
"total_score": 78,
"module_scores": {
"technical": 92,
"onpage": 71,
"performance": null,
"ai": 65,
"modern_seo": 80,
"social": 88,
"accessibility": 74,
"privacy": 82,
"readability": 70,
"tech_stack": 100,
"organic_traffic": 100
},
"rules": [
{
"module": "onpage",
"rule_id": "onpage.meta-description",
"passed": false,
"severity": "major",
"title": "Missing meta description",
"recommendation": "Add a 140-160 character meta description summarizing the page.",
"data": {}
}
]
},
"note": "Anonymous audits are limited and do not include Core Web Vitals. Sign up free for full audits and PDF reports."
}
Campi:
audit.url: l’URL auditato, riecheggiato.audit.domain: hostname estratto dall’URL.audit.total_score: punteggio ponderato su tutti i moduli, 0 a 100.audit.module_scores: punteggio per modulo 0 a 100, onullquando il modulo è stato saltato (performanceè semprenullper audit anonimi).audit.rules: array di ogni regola valutata. Ogni voce hamodule,rule_id,passed(boolean),severity(info|minor|major|critical),title,recommendationopzionale, edata(payload specifico della regola).note: stringa che spiega i limiti anonimi, per visualizzazione UI.
Busta di errore
{ "error": "Rate limit reached", "message": "Sign up free for more reports." }
Errori comuni
| Codice | Quando | Azione |
|---|---|---|
INVALID_URL (400) | URL non parsabile, schema mancante, o > 2000 caratteri | Passa un URL assoluto https:// |
RATE_LIMITED (429) | IP ha già auditato nelle ultime 24h | Aspetta 24h, o iscriviti a un piano Free (10 audit/mese) |
UPSTREAM_FAILED (502) | Glitch del crawler | Riprova con backoff breve |
INTERNAL (500) | Errore backend inatteso | Riprova; se persiste, accedi e usa POST /api/audits per un retry in coda |
L’endpoint non restituisce 401, 402 o 404: è non-autenticato per design e non ha risorse da cercare.
Domande frequenti
Perché performance è sempre null?
L’endpoint anonimo salta il Google PageSpeed Insights per mantenere il tempo totale sotto i 60 secondi ed evitare di bruciare quota PSI su traffico non-throttlato. Per Core Web Vitals (LCP, CLS, INP), usa il POST /api/audits autenticato, che fa girare PSI in parallelo al crawler.
Come viene applicato il rate limit?
Una riga è inserita nella tabella audits a ogni esecuzione anonima con user_id = NULL e ip_address impostato all’IP del chiamante. Chiamate successive dallo stesso IP entro 24h restituiscono 429. L’IP è letto dagli header standard di reverse proxy (X-Forwarded-For), quindi audit dietro un proxy condiviso possono collidere.
Posso usarlo dal browser?
Sì. L’endpoint imposta CORS permissivo per metricspot.com e accetta POST cross-origin. Per il tuo dominio, fai girare una funzione serverless come proxy sottile: permette di aggiungere rate limit per tenant ed evita di esporre gli IP dei tuoi visitatori a MetricSpot direttamente.
Il risultato è persistito da qualche parte?
Una riga esiste per fini di rate-limit, ma non è collegata a nessun account utente e non è visibile in nessuna dashboard. Per salvare e rivisitare un audit, iscriviti gratis e chiama POST /api/audits.
Fonti
Ultimo aggiornamento 2026-05-14