API & MCP
One free endpoint, two indexes. FreeSerp Main (index=sites, default, unchanged — main pages only): 20M+ homepage profiles with LLM summaries, Domain Rating and AI niche taxonomy, filterable and sortable on every field. FreeSerp Global (index=web): full-web search over 3.1B+ pages from our own engine — any URL, any language. No key, CORS-open, or wire it in as an MCP tool.
Quickstart
A single GET request. No authentication. By default you search FreeSerp Main — main pages only, 20M+ site profiles with LLM summaries (exactly the API you may already use):
curl 'https://freeserp.ai/api.php?q=ai+chatbot&ai_startups=1&sort=went_live&order=desc&size=3'Add index=web to search the open web with FreeSerp Global — our own 3.1B+ page index. Results are ranked pages: url, title, snippet, language, publication date, and a site card (Domain Rating, category, live date) when we know the domain:
curl 'https://freeserp.ai/api.php?index=web&q=how+to+fine-tune+llama+3&size=3'Python
import requests
# FreeSerp Main (default): newest AI startups with LLM summaries
r = requests.get('https://freeserp.ai/api.php', params={
'q': 'ai chatbot', 'ai_startups': 1, 'sort': 'went_live', 'order': 'desc', 'size': 5,
})
for hit in r.json()['results']:
print(hit['domain'], '—', hit['ai_summary'][:120])
# FreeSerp Global: any page on the web
r = requests.get('https://freeserp.ai/api.php', params={'index': 'web', 'q': 'how to fine-tune llama 3', 'lang': 'en', 'size': 5})
for hit in r.json()['results']:
print(hit['url'], '—', hit['snippet'][:120])JavaScript (fetch)
const r = await fetch('https://freeserp.ai/api.php?' + new URLSearchParams({
index: 'web', q: 'best crm for small business', size: 5,
}));
const { results } = await r.json();
results.forEach(h => console.log(h.url, h.title, h.site?.dr));Discover it live:
GET /api.php?help=1 returns a machine-readable usage guide — every parameter, both indexes, recommended queries and caveats. Great as the first call an agent makes.Two indexes
FreeSerp Global — index=web | FreeSerp Main — index=sites (default) | |
|---|---|---|
| What | Full-web search: 3,132,469,027 pages from our own crawl (own extraction, own link graph), ranked by text relevance (title, headings, body, anchors), link authority and domain trust. | Main pages only: homepage-level profiles of 20M+ live sites — LLM summary, Domain Rating, AI niche taxonomy, tech stack, live date. Every field filterable and sortable. |
| Unit | a page (any URL) | a site (domain) |
| Params | q (required), lang, fresh, published_from/to, ranking, size, from | q (optional), ai_startups, ai_categories, category, ai_source, dr_min/max, from_date/to_date, sort/order, content, all… |
| Result | url, domain, title, snippet, language, published_at, crawled_at, score, site{dr, category, ai_categories, ai_source, went_live, summary}, source{index, captured_at, digest} | domain, url, title, ai_summary, category, ai_categories, ai_source, dr, went_live, first_seen, tld, http_status… |
| Depth | top 100 candidates (from+size ≤ 100); total = size of that pool, not an exhaustive count | exact total; from+size ≤ 10,000 |
| Best for | facts, how-to, comparisons, grounding, any-language questions | discovering new sites & AI startups, competitor sets, domain lookups, niche browsing |
index is omitted the request goes to FreeSerp Main — nothing changes for existing integrations. Pass index=web (alias global) to search the open web with FreeSerp Global (requires q). If FreeSerp Global is momentarily unavailable the request is served from FreeSerp Main with engine_fallback: true. On the search UI FreeSerp Global is the default tab.Endpoint
Also reachable as /api. Read-only. Responses are cached ~30s at the edge.
Parameters
| Param | Type | Default | Description |
|---|---|---|---|
| index | sites·web | sites | Which index to search (see Two indexes). web = FreeSerp Global, full-web search, needs q (alias global); sites = FreeSerp Main (alias main). Param alias: mode. |
| q | string | — | web: full-text query over any page (title, headings, body, anchors). sites: title, AI summary and homepage text; exact domain names are boosted. Omit q to browse/filter the sites index. |
| lang | iso | — | web only. Language filter: en ru de fr es ja zh it pt pl nl tr cs vi ko ar uk sv id th… Alias: language. |
| fresh | 0·1 | 0 | web only. 1 ranks fresher pages higher (same as sort=fresh). |
| published_from / published_to | date | — | web only. Publication-date window (YYYY-MM-DD). |
| ranking | enum | bm25_trust | web only, advanced. bm25_trust (text × domain trust), bm25 (text × link authority), bm25_rank, bm25_fresh. |
| sort | enum | relevance | sites: any sortable field (see Sorting); relevance = text score × Domain Rating. web: relevance or fresh. |
| order | asc·desc | desc | sites. Sort direction (ignored for relevance). |
| size | int | 20 · web 10 | Results per page, 1–100. |
| from | int | 0 | Offset for paging (sites: max 10,000; web: from+size ≤ 100). |
FreeSerp Main parameters (index=sites, the default index): | |||
| all | 0·1 | 0 | 1 also returns parked/empty domains. Default: real content sites only. |
| ai | 0·1 | 0 | 1 restricts to AI-built sites (ai_source ∈ ai_likely, lovable, base44, v0, bolt). |
| ai_startups | 0·1 | 0 | Recommended for discovering real AI startups. Keeps only genuine AI-product niches (see field values) and strips the noise that category=ai lets through — AI-flavoured Shopify shops, directories and casinos. |
| help | any | — | Present ⇒ ignore the search and return a machine-readable usage guide (params, recommended queries, caveats, field list). ?help=1. |
| content | 0·1 | 0 | 1 also returns the full extracted page text of each result under content (not just the AI summary). |
| content_max | int | — | Cap the returned page text to N characters. Omit for the full text. |
| dr_min / dr_max | int | — | Domain Rating range filter (0–100). |
| from_date / to_date | date | — | Filter by went_live (YYYY-MM-DD). |
| Plus an exact-match filter for every keyword field — pass the field name as a query param: | |||
| category | keyword | — | e.g. ai, betting/casino |
| ai_source | keyword | — | e.g. shopify, nextjs, lovable |
| ai_categories | keyword | — | AI sub-niche, e.g. Image Generation |
| tld | keyword | — | e.g. ai, io |
| webserver | keyword | — | e.g. cloudflare, nginx |
| http_status | number | — | e.g. 200 |
Response
FreeSerp Global (index=web)
{
"ok": true,
"index": "web",
"query": "how to fine-tune llama 3",
"total": 97, // de-duplicated candidate pool (≤ 100), not an exhaustive count
"count": 3, "from": 0, "size": 3,
"sort": "relevance", "ranking": "bm25_trust",
"filters": { "lang": "en" },
"took_ms": 412, "engine_ms": 388, "cached": false,
"results": [
{
"url": "https://example.com/blog/fine-tune-llama-3",
"domain": "example.com",
"title": "How to fine-tune Llama 3 on your own data",
"snippet": "… step-by-step guide to fine-tune Llama 3 with LoRA on a single GPU …",
"language": "en",
"published_at": "2026-05-14", "crawled_at": "2026-07-12",
"score": 341.2,
"site": { "dr": 41, "category": "ai", "ai_categories": ["Code & Dev Tools"], "ai_source": "nextjs", "went_live": "2026-08-22", "summary": "Example is …" },
"source": { "index": "FreeSerp Global", "captured_at": "2026-07-18T03:05:37Z", "digest": "sha1:…" }
}
],
"related_apis": { … }
}site is null when the domain is not in FreeSerp Main. source.captured_at / source.digest identify the exact capture the page came from — reproducible evidence for grounding.
FreeSerp Main (index=sites)
{
"ok": true,
"index": "sites",
"query": "ai chatbot",
"total": 48213,
"count": 3,
"from": 0, "size": 3,
"sort": "relevance", "order": "desc",
"filters": { "real_site": "1" },
"took_ms": 34, "engine_ms": 21,
"results": [
{
"domain": "example.ai",
"url": "https://example.ai",
"title": "Example — AI chatbot for support",
"ai_summary": "Example is an AI chatbot platform that …",
"category": "ai",
"ai_categories": ["AI Chatbot & Assistant"],
"ai_source": "nextjs",
"dr": 41, "went_live": "2026-08-22", "first_seen": "2026-07-10",
"tld": "ai", "http_status": 200,
"content_length": 8123, "html_size": 40213,
"_score": 3182.4
}
]
}Sorting — every field
FreeSerp Global: sort=relevance (default) or sort=fresh. FreeSerp Main: pass any of these as sort=, with order=asc|desc:
All fields
FreeSerp Global results always carry: url domain title snippet language published_at crawled_at score site{…} source{index, captured_at, digest}.
Sites index — every field returned per result, and whether you can filter or sort on it:
| Field | Type | Sort | Filter | Description |
|---|---|---|---|---|
| domain | keyword | ✓ | ✓ | Registered domain (e.g. example.com) |
| title | text | — | ✓ | Page <title> |
| ai_summary | text | — | ✓ | LLM-generated factual overview of the site |
| category | keyword | ✓ | ✓ | High-level category: 'ai', 'betting/casino', or null |
| ai_categories | keyword | ✓ | ✓ | AI sub-niche taxonomy (multi-valued) |
| ai_source | keyword | ✓ | ✓ | Builder / stack signal: wordpress, shopify, nextjs, lovable, v0, bolt, base44, ai_likely, not_ai… |
| dr | number | ✓ | ✓ | Domain Rating 0–100 (authority proxy) |
| went_live | date | ✓ | ✓ | Date the liveness probe first confirmed the site live |
| first_seen | date | ✓ | ✓ | Date the domain was first discovered |
| real_site | number | ✓ | ✓ | 1 = real content site, 0 = parked/empty/error |
| tld | keyword | ✓ | ✓ | Top-level domain (com, ai, io…) |
| http_status | number | ✓ | ✓ | Last HTTP status of the homepage |
| content_length | number | ✓ | ✓ | Extracted text length (bytes) |
| html_size | number | ✓ | ✓ | Raw HTML size (bytes) |
| webserver | keyword | ✓ | ✓ | Server header (nginx, Apache, cloudflare…) |
| ip | ip | ✓ | ✓ | Resolved IP address |
| fetched_at | date | ✓ | — | When the HTML was last fetched |
Field values
The keyword fields you filter on take a fixed set of values. The most useful:
category
Broad heuristic bucket. ai betting/casino (null)
— ai is deliberately wide; prefer ai_startups=1 / ai_categories for real AI products.
ai_source — builder / tech stack
AI-builder signals: ai_likely lovable v0 bolt base44 · classic stacks: wordpress shopify wix webflow nextjs react not_ai
ai_categories — AI sub-niche (multi-valued)
Counted as a real AI startup by ai_startups=1:
AI Agents & Autonomous Code & Dev Tools AI Infrastructure & API
AI Automation & Workflows LLM & Prompt Tools AI Search & Answers
AI Website Builder No-code / App Builder Image Generation
Video Generation Voice & Text-to-Speech Data & Analytics
Research & Science Design & UI Chatbot & Assistant
Also present but treated as noise for startup discovery: E-commerce, Directory / Aggregator, Marketing & Ads, Sales & CRM, Lead Gen & Outreach, Finance & Trading, Healthcare & Medical, Education & Tutoring, Other AI, …
GET /api.php?help=1 and the MCP freeserp_list_endpoints tool both enumerate the live surface — never hard-code, ask the API.Caveats — read this
| Field / filter | What it really means |
|---|---|
| total (web) | FreeSerp Global returns the top 100 candidates after de-duplication; total is the size of that pool, not how many pages match on the whole web. Page inside the window with from/size. |
| published_at (web) | The page's own publication date when it declares one (meta / schema / visible date). Missing for many pages — then use crawled_at, the date we fetched it. |
| freshness (web) | FreeSerp Global is refreshed in batches from our own crawl; a page changed or created after its last capture (crawled_at) is not reflected yet. FreeSerp Main is refreshed daily. |
| engine_fallback | Present and true when the web engine was unavailable and the response was served from the sites index instead. |
| went_live | The date FreeSerp's liveness probe first confirmed the site reachable — not the startup's official launch date. A domain can be registered or launched well before we first see it live. |
| category=ai | A broad keyword heuristic (AI phrases in the HTML). It also flags AI-flavoured Shopify shops, directories and casinos. For genuine AI products use ai_startups=1 and/or ai_categories. |
| ai_source=ai_likely | A heuristic "looks AI-built" signal — useful but noisy on its own. Combine with ai_categories for precision. |
| dr | Domain Rating 0–100 from our own web-graph (Ahrefs-calibrated), not a live third-party API. Brand-new domains may still read dr: null until scored. |
| first_seen | When the domain entered our discovery feed (often its NRD registration date), not when it went live. |
Data & coverage
FreeSerp Global: 3,132,469,027 pages, built and ranked by us — own crawl, own extraction, own link graph for authority and domain trust. Languages: en 1,256M, ru 228M, de 187M, fr 162M, ja 160M, es 158M, zh 140M, it, pt, pl, nl, tr, cs, vi and more. Every result is reproducible down to the capture (source.captured_at, source.digest).
FreeSerp Main (main pages only): ~20M live sites from our own continuously-refreshed discovery pipeline (newly-registered domains are probed daily; live ones are crawled, LLM-summarised, categorised and DR-scored). Global — every TLD and language. Each record is the homepage: title, extracted text, ai_summary, tech stack, DR and live date. It is a discovery index of what is newly live on the web — not a crawl of every page of every site (that is what FreeSerp Global is for).
Limits, paging & errors
Rate limits
No hard limit and no key — the service is free and open. Please be reasonable (a few requests/second), cache when you can, and identify yourself so we can reach you before a change or ask you to ease off instead of blocking. Responses are edge-cached ~30s.
Paging
Web: from + size ≤ 100 — the engine returns the top-100 candidates for a query; refine the query or add lang/published_from instead of paging deeper. Sites: size ≤ 100 per page; from + size ≤ 10,000. To pull a large set, narrow with filters (date range, ai_categories, dr_min) rather than paging to the cap.
Errors
HTTP 200 with "ok": true on success. On failure you get a non-2xx with an error body:
{ "ok": false, "error": "upstream", "detail": "search_phase_execution_exception" }| Status | Meaning |
|---|---|
| 200 | OK — results (may be empty; check total). |
| 204 | CORS pre-flight (OPTIONS). |
| 400 | query_required — index=web needs q; use index=sites to browse without a query. |
| 502 | Upstream search error — retry with backoff (web-engine outages are normally masked by engine_fallback). |
Bad params never error — unknown filters are ignored and an invalid sort falls back to relevance, so a query always returns something. The echoed filters object shows exactly what was applied.
Statistics
A live snapshot of the whole index, refreshed every 30 minutes — no heavy query on your side.
{
"ok": true,
"generated_at": "2026-09-06T10:16:35+00:00",
"web_index": { "name": "FreeSerp Global", "pages": 3132469027, "nodes": 18, "languages": { "en": 1256209788, "ru": 228281221, … }, "engine_ready": true },
"totals": { "real_sites": 16273795, "all_sites": 21086714 },
"new": { "today": 29247, "yesterday": 31800, "last_7d": 232787, "last_30d": 11289030 },
"ai_startups": { "total": 33429, "today": 72 },
"by_category": [ {"key":"ai","count":78674}, {"key":"betting/casino","count":806182} ],
"top_ai_categories": [ {"key":"AI Agents & Autonomous","count":10467}, … ],
"top_ai_source": [ … ], "top_tld": [ … ],
"dr": { "avg": 8.4, "min": 0, "max": 99, "histogram": [ … ] },
"by_day": [ {"key":"2026-09-06","count":29247}, … ],
"gambling": { "today": {"original":…,"affiliate":…}, "total": {…} },
"pipeline": { "summary_todo": …, "went_live_today": …, "probe_due": … }
}Over MCP, the same snapshot is the freeserp_stats tool. The robot also keeps 30 days of half-hourly history in freeserp_stats for trend charts.
Examples & recipes
★ Answer a question from the web (index=web)
curl 'https://freeserp.ai/api.php?index=web&q=how+does+chatgpt+search+choose+sources&size=5'English results, fresher pages first
curl 'https://freeserp.ai/api.php?index=web&q=best+link+indexing+services&lang=en&fresh=1'Pages published this year only
curl 'https://freeserp.ai/api.php?index=web&q=gpt-5+pricing&published_from=2026-01-01&size=10'Grounding for an agent: ask, then read the site card
r = requests.get('https://freeserp.ai/api.php', params={'index': 'web', 'q': 'best backlink indexing service', 'size': 8}).json()
for h in r['results']:
site = h['site'] or {}
print(h['url'], '| DR', site.get('dr'), '|', site.get('summary', '')[:80])★ Discover new AI startups in a niche (default index — recommended combo)
curl 'https://freeserp.ai/api.php?ai_startups=1&ai_categories=AI%20Agents%20%26%20Autonomous&from_date=2026-09-01&sort=went_live&order=desc'Newest AI sites, most authoritative first
curl 'https://freeserp.ai/api.php?ai=1&sort=dr&order=desc&size=10'All sites built on Shopify, most authoritative first
curl 'https://freeserp.ai/api.php?ai_source=shopify&sort=dr&order=desc&size=25'High-DR news sites that went live in the last two weeks
curl 'https://freeserp.ai/api.php?q=news&dr_min=30&from_date=2026-08-16&sort=went_live&order=desc'Browse by niche, no text query
curl 'https://freeserp.ai/api.php?ai_categories=Image%20Generation&sort=dr&order=desc'Return full page text, not just the summary
curl 'https://freeserp.ai/api.php?q=ai+chatbot&content=1&content_max=4000&size=3'Look up one exact domain (record, DR, stack, summary)
Pass the full domain (any TLD) as q — it is boosted to the top; take the first result and confirm results[0].domain matches. Add all=1 so parked/empty domains still resolve.
curl 'https://freeserp.ai/api.php?q=mynewstartup.ai&all=1&size=1'results[0].domain ≠ your query, the domain isn't in that index; the web index still has its pages.Is this a real site or parked/dead?
Check real_site and http_status on the returned record (1 = real content, 0 = parked/empty/error).
curl 'https://freeserp.ai/api.php?q=somedomain.io&all=1&size=1'Find competitors / similar sites in a space
curl 'https://freeserp.ai/api.php?q=vector+database&ai_startups=1&dr_min=10&sort=dr&order=desc&size=25'from_date/to_date week-windows with a fixed ai_categories filter, or tighten with dr_min.Identify yourself (optional)
There is no key and no signup — which also means that when something is about to change, we have no way to reach you. These four fields fix that. Every one is optional, nothing is validated, and none of them affect your results.
curl 'https://freeserp.ai/api.php?q=ai&agent=MyAgent/1.0&[email protected]&project=Acme&website=https://acme.com'| Field | Example | Purpose |
|---|---|---|
| agent | MyAgent/1.0 | Your agent name + version (also accepted as the X-Agent header). |
| [email protected] | Contact address — contact= works the same. Used only to reach a human about this API. | |
| project | Acme Research | The project/product making the calls. |
| website | https://acme.com | Project website. |
Over MCP, pass the same fields as arguments to any freeserp_search call. Sending them once is enough. What it buys you: we can warn before a breaking change, ask what you are missing, and — if your traffic starts hurting the service — ask you to slow down instead of blocking you. Stored privately next to request counts; never published, never shared.
MCP connector
FreeSerp ships a hosted Streamable-HTTP MCP server — one URL, no install. Tools and their schemas are generated live from the field registry, so they never drift from the API.
A plain GET on that URL returns the live tool catalog (server, transport, tool_count, and every tool with its description) — same shape your client discovers over JSON-RPC:
curl 'https://freeserp.ai/mcp'Add it to Claude (Desktop / Code / any MCP client)
Point the client at the remote endpoint via mcp-remote:
{
"mcpServers": {
"freeserp": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://freeserp.ai/mcp"]
}
}
}Restart the client — your agent now has these tools:
| Tool | What it does |
|---|---|
| freeserp_search | The main search over both indexes. Default index: "sites" (FreeSerp Main) with ai_startups, ai_categories, sort, filters…; index: "web" with q, lang, fresh, published_from/to for the open web (FreeSerp Global). |
| freeserp_help | Usage guide: quickstart, every param, recommended AI-startup query, caveats. Call this first. |
| freeserp_stats | Live index statistics — totals, new today/7d, AI-startup counts, top niches/TLDs, DR distribution (refreshed every 30 min). |
| freeserp_list_endpoints | Field catalog — every field with type and whether it is sortable/filterable. |
| freeserp_get | Escape hatch: raw GET of the REST API with any query string. |
freeserp_help (or freeserp_list_endpoints) first — it learns every field and the recommended ai_startups combo, so it composes precise queries on its own instead of guessing.Raw JSON-RPC
Talk to it directly — initialize, then tools/list / tools/call:
# discover tools
curl -s 'https://freeserp.ai/mcp' -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# run a search
curl -s 'https://freeserp.ai/mcp' -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{
"name":"freeserp_search",
"arguments":{"q":"ai chatbot","ai_startups":true,"sort":"went_live","size":5}}}'
# FreeSerp Global: any page on the web
curl -s 'https://freeserp.ai/mcp' -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{
"name":"freeserp_search",
"arguments":{"index":"web","q":"how to fine-tune llama 3","lang":"en","size":5}}}'/api.php and skip MCP entirely.