Documentation
Static Search
Use ZeroPress native search artifacts or swap to Pagefind for advanced static search.
Static Search
ZeroPress can emit dependency-free native search artifacts during a normal build:
/_zeropress/search.json/_zeropress/search.js
The theme owns the search UI. The generated adapter owns loading, tokenizing, scoring, and returning search results.
Native search is enabled only when both conditions are true:
- preview-data does not set
site.search: false - the active theme declares
features.search: true
When native search is disabled, ZeroPress does not emit /_zeropress/search.json or /_zeropress/search.js, and templates receive site.search: false so search UI can be hidden with {{#if site.search}}.
Native Search
Import the adapter from client-side theme JavaScript:
const searchApi = await import("/_zeropress/search.js");
const result = await searchApi.search("ubuntu", { limit: 10 });
for (const item of result.results) {
const data = await item.data();
console.log(data.meta.title, data.url, item.score);
}
The result shape intentionally resembles a small subset of Pagefind:
{
results: [
{
id: "post:hello-world",
score: 12.4,
data: async () => ({
url: "/posts/hello-world/",
excerpt: "Short excerpt...",
plain_excerpt: "Short excerpt...",
meta: {
title: "Hello World",
type: "post",
published_at_iso: "2026-05-01T00:00:00Z",
updated_at_iso: "2026-05-02T00:00:00Z",
categories: ["Guide"],
tags: ["ZeroPress"]
},
sub_results: []
})
}
]
}
Only options.limit is supported in the native adapter. The default limit is 20.
Indexed Content
search.json indexes published posts and pages. It does not index taxonomy routes, archive routes, 404.html, feed files, sitemap files, or standalone raw front-page HTML.
When the front page is rendered from a page, that page is indexed with the URL /.
Posts or pages with discoverability: "delist" are excluded from the native search index. site.indexing: false does not disable native search; it only changes generated fallback robots.txt. Use site.search: false to disable native search artifacts.
Each search item includes:
{
"id": "post:hello-world",
"type": "post",
"title": "Hello World",
"url": "/posts/hello-world/",
"excerpt": "Short excerpt...",
"headings": ["Install", "Usage"],
"categories": ["Guide"],
"tags": ["ZeroPress"],
"published_at_iso": "2026-05-01T00:00:00Z",
"updated_at_iso": "2026-05-02T00:00:00Z",
"content_text": "Plain searchable body text"
}
content_text is derived from rendered HTML after removing scripts, styles, tags, entities, and extra whitespace.
Scoring
The native adapter uses a small BM25-like and TF-IDF-like scorer.
Current field weights are internal defaults:
title:5headings:3tags:2.5categories:2excerpt:1.5content_text:1
Posts can receive a small recency boost. The maximum recency boost is 0.15, so it should not overpower a clearly better text match.
These values are not preview-data or theme runtime configuration. Treat them as ZeroPress-owned defaults for the native adapter.
Pagefind
For larger sites or higher search quality, Pagefind is a good post-build option:
npx pagefind --site ./_site --root-selector ".prose"
You can narrow the indexed files if needed:
npx pagefind --site ./_site --root-selector ".prose" --glob "posts/**/*.html"
Pagefind writes its own /pagefind/ assets after the ZeroPress build. A theme can keep its UI code small by isolating the search engine behind an adapter module:
const searchApi = await import("/_zeropress/search.js");
// or, for a Pagefind-enabled deployment:
// const searchApi = await import("/pagefind/pagefind.js");
Avoid probing both paths on every page view. Pick the provider for the site or theme build so browsers do not repeatedly request a missing search engine file.