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

# Results, Evidence, and Returned Fields

> Work with timestamped search results, supporting evidence, and playable video streams.

Moment-returning APIs provide timestamped `Shot` objects for the matching parts of a video.

Each `Shot` identifies the source video and exact time range, so an application can inspect the evidence, play an individual moment, or combine several results into one stream. Use `return_fields` to include the stored index rows associated with each result.

```text theme={null}
Search request
      ↓
Timestamped Shot
      ├── source video and time range
      ├── relevance score and matched text
      ├── hydrated index evidence
      └── playable stream
```

| Result layer | What it provides |
| - | - |
| Identity | `video_id` and `video_title` identify the source. |
| Time | `start` and `end` locate the exact moment. |
| Relevance | `search_score` and optional text explain the match strength and content. |
| Evidence | `metadata["indexes"]` contains requested index rows. |
| Playback | `stream_url`, `player_url`, or `generate_stream()` makes the moment playable. |

***

## Basic result

```python theme={null}
response = video.search(
    query="find moments where a red car drives away",
)

for shot in response:
    print(shot.start, shot.end, shot.search_score)
    print(shot.generate_stream())
```

A `Shot` includes:

| Field | Type | Description |
| - | -: | - |
| `video_id` | string | Source video ID. |
| `video_length` | float | Source video duration in seconds. |
| `video_title` | string | Source video title. |
| `start` | float | Start time in seconds. |
| `end` | float | End time in seconds. |
| `text` | string or `None` | Optional matched text-like value. |
| `search_score` | float | Relevance score, when applicable. |
| `scene_index_id` | string or `None` | Index ID associated with the match, when available. |
| `scene_index_name` | string or `None` | Index name associated with the match, when available. |
| `metadata` | dict or `None` | Result metadata plus hydrated rows under `metadata["indexes"]`. |
| `stream_url` | string or `None` | Playable stream URL for this shot when already generated. |
| `player_url` | string or `None` | Player URL for this shot when already generated. |

Example:

```python theme={null}
Shot(
    video_id="m-123",
    video_length=120.5,
    video_title="Store walkthrough",
    start=3.42,
    end=7.10,
    text="Just grabbing my Nike bag...",
    search_score=0.87,
    scene_index_id="idx-123",
    scene_index_name="scene",
    metadata={
        "indexes": {
            "objects": [
                {"label": "person", "count": 1, "max_score": 0.93},
                {"label": "cell phone", "count": 1, "max_score": 0.91},
            ]
        }
    },
    stream_url="https://stream.videodb.io/v3/published/manifests/result.m3u8",
    player_url="https://console.videodb.io/player/...",
)
```

***

## APIs that return shots

These APIs return `Shot` objects:

```python theme={null}
# High-level v2 search: returns SearchResponse
response = video.search(query="happy reunion")
shots = response.shots

# Direct semantic search: returns SearchResult
semantic_results = video.semantic_search(query="happy reunion", index_names=["scene"])
shots = semantic_results.get_shots()

# Structured query: returns SearchResult
query_results = video.query(
    index_name="objects",
    filter=[{"field": "label", "op": "contains", "value": "cell phone"}],
    limit=100,
)
shots = query_results.get_shots()
```

`aggregate()` does not return shots; it returns aggregate rows. `ask()` returns an answer plus optional source shots.

***

## Play a result

You can play an individual shot:

```python theme={null}
response.shots[0].play()
```

Or use the URL directly when present:

```python theme={null}
url = response.shots[0].stream_url
```

If a stream URL is not already present, generate it from the shot timestamps:

```python theme={null}
url = response.shots[0].generate_stream()
```

***

## Return hydrated index rows

`return_fields` selects which indexes to hydrate for each matched scene. Hydrated rows are available in `shot.metadata["indexes"]`, not `shot.fields`.

For a single index:

```python theme={null}
results = video.semantic_search(
    query="person holding a phone",
    index_names=["scene"],
    top_k=10,
    return_fields=["scene"],
)

for shot in results:
    scene_rows = shot.metadata.get("indexes", {}).get("scene", [])
    print(scene_rows)
```

