Developer preview

Build on top of a private search index.

Purili exposes the same JSON endpoints used by the web app: organic search, suggestions, infocards, image search, news, favicons, and crawl submission. The API is still experimental, but it is already useful for prototypes, dashboards, browser integrations, and local search tools.

Base URL

https://puri.li

Format

JSON by default

Core index

Purili crawler

Status

Experimental

Quickstart

Start with /api/search. The GET endpoint is easiest for browser extensions and simple scripts. POST returns the same shape.

curl
curl -sS 'https://puri.li/api/search?q=duckduckgo&page=1' | jq
fetch
const res = await fetch("https://puri.li/api/search?q=duckduckgo&page=1")
const data = await res.json()

for (const result of data.results) {
  console.log(result.title, result.url)
}

Search operators

Search supports a small set of dork-style operators. They work through the same endpoint as normal text queries.

site:example.com

Restrict results to a host or its subdomains.

"exact phrase"

Require an exact phrase in the text query.

-term

Exclude results containing a term.

intitle:privacy

Require a word or phrase in the result title.

inurl:docs

Require a word in the URL.

filetype:pdf

Filter by file extension where known.

Endpoint reference

All examples are relative to https://puri.li.

Current version: unversioned preview

GET/api/search

Search

Returns ranked organic results from Purili's local index, plus totals, pagination state, latency, and optional query correction metadata.

qpageexact
request
/api/search?q=site:duckduckgo.com%20privacy&page=1
sample response
{
  "results": [
    {
      "id": "crawled-0-1",
      "title": "DuckDuckGo - Protection. Privacy. Peace of mind.",
      "url": "https://duckduckgo.com/",
      "displayUrl": "duckduckgo.com",
      "description": "The Internet privacy company that empowers you to take control of your personal information online.",
      "favicon": "/api/favicon?host=duckduckgo.com",
      "source": "crawled"
    }
  ],
  "total": 174,
  "timeMs": "0.09",
  "hasNext": true,
  "totalPages": 2,
  "page": 1
}
POST/api/search

Search with JSON

Same response as GET. Use this when you do not want query text in the URL or when your client prefers JSON request bodies.

qpageexact
request
{
  "q": "google finance",
  "page": 1,
  "exact": false
}
sample response
{
  "results": [
    {
      "title": "Google Finance",
      "url": "https://google.com/finance",
      "displayUrl": "google.com › finance",
      "description": "Real-time market quotes, financial news, and portfolio data.",
      "source": "crawled"
    }
  ],
  "correction": null
}
GET/api/suggest

Autocomplete

Returns cleaned autocomplete phrases from Purili's own index and curated local suggestions. Gambling, adult, URL-like, and noisy all-caps suggestions are filtered.

q
request
/api/suggest?q=google%20m
sample response
[
  "google maps",
  "google mail",
  "google meet",
  "google my business"
]
GET/api/correct

Query corrections

Returns local spelling or spacing correction metadata. Search responses may already include the same correction object.

q
request
/api/correct?q=EU%20webhosting
sample response
{
  "type": "showing",
  "original": "EU webhosting",
  "corrected": "EU web hosting"
}
GET/api/infocard

Infocards

Returns local Wikipedia-derived entity data and instant answers when available. Null means Purili has no confident card for that query.

q
request
/api/infocard?q=capital%20of%20the%20UK
sample response
{
  "title": "United Kingdom",
  "entityType": "place",
  "displayType": "Place",
  "instantAnswer": {
    "question": "capital of united kingdom",
    "answer": "London",
    "sourceLabel": "Infobox country - capital"
  },
  "facts": [
    { "label": "Capital", "value": "London" },
    { "label": "Currency", "value": "Pound sterling" }
  ],
  "sourceUrl": "https://en.wikipedia.org/wiki/United_Kingdom"
}
GET/api/images

Images

Image results used by the Images tab. This currently searches Wikimedia Commons and proxies image URLs through Purili.

qpage
request
/api/images?q=mountains&page=1
sample response
{
  "images": [
    {
      "id": "wm-File:Mountain.jpg",
      "title": "Mountain",
      "url": "/api/image-proxy?url=...",
      "thumbUrl": "/api/image-proxy?url=...",
      "width": 400,
      "height": 300,
      "source": "wikimedia",
      "license": "CC BY-SA"
    }
  ],
  "total": 24,
  "page": 1
}
GET/api/news

News

Returns cached news feed items used by the News tab. The endpoint is optimized for the Purili UI rather than a stable public contract.

q
request
/api/news?q=technology
sample response
{
  "items": [
    {
      "id": "a1b2",
      "title": "Technology headline",
      "description": "Short summary from the feed.",
      "url": "https://example.com/article",
      "source": "Example News",
      "category": "technology",
      "publishedAt": "2026-07-07T09:30:00.000Z",
      "imageUrl": "/api/news-image?id=..."
    }
  ]
}
GET/api/favicon

Favicons

Fetches, normalizes, and caches site icons for result rendering. Returns an image response, not JSON.

host
request
/api/favicon?host=wikipedia.org
sample response
HTTP/1.1 200 OK
Content-Type: image/png
Cache-Control: public, max-age=604800, immutable
GET/api/crawler-stats

Index stats

Crawler and index counters used by the public stats page. Useful for dashboards and operational checks.

no parameters
request
/api/crawler-stats
sample response
{
  "pages_indexed": 39113872,
  "index_size_bytes": 64563604275,
  "queue_depth": 0,
  "estimated_unique_domains": 1117539,
  "pages_per_sec": 273.8
}
GET/POST/api/submit-site

Site submission

Queues public URLs as crawl seeds after a lightweight challenge and rate limit. Intended for the Add site form.

urltokenanswer
request
GET /api/submit-site
POST /api/submit-site
{
  "url": "https://example.org/",
  "challengeToken": "<challenge token>",
  "challengeAnswer": "12"
}
sample response
{
  "ok": true,
  "url": "https://example.org/",
  "seedCount": 3,
  "message": "Queued 3 crawl seeds."
}

Response schema

Search response

resultsArray of ranked organic results.
totalEstimated reachable result count after filtering and diversification.
timeMsFrontend plus backend search latency, expressed in seconds.
hasNextWhether the next page is expected to have results.
totalPagesReachable pagination horizon, not a raw Tantivy total divided by ten.
pageCurrent result page.
correctionOptional object describing showing-results-for or did-you-mean behavior.

Result object

idStable enough for rendering, not guaranteed as a permanent document ID.
titleCleaned result title.
urlCanonical result URL.
displayUrlReadable host/path display for UI breadcrumbs.
descriptionCleaned indexed snippet.
faviconOptional local favicon endpoint URL.
sourceUsually crawled. Can be generated for local synthetic results.

Corrections

A search response can include correction. Typeshowing means Purili already searched the corrected query. Type suggestion means clients should show a did-you-mean link.

{
  "type": "showing",
  "original": "yahoo financ",
  "corrected": "yahoo finance"
}

Authentication

No public API keys yet. Current endpoints are open and experimental.

Rate limits

No formal public quotas yet. Keep automated use light and cache responses.

Privacy

Core search and suggestions use Purili's own index. No per-query tracking is intentionally added.

Contracts

Response shapes may change until versioned API routes are introduced.