Search
Query published content across your site for search-as-you-type and search results pages
The search endpoint runs a full-text query across the published content on your site and returns ranked matches. Use it to build search-as-you-type boxes, a dedicated results page, or any widget that needs to find content from the browser.
Matching is both exact and fuzzy, so close-but-imperfect queries still return useful results, and editor-configured boosts and synonyms are applied to the ranking automatically.
Search
GET {your-domain}/api/search?q={query}Unlike the content endpoints, search does not accept the .json suffix — always call the bare /api/search path.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
q | string | — | The search query. Required; a missing query returns a 400. |
collection | string | (all types) | Restrict results to one or more content types. Comma-separated; valid values are pages, posts, events, and people. Omit to search all types. An unrecognised value returns a 400. |
Results are always returned in the language of the request — search follows the locale inferred from the request URL.
Response
A docs array of ranked matches plus list metadata. Each item carries a collectionType field identifying which content type it matched, so you can group or filter results by type on the client.
{
"docs": [
{
"id": "67be2c1cb1d3f...",
"collectionType": "events",
"title": "La Traviata",
"slug": "la-traviata",
"url": "/events/la-traviata"
},
{
"id": "5f9a1b2c3d4e5...",
"collectionType": "posts",
"title": "Behind the scenes of our new season",
"slug": "behind-the-scenes",
"url": "/blogs/news/posts/behind-the-scenes"
}
],
"totalDocs": 12,
"limit": 200,
"totalPages": 1,
"page": 1,
"pagingCounter": 1,
"hasPrevPage": false,
"hasNextPage": false,
"prevPage": null,
"nextPage": null
}Search returns the full ranked set in a single response (up to 200 results); it is not paged. The exact fields on each result depend on the content type that matched, but every result includes at least an id, a collectionType, a title, and a link you can render.
Examples
Search as the visitor types:
async function search(query) {
if (!query) return [];
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
const { docs } = await res.json();
return docs;
}Group results by content type for a tabbed results page:
const { docs } = await (await fetch(`/api/search?q=${encodeURIComponent(query)}`)).json();
const byType = docs.reduce((groups, result) => {
(groups[result.collectionType] ??= []).push(result);
return groups;
}, {});
// byType.events, byType.posts, byType.people, …Caching
Search responses are cacheable at the edge. Because queries vary per visitor, popular queries benefit from caching while long-tail queries fall through to a fresh response. Avoid appending request-uniqueness parameters (cache-busters, timestamps) to the URL unless you genuinely need to bypass the cache.
See also
- Event instances — list and fetch performances.
- Content endpoints — fetch a single content type directly when you already know what you want.