For high-level search across multiple indexes:

```python theme={null}
response = collection.search(
    query="person holding a phone",
    top_k=10,
    mode="default",
    return_fields=["scene", "objects"],
)

for shot in response:
    indexes = shot.metadata.get("indexes", {})
    print(indexes.get("scene", []))
    print(indexes.get("objects", []))
```

A hydrated `Shot` then looks like:

```python theme={null}
Shot(
    video_id="m-123",
    video_length=120.5,
    video_title="Store walkthrough",
    start=3.42,
    end=7.10,
    text="A person holds a phone while speaking.",
    search_score=0.91,
    scene_index_id="idx_scene_123",
    scene_index_name="scene",
    metadata={
        "indexes": {
            "scene": [
                {"scene_description": "A person holds a phone while speaking."}
            ],
            "objects": [
                {"label": "person", "count": 1, "max_score": 0.93},
                {"label": "cell phone", "count": 1, "max_score": 0.91},
            ],
        }
    },
    stream_url="https://stream.videodb.io/...",
    player_url="https://console.videodb.io/player/...",
)
```

For debugging, request all stored index rows for each matched scene:

```python theme={null}
response = video.search(
    query="product demo moments",
    top_k=10,
    return_fields="all",
)
```

Accepted `return_fields` values:

| Value | Meaning |
| - | - |
| `None` | No additional hydration. |
| `"all"` or `"*"` | Hydrate all available indexes for the matched scene. |
| string | Hydrate one index by name or ID. |
| list | Hydrate selected indexes by name or ID. |
| dict | Dict keys select indexes; values are accepted for compatibility but are not field projections. |

<Note>
  `return_fields` currently selects indexes, not individual fields. A hydrated index value is a list because one scene can map to multiple rows, such as several object labels or brand mentions.
</Note>

***

## Compile many results into one stream

For `semantic_search()` or `query()` results, compile the `SearchResult` directly:

```python theme={null}
results = video.semantic_search(query="product demo", index_names=["scene"])
stream_url = results.compile()
```

For high-level `search()`, compile the nested `SearchResult`:

```python theme={null}
response = video.search(query="product demo")
stream_url = response.results.compile()
```

Or build a stream from `Shot` timestamps:

```python theme={null}
timestamps = [(shot.start, shot.end) for shot in response]
stream_url = video.generate_stream(timestamps)
```

Generated streams are playable HLS URLs.

```text theme={null}
https://stream.videodb.io/v3/published/manifests/{manifest-id}.m3u8
```

***

## Ask sources

`ask()` returns an answer and, when `include_sources=True`, supporting `Shot` objects.

```python theme={null}
answer = collection.ask(
    question="Which brands are mentioned?",
    include_sources=True,
)

print(answer.answer)

for source in answer.sources:
    print(source.video_id, source.start, source.end)
    print(source.generate_stream())
```

***

## Result controls

| Option | Type | Default | Description |
| - | -: | - | - |
| `return_fields` | string, list, dict, or `"all"` | none | Select indexes to hydrate under `shot.metadata["indexes"]`. |
| `top_k` | int | API-specific | Maximum returned moments for search-style APIs. |
| `score_threshold` | float | none | Minimum semantic score for `semantic_search()`. |
| `limit` | int | API-specific | Maximum rows for `query()` and `aggregate()`. |

Hydrated index rows can make responses larger. Keep `return_fields` narrow for broad search previews and use `"all"` mainly for debugging or final inspection.

***

## Next steps

<CardGroup cols={2}>
  <Card icon="search" title="Search APIs" href="/pages/understand/search-and-retrieval/natural-language-query">
    Retrieve indexed moments.
  </Card>

  <Card icon="folder-search" title="Hybrid and Collection Search" href="/pages/understand/search-and-retrieval/collection-search">
    Combine results across indexes and videos.
  </Card>
</CardGroup>


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