api
POST /api/public/audit
Lancez un audit SEO anonyme sans clé API. Réponse synchrone en moins de 60s, plafonné à 1 audit par IP toutes les 24h, sans Core Web Vitals.
Ce que fait cet endpoint
POST /api/public/audit lance un audit SEO synchrone sur toute URL publique sans clé API. Il renvoie l’enveloppe complète dans la même réponse : score total, scores par module et findings par règle. PageSpeed Insights est omis pour garder l’appel peu coûteux et la réponse sous 60 secondes.
- Synchrone : bloque jusqu’à la fin, sans polling.
- Anonyme : identifié par IP client, plafonné à 1 audit par IP toutes les 24h.
- Omet Core Web Vitals (LCP, CLS, INP). Pour les données PSI, utilisez l’authentifié
POST /api/audits. - Le résultat n’est pas persisté sur un compte : seule une ligne de rate-limit est stockée avec
user_id = NULL.
Pourquoi c’est important
L’audit anonyme est le chemin de moindre friction pour le widget “audit gratuit” d’une landing et pour les outils tiers qui veulent montrer le score MetricSpot avant de demander une inscription. Pas d’OAuth, pas de clé, pas de plan : juste un POST HTTPS.
Workflows concrets :
- Un builder de landing intègre un formulaire “testez votre site” qui appelle l’endpoint directement depuis le navigateur de l’utilisateur et affiche le score inline.
- Un bot Slack accepte
/audit example.comde tout coéquipier et reposte le score sans que personne dans le workspace n’ait à s’authentifier auprès de MetricSpot.
Comment l’utiliser
Envoyez un POST avec un corps JSON contenant url. L’URL doit être absolue (https://...), parsable et de 2000 caractères maximum.
Requête
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(`Score ${audit.total_score} for ${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"])
Réponse
200 OK avec l’enveloppe complète :
{
"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."
}
Champs :
audit.url: l’URL auditée, renvoyée en écho.audit.domain: hostname extrait de l’URL.audit.total_score: score pondéré tous modules, de 0 à 100.audit.module_scores: score par module de 0 à 100, ounullsi le module a été sauté (par ex.performanceest toujoursnullen audit anonyme).audit.rules: tableau de chaque règle évaluée. Chaque entrée amodule,rule_id,passed(booléen),severity(info|minor|major|critical),title,recommendationoptionnelle etdata(payload propre à la règle).note: chaîne expliquant les limites anonymes, pour affichage UI.
Enveloppe d’erreur
{ "error": "Rate limit reached", "message": "Sign up free for more reports." }
Erreurs courantes
| Code | Quand | Action |
|---|---|---|
INVALID_URL (400) | URL non parsable, sans schéma ou > 2000 caractères | Passez une URL absolue https:// |
RATE_LIMITED (429) | Cette IP a déjà audité dans les 24 dernières heures | Attendez 24h ou inscrivez-vous sur Free (10 audits/mois) |
UPSTREAM_FAILED (502) | Aléa de crawler en amont | Réessayez une fois après un court délai |
INTERNAL (500) | Erreur backend inattendue | Réessayez ; si persistant, connectez-vous et utilisez POST /api/audits |
L’endpoint ne renvoie pas 401, 402 ni 404 : il est non authentifié par conception et n’a aucune ressource à résoudre.
Questions fréquentes
Pourquoi performance est-il toujours null ?
L’endpoint anonyme omet Google PageSpeed Insights pour garder le temps total sous 60 secondes et ne pas brûler le quota PSI sur du trafic non plafonné. Pour Core Web Vitals (LCP, CLS, INP), utilisez l’authentifié POST /api/audits, qui lance PSI en parallèle du crawler.
Comment le rate limit est-il appliqué ?
Une ligne est insérée dans la table audits à chaque lancement anonyme avec user_id = NULL et ip_address à l’IP de l’appelant. Les appels ultérieurs depuis la même IP sous 24h renvoient 429. L’IP est lue depuis les en-têtes reverse-proxy standard (X-Forwarded-For), donc les audits derrière un proxy partagé peuvent entrer en collision.
Puis-je l’utiliser depuis le navigateur ?
Oui. L’endpoint définit un CORS permissif pour metricspot.com et accepte les POST cross-origin. Pour votre propre domaine, lancez une fonction serverless comme proxy fin : elle permet d’ajouter un rate-limit par tenant et évite d’exposer les IP de vos visiteurs à MetricSpot directement.
Le résultat est-il persisté quelque part ?
Une ligne existe pour le rate-limit, mais elle n’est attachée à aucun compte et n’est visible dans aucun tableau de bord. Pour sauvegarder et revisiter un audit, inscrivez-vous gratuitement et appelez POST /api/audits à la place.
Sources
Dernière mise à jour 2026-05-14