# Searching

> Queries, filters, facets, sorting, paging, and highlighting, from the browser or your server.

The browser and server SDKs take the same search request. The examples use the browser client:

```ts
import { SearchBrowserClient } from "@findlane/browser"

const client = new SearchBrowserClient({ publicId: "pub_your_public_id" })

const results = await client.search<Product>({
  q: "rain jacket",
  filters: { "brand.name": { in: ["Northwind", "Acme"] }, price: { lte: 200 }, inStock: true },
  facets: ["brand.name", "categories"],
  sort: "price-asc",
  limit: 24,
  highlight: true,
})
```

## Queries

`q` is up to 200 characters. Every word must match one of the searchable fields, with [typo tolerance](/docs/settings.md#typo-tolerance) and synonyms, and results rank by how well and where they match. An empty `q` returns every record that passes the filters, in the chosen sort.

## Filters

`filters` keeps records whose fields match, for up to 20 [facet or filter fields](/docs/settings.md#facets-and-filters). All filters must match.

| Filter                                            | Keeps records where the field                                  |
| ------------------------------------------------- | -------------------------------------------------------------- |
| `{ inStock: true }`                               | Is `true`. Text and numbers work the same way.                 |
| `{ "brand.name": { in: ["Acme", "Northwind"] } }` | Is any of up to 100 values                                     |
| `{ price: { gte: 50, lte: 200 } }`                | Is within a range; either bound can be left out. Numbers only. |

A list field matches when any of its values does.

## Facets

`facets` asks for value counts of up to eight [facet fields](/docs/settings.md#facets-and-filters):

```ts
results.facets
// { "brand.name": { Acme: 12, Northwind: 7 }, categories: { Jackets: 15, Shoes: 4 } }
```

To show counts for other values of a field that is filtered, as a list of checkboxes usually does, ask again without that field's filter.

## Sorting

`sort` is a sort ID from the index's settings, or `relevance`. Without one, the index's default sort applies. `results.sort` says which sort was used.

## Paging and counts

`limit` is the number of hits per request (20 by default; up to 100 from your server and 50 from browsers), and `offset` skips hits, up to 1,000.

By default, `total` and facet counts cover the returned page when a query matches more, which keeps searches fast:

- `hasMore` is `true` when there are more hits after this page.
- `totalRelation` is `"gte"` when `total` is a lower bound.

Set `countMode: "exact"` for the total number of matches, and `facetMode: "exact"` for facet counts across all of them. They cost more time on broad queries, so ask for them when you show them, such as on the first page of results.

## Highlighting

`highlight: true` returns each hit's matched searchable fields with the matched words in `<mark>` tags, under `highlights`. The values are HTML-escaped, so they are safe to insert as HTML. List fields give one string per value.

```ts
results.hits[0].highlights
// { title: "Waterproof <mark>rain</mark> <mark>jacket</mark>" }
```

Choose other tags with `highlight: { preTag: "<em>", postTag: "</em>" }`.

## Fewer fields

`attributesToRetrieve` returns only the listed fields of each record, such as `["title", "price", "image"]`, which makes responses smaller. It doesn't keep the other fields private; see [Security](/docs/security.md).

## Responses

```ts
{
  hits: [{ id: "sku-2", score: 12.4, record: { objectID: "sku-2", title: "Waterproof rain jacket", ... } }],
  total: 1,
  totalRelation: "eq",
  hasMore: false,
  facets: { "brand.name": { Northwind: 1 } },
  sort: "relevance",
  tookMs: 6,
}
```

## Search as you type

- Cancel the previous request when the query changes: pass `{ signal }` to the browser client, or a signal as the server client's second argument.
- Wait about 100 to 150 ms after a keystroke before searching. Every request counts toward your plan's monthly searches.
- Keep the first request light: exact counts and many facets can wait for the results page.
