Search records across your entities
Full-text search across your entities from the dashboard, CLI or REST API: pick searchable fields, filter and sort, find similar records, and search publicly.
Last updated
Anythink keeps a search index of your records, powered by Meilisearch. Every time you create, update or delete a record the index is updated in the background, so there is nothing to set up beyond choosing which fields are searchable. One query can search every entity in your project at once, or just the ones you name. It handles typos, ranks the best matches first, and can filter, sort, count and highlight.
There are two ways in:
| Signed-in search | Public search | |
|---|---|---|
| Endpoint | GET /org/{project_id}/search |
GET /org/{project_id}/search/public |
| Needs a token | Yes, a signed-in user | No |
| Fields returned | The whole record | Only publicly searchable fields |
| Row-level security | Applied | Not applicable: public fields only |
| Use it for | Your own app, once people have signed in | A blog, docs site or catalogue anyone can search |
Your project ID is the number after /org/ in the dashboard address. The examples use https://api.my.anythink.cloud as the API URL. For how users get a token, see Sign in users.
What search covers
Search covers the fields you mark as searchable, on every entity in the project. Two flags on each field control it:
| Flag | In the dashboard | What it does |
|---|---|---|
is_searchable |
Searchable | The field's text is matched by search. The field can also be used to filter, sort and count (facets). |
publicly_searchable |
Publicly Searchable | The field is also matched by public search, and returned in its results. Only available on a searchable field. |
A few rules sit on top of that:
- The name field. The field you mark as the entity's name field is the record's label. Search always matches it, and ranks matches in it highest. Signed-in results carry it as
__name. In the dashboard, ticking Name field ticks Searchable for you. idis always searchable, so searching for a record's ID finds it.- Ranking. A match in the name field beats a match in a text field, which beats a match in any other searchable field, which beats a match in a related record's name.
- Relationships. A searchable many-to-one, one-to-one or user field is matched on the name of the record it points to. Searching for an author's name finds their articles.
- Fields you leave off. A field that isn't searchable is never matched. It can still appear in a signed-in search result, because those return the whole record.
- No setup for new records. Indexing is automatic.
In the Anythink dashboard
- Open Settings › Data Model and choose the entity.
- Open a field, or add a new one.
- In the Performance & API card, tick Searchable. Tick Publicly Searchable as well if anonymous visitors should be able to search it.
- Save the field.
Back on the entity's field list, small badges show the flags: S for searchable, PS for publicly searchable and NF for the name field.
To search from anywhere in the dashboard, press Cmd+K (Ctrl+K on Windows and Linux), and type into Search for anything.... It runs a signed-in search across all your entities.
With the CLI
# Add a searchable field, public as well
anythink fields add articles title --type varchar --name-field --searchable --public
# Change an existing field
anythink fields update articles body --searchable
anythink fields update articles status --searchable --public
# Turn the flags off again
anythink fields update articles body --no-searchable
anythink fields update articles status --no-public
--public sets Publicly Searchable. Check the result with anythink fields list articles.
With an AI assistant (MCP)
On the articles entity, make title and body searchable, and make title and status publicly searchable.
The assistant runs fields update through the cli tool for each field. Connect an AI assistant sets up the MCP server. Field types are covered in Field types.
Search from the API
Send the signed-in user's access token and a query:
GET /org/{project_id}/search?q=espresso&e=articles
Authorization: Bearer <access token>
{
"items": [
{
"id": "1",
"created_at": "2026-10-04T13:38:09.288332Z",
"updated_at": "2026-10-04T13:38:09.288332Z",
"title": "Espresso guide",
"body": "Grind fine and pull a double shot",
"status": "published",
"__name": "Espresso guide",
"__entity": "articles",
"__url": "/org/{project_id}/entities/articles/items/1"
}
],
"page": 1,
"page_size": 20,
"total_items": 1,
"total_pages": 1,
"has_next_page": false,
"has_previous_page": false,
"retrieval_time": 4,
"facet_distribution": null
}
Each item is the record, plus __entity (the entity it came from), __url (the path to the record) and __name (its name field). retrieval_time is milliseconds spent searching. Results from several entities arrive in one list, and __entity tells you which is which.
| Parameter | Meaning |
|---|---|
q |
The search text. Leave it out, or send *, to match everything. |
e |
Comma-separated entity names to search, such as e=articles,products. Leave it out to search every entity. |
q=field:text |
Search a single field. q=title:espresso matches espresso in title only. An entity without that searchable field is skipped. |
s |
Sort, such as s=created_at:desc. See filters and sorting. |
fl |
A filter expression, such as fl=status = published. |
f |
Comma-separated fields to count values for (facets), such as f=status,category. |
hl |
hl=true adds a _formatted copy of each record with matches wrapped in <mark> tags. |
page |
Page number, starting at 1. Default 1. |
pageSize |
Results per page, 1 to 100. Default 20. |
Text before a colon in q is read as a field name, so leave colons out of free-text queries.
In the Anythink dashboard
Use the Cmd+K search box for quick lookups. Filters, sorting, facets and highlighting are API features: the dashboard's search box sends the text only.
With the CLI
anythink search query espresso
anythink search query espresso --entities articles
anythink search query "*" --entities articles --filter "status = published" --sort "created_at:desc" --limit 10
anythink search query espresso --entities articles --facet status --highlight --page 2
anythink search query espresso --json
| Option | Sends |
|---|---|
--entities <LIST> |
e |
--filter <EXPR> |
fl |
--sort <LIST> |
s |
--facet <FIELDS> |
f |
--highlight |
hl=true |
--page <N>, --limit <N> |
page, pageSize (1 to 100) |
--public |
Uses /search/public instead |
--json |
Prints the raw response |
Without --json the CLI prints each match as entity/id — name, with its created time and URL, and a page footer when there is more than one page. anythink fetch calls the endpoint directly if you want the raw HTTP: anythink fetch "/search?q=espresso&e=articles".
With an AI assistant (MCP)
Search my articles for espresso and show the three newest published ones.
The assistant runs search query espresso --entities articles --filter "status = published" --sort "created_at:desc" --limit 3 through the cli tool. See MCP tool reference.
Search without signing in
For a blog, documentation site or catalogue where visitors aren't signed in, call the public endpoint. It takes no token and the same q, e, s, fl, f, page and pageSize parameters:
GET /org/{project_id}/search/public?q=espresso&e=articles
{
"items": [
{
"id": "1",
"created_at": "2026-10-04T13:38:09.288332Z",
"updated_at": "2026-10-04T13:38:09.288332Z",
"title": "Espresso guide",
"status": "published",
"__entity": "articles",
"__url": "/org/{project_id}/entities/articles/items/1"
}
],
"page": 1,
"page_size": 20,
"total_items": 1,
"total_pages": 1,
"has_next_page": false,
"has_previous_page": false,
"retrieval_time": 0,
"facet_distribution": null
}
What public search does differently:
- It only matches publicly searchable fields. Text in a field that is only Searchable is never matched, so a visitor can't discover it by guessing words.
- It only returns publicly searchable fields, plus five default fields on every result:
id,created_at,updated_at,__entityand__url. In the example,bodyis searchable but not public, so it is absent. - It only searches entities with at least one publicly searchable field (other than
id). Entities without one never appear, even if you name them ine. - A field search such as
q=title:espressoonly works on a publicly searchable field. Any other field returns no results.
Treat everything in a publicly searchable field as public. Before you open a site to visitors, mark only the fields you'd be happy to show on a web page.
In the Anythink dashboard
Turn on Publicly Searchable for the fields you want to expose, as described in What search covers. Keep Searchable only on fields that are for signed-in users.
With the CLI
anythink search query espresso --public
anythink search query "*" --public --entities articles --limit 5
anythink search audit articles
search audit runs the same query publicly and signed in, and reports whether the public results contain any field you haven't marked publicly searchable. Run it after changing which fields are public.
With an AI assistant (MCP)
Check what an anonymous visitor can search on the articles entity, and list the fields that are public.
The assistant runs search query with --public and search audit articles through the cli tool.
Filters and sorting
Filters use Meilisearch's expression syntax and go in the fl parameter. Your filter is combined with a restriction to your project, so it can only narrow results.
| You want | Filter |
|---|---|
| Equals | status = published |
| Not equal | status != draft |
| One of several values | status IN [published, scheduled] |
| Both conditions | status = published AND category = news |
| Either condition | status = draft OR status = scheduled |
| Negate | NOT status = draft |
| Number comparison | id > 100, id >= 10 AND id < 50 |
| Has a value | subtitle EXISTS |
Quote values that contain spaces: title = "Cold brew notes". URL-encode the whole expression when you build the URL by hand.
You can filter, sort and count (f) on:
- Every field marked Searchable.
- The record's
id,created_atandupdated_at. - Your many-to-one, one-to-one and user fields, searchable or not.
Filtering on any other field returns an error, so mark the field searchable first.
Sorting. Give s one or more field:direction pairs, comma separated: s=created_at:desc,id:asc. Direction is asc or desc. Sort fields that aren't searchable are ignored, and results then come back in relevance order. Without s, results are ranked by relevance.
Facets. f=status returns a count of each value of status among the matches, in facet_distribution:
"facet_distribution": {
"status": { "draft": 1, "published": 2 }
}
Counts from several entities are added together. That makes facets good for category filters and tag lists on a search page.
Geo fields. If an entity has a geo field, you can also filter with _geoRadius(lat, lng, distanceInMeters) or _geoBoundingBox([lat, lng], [lat, lng]), and sort with _geoPoint(lat, lng):asc.
Find similar records
Anythink also builds a semantic (vector) index of each entity from its searchable text fields and related names, so it can find records with similar meaning, even without shared keywords. Use it for "more like this" and "related articles".
GET /org/{project_id}/search/similar?e=articles&id=1&limit=10
Authorization: Bearer <access token>
The response is a list of records, most similar first, not wrapped in the paginated shape:
[
{
"id": "3",
"title": "Espresso machines compared",
"body": "Pump pressure and boiler types",
"status": "published",
"__name": "Espresso machines compared",
"__entity": "articles",
"__url": "/org/{project_id}/entities/articles/items/3"
}
]
| Parameter | Meaning |
|---|---|
e |
The entity name. Required. |
id |
The record to find neighbours of. Required. |
limit |
How many to return. Default 10. |
An unknown entity or a record that isn't indexed returns 404. The source record itself isn't included. If the entity uses row-level security, records you can't read are removed, so you may get fewer than limit.
In the Anythink dashboard
The dashboard has no "similar records" screen. Use the CLI or the API.
With the CLI
anythink search similar articles 1
anythink search similar articles 1 --limit 5 --json
With an AI assistant (MCP)
Find articles similar to article 1.
The assistant runs search similar articles 1 through the cli tool.
Row-level security and search
Search respects who is asking.
- Signed-in search applies row-level security. For an entity with row-level security on, each matching record is checked against the signed-in user, and records they aren't allowed to read are removed from the results. Entities without row-level security return all matches. A page can therefore hold fewer items than
pageSize. - Public search never depends on a user. It returns only publicly searchable fields. Don't put anything in a publicly searchable field that you wouldn't show an anonymous visitor, even on an entity that uses row-level security.
- Similar records follow the same rule as signed-in search.
How access is granted is covered in Groups and row-level security and Roles and permissions.
Rebuild the search index
Rehydrating re-sends every record of an entity, or of the whole project, from your database to the search index. Existing entries are replaced and no data is lost. It runs in the background, so results can look incomplete until it finishes. Only a project administrator can start one.
| Task | Endpoint | Response |
|---|---|---|
| Rehydrate every entity | POST /org/{project_id}/search/rehydrate |
204 No Content |
| Rehydrate one entity | POST /org/{project_id}/search/rehydrate/{entity_name} |
204 No Content |
In the Anythink dashboard
- Open Settings › Operations.
- Under Search Operations, click Rehydrate Search Data for everything, or use the Rehydrate button beside one entity.
- Confirm. A message tells you the job has been queued.
The same page has a Purge button, which empties the index. Rehydrate afterwards to fill it again.
With the CLI
anythink search rehydrate articles
anythink search rehydrate --yes
Without --yes the CLI asks you to confirm. Leave out the entity to rehydrate everything. anythink search purge [entity] empties the index in the same way, and you then run search rehydrate to repopulate it.
With an AI assistant (MCP)
Rehydrate the search index for the articles entity.
The assistant runs search rehydrate articles --yes through the cli tool. Ask it to check with you first if you'd like a confirmation step.
Limits
| Limit | Detail |
|---|---|
| Results per page | 1 to 100. Default 20. |
| Reachable results | 1,000 per query for each entity. Narrow the query with q, e or fl instead of paging deeper. |
| Page number | 1 or more. |
| Similar records | limit defaults to 10. |
| Filter, sort and facet fields | Searchable fields, relationship fields, and id, created_at, updated_at. |
| Public search | Publicly searchable fields only, plus id, created_at, updated_at, __entity and __url. |
| Index updates | Background, so a change is searchable a moment after you save it. |
| Rehydrate and purge | Project administrators only. |
| Who can call signed-in search | A signed-in user with access to the project. |