Measure a site.
Give your agent the next fix.
A public HTML score, evidence, and actionable improvements.
Analyze any public website
Use your app’s confirmed Supabase session token. The URL is normalized to a domain, checked across representative public pages, and saved to your Builder dashboard.
curl "$AF_ORIGIN/api/analyze" \
-H "Authorization: Bearer $AF_SESSION_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"url":"https://example.com/products/item"}'AF_ORIGIN is your deployed origin, or http://localhost:3100 locally. Export a current access token obtained through your own app sign-in. Do not put tokens in URLs or source control.
{ "id": "JOB_ID", "domain": "example.com", "status": "queued", "saved": true }This is a fictional response. Poll GET /api/jobs/JOB_ID every two seconds. A complete job has a run_id; retrieve GET /api/runs/RUN_ID. A cached response already has the run ID and needs no polling.
Use the portable client
import { analyzeURL } from './api-client.js';
const report = await analyzeURL({
origin: process.env.AF_ORIGIN,
url: 'https://example.com',
token: process.env.AF_SESSION_TOKEN,
onJob: job => console.log(job.status)
});
console.log(report.score, report.coverage, report.recommendations);Download the client above. It works in Node 22+ or a browser, bounds polling, respects Retry-After and attempts recovery if a job expires. A failed check stays unscored; inspect its coverage rather than treating null as zero.
Choose the right endpoint
| Endpoint | Access | Behavior |
|---|---|---|
| POST /api/analyze | Confirmed session | Analyze + save. Fresh measured results reused for six hours. refresh:true uses a one-minute cooldown. |
| POST /api/benchmarks | Session or configured benchmark key | CLI remeasurement. Five-minute cooldown. No dashboard save. |
| POST /api/discover | Public | Add a domain; normally return indexed results. No private saved-site access. |
| GET /api/jobs/:id GET /api/runs/:id GET /api/sites/:domain | Public | Read job state, immutable run or site history. |
Never use a Supabase service-role key as a user bearer token. Session tokens expire: refresh through Supabase, then retry a rejected request. A deployment benchmark key is accepted only by the benchmark route.
Five states. One clear outcome.
queued → running → complete → GET /api/runs/:run_id
cached → GET /api/runs/:run_id
failed → inspect error; retry laterJobs are in memory and expire six hours after completion or on server restart. Keep the job ID and domain when polling times out. Use GET /api/sites/:domain to recover a newly completed result, or request a new check. Runs retain the last 120 per site; they are not stored forever.
Only status: measured with a numeric score represents a full basic result. limited and unavailable have no score. At least five readable pages are required. No login, checkout, payment or CAPTCHA bypass is performed.
Errors you can handle
{
"error": "Sign in to continue.",
"code": "UNAUTHORIZED",
"request_id": "server-generated-request-id"
}Every response includes X-Request-ID. Errors repeat it in the body so a client can report a specific request without disclosing credentials.
| Status | Next action |
|---|---|
| 400 / 413 | Correct the public URL or reduce the JSON body to 4,096 characters. |
| 401 | Sign in with a confirmed account or refresh your session. |
| 404 | Check the identifier; expired jobs may still have saved site results. |
| 429 | Wait for Retry-After seconds. Do not retry in a tight loop. |
| 503 | Retry later; account, persistence or service setup may be unavailable. |
The beta limits benchmark requests to 12 per hour per socket IP and brand search to 20 per minute. Shared networks share these limits. The catalog has a 500-site capacity. Private and loopback destinations, credential-bearing URLs and custom ports are rejected. Redirect destinations are checked too.
Keep a baseline. Compare the evidence.
AGENT_FRIENDLY_URL=https://YOUR_HOST \
npm run harness -- example.com BASELINE_RUN_IDThe harness runs from the source checkout. Set the server’s configured private benchmark key as BENCHMARK_API_KEY for CLI access. Compare the same domain, profile and benchmark version after the five-minute cooldown. A score change is not evidence of a sales change.
The server schedules tracked sites every six hours and resumes overdue checks on restart. Use one scheduler with persistent storage. Deep Agentic Rubric is a separate engineering specification; a readable HTML score does not certify idempotency, delegated authorization or partner checkout.
Send a concrete observation
Discover an active verified-owner inbox with GET /api/feedback-target/example.com. Use the feedback schema and avoid private buyer data.
POST /api/feedback
Content-Type: application/json
{
"domain": "example.com",
"kind": "agent",
"agent_name": "Site review agent",
"topic": "Other",
"message": "Dispatch and arrival times are not distinguished.",
"page_url": "https://example.com/shipping"
}Agent identity is self-reported. Feedback stays separate from measured scores. Only a verified owner can read the private inbox. Write feedback that can become a fix ↗