> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pool.day/llms.txt
> Use this file to discover all available pages before exploring further.

# Search and browse

> Find the photos themselves by what they say and what they show, find look-alikes, and count what a library holds.

## Search photos

```swift theme={null}
let result = try await pool.context.search("red sneakers", using: grant)

for hit in result.hits {
    print(hit.asset.id, hit.reasons, hit.labels)
}
```

Search runs on the device and needs no network. It matches the text read from each capture, what Apple's Vision saw in the image, the things Pool named and, once the engine's models are installed, what the image looks like. With no words it lists the newest photos. It needs the `.query` operation.

| On AssetHit | Meaning |
| - | - |
| `asset` | The photo or screenshot: its Pool identifier, source and capture time. |
| `reasons` | Why it matched: `looksLike`, `text`, `label`, `entity` or `similar`. A hit can have several. |
| `labels` | What Vision saw in the image, most confident first. |
| `excerpt` | The line of text that matched. Only present when the grant includes `.recognizedText`. |
| `entityIDs` | The things found in this photo that the grant covers. |
| `matchReasons` | The same reasons grouped as `image`, `text` and `place`. |
| `matchedText` | The same as `excerpt`. |
| `relevance` | 0 to 1: this hit against the best match of the whole search. |
| `retrievalScore` | 0 to 1: the strongest single signal, image or text, against the best of that signal. |
| `score` | The fused score, for ordering within one result only. |
| `duplicates` | PhotoKit identifiers of other shots of the same moment (a burst, or near-identical frames seconds apart). They are shown once, as this hit. |
| `details` | Everything else PoolKit knows about the capture: see [Capture details](#capture-details). |

### Paging and counts

`search` returns up to 500 hits by default. Pass `limit: nil` for every match (up to 10,000), `offset` to skip, or the `nextCursor` of the last page; a cursor wins over an offset.

| On AssetSearchResult | Meaning |
| - | - |
| `totalCount` | How many captures matched, near-duplicates counted once. |
| `offset` | Where this page starts in the whole result. |
| `searchPlan` | How the words were read: `operation` (`semantic`, `location`, `date`, `capture`, `holiday`), `retrievalIntent` (`content`, `place`, `contentAndPlace`, `placeType`, `holiday`, `metadata`), `visualText` (the words matched against images, with date and media words removed), `sort`, `dateRange`, `mediaTypes`, `holiday` and a one-line `details`. |
| `seconds`, `timings` | How long the search took on the device, and how much of it went to planning, text matching, visual matching, ranking and reading. |

The result also carries `coverage`, `asOf`, `plan`, `nextCursor` and `traceID`, as a query does. `matchedVisually` is true when the image model took part. It is false until the models are installed, and search then answers from text, labels and things alone.

### Words PoolKit reads

* Dates: "last week", "in March", "2025", "last spring", "this summer". Seasons follow northern-hemisphere months: spring is March to May.
* Holidays: Christmas (24 to 26 December), Christmas Eve and Day, New Year's (31 December to 1 January), Easter (Good Friday to Easter Monday), US Thanksgiving (Thursday to Sunday), Halloween and Valentine's Day. Each works as "Christmas", "last Christmas", "this Easter" or "Easter 2025".
* Kinds of capture: "screenshots", "photos", "videos".
* Singular and plural find each other: "sneaker" finds "sneakers", "city" finds "cities".

## Capture details

Every hit from `search` and `similar` carries `details`:

| On CaptureDetails | Meaning |
| - | - |
| `labels` | What Vision saw, each with its probability. |
| `cuisines` | Cuisines Vision's food labels point to, such as `Japanese` or `Italian`. |
| `screenshot` | For screenshots: `appKind` (shopping, social, messaging, maps, music, video, news, recipes, events, travel, other), `topic`, `action` (buy, visit, attend, cook, read, listen, watch, book), `confidence`, `eventTime` and `temporalRelation` (past or upcoming) for events, `entities`, and `entityStatus`: `named`, `deferred` when no language model has read it yet, or `notApplicable`. |
| `context` | `partOfDay`, `weekend`, `faceCount` and `withPeople` (faces counted, never recognized), `selfie`, and `awayFromHome`, only under `.placesVisited` or `.locations`. |
| `activities` | Taxonomy topics the capture is about, with `path`, `strength` and `source` (photos, cuisine, rules, travel). See [Interests](https://docs.pool.day/interests.md). |
| `isFavorite`, `mediaType` | From Photos: favorite, and photo, Live Photo, panorama, portrait, screenshot, video, slow motion or time-lapse. |
| `location`, `visit` | Where it was taken: city and country under `.placesVisited`; neighbourhood, coordinates and the visit with its venue under `.locations`. See [Places and visits](https://docs.pool.day/places.md). |
| `timeZone` | Where it was taken, once places are indexed. |

`appKind` and `action` come from rules over the things PoolKit found and the words on screen. No model guesses them.

## Photos that look alike

```swift theme={null}
let alike = try await pool.context.similar(to: hit.asset.id, using: grant, limit: 20)
```

The reference photo has to be inside the grant. Captures held back by the privacy gate are never returned. `similar` takes the same `limit` and `offset`, fills the same fields, and leaves out other shots of the reference's own moment.

## Facets

```swift theme={null}
let facets = try await pool.context.facets(using: grant)
// type:product 412, label:sneaker 96, brand:nike 31, store:zalando.de 18 …
```

A facet is a count over everything the grant covers: a kind of thing (`type`), something Vision saw (`label`), a `brand` or a `store`. Each one carries a few sample photos, newest first. Use facets to build a browse screen without asking a question first. `limit` is at most 64 and `samples` at most 32.

## Recurring things

```swift theme={null}
let things = try await pool.context.recurringThings(using: grant, types: [.product])

for thing in things where thing.trend == .rising {
    print(thing.entity.label, thing.occurrences, thing.lastSeen)
}
```

| On RecurringThing | Meaning |
| - | - |
| `entity` | The product, place or other thing. |
| `occurrences` | How many different captures it appears in. |
| `recentOccurrences` | How many of those are from the last 30 days. |
| `firstSeen`, `lastSeen` | When it was first and last captured. |
| `trend` | `rising`, `steady`, `fading` or `new`, from the last 30 days against the rate before. |
| `evidenceIDs` | The evidence behind it, newest first. |

These are counts and dates. PoolKit never says a person likes something, and it never names people. What a count means for your feature is your call, and yours to explain to the person.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.