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

# Search

> Full-text search across EU frameworks with the Law4Devs Python SDK.

## Overview

The search endpoint performs full-text search across articles, recitals, and requirements. Results include a `match_context` snippet showing where the query matched. Use filters to narrow by framework or content type.

***

## Methods

### `query()`

Run a full-text search and return a page of results.

```python theme={null}
results = client.search.query("data breach notification")

print(f"Found {len(results.data)} results")
for r in results.data:
    print(f"  [{r.type}] {r.framework_slug} — {r.match_context[:80]}...")
```

**Parameters**

| Parameter     | Type  | Default  | Description                                  |
| ------------- | ----- | -------- | -------------------------------------------- |
| `q`           | `str` | required | Search query string                          |
| `framework`   | `str` | `None`   | Limit to a specific framework slug           |
| `result_type` | `str` | `None`   | `"article"`, `"recital"`, or `"requirement"` |
| `page`        | `int` | `1`      | Page number                                  |
| `per_page`    | `int` | `20`     | Items per page (1–100)                       |

**Returns** `Page[SearchResult]`

<Note>
  `page.meta.pages` is always `0` for search results. The search endpoint does not support traditional page-count pagination. Use the presence of `page.links.next` to detect whether more results exist.
</Note>

***

## Model

### `SearchResult`

| Field              | Type          | Description                                               |
| ------------------ | ------------- | --------------------------------------------------------- |
| `type`             | `str`         | Result type: `"article"`, `"recital"`, or `"requirement"` |
| `framework_slug`   | `str`         | Framework the result belongs to                           |
| `framework_name`   | `str`         | Human-readable framework name                             |
| `article_number`   | `int \| None` | Article number (for article and requirement results)      |
| `recital_number`   | `int \| None` | Recital number (for recital results)                      |
| `paragraph_ref`    | `str \| None` | Paragraph label (for requirement results)                 |
| `title`            | `str \| None` | Article or section heading                                |
| `requirement_type` | `str \| None` | Requirement classification (requirement results only)     |
| `match_context`    | `str`         | Snippet of matched text with surrounding context          |
| `url`              | `str`         | Direct API URL to the matched resource                    |

***

## Examples

### Basic search

```python theme={null}
from law4devs import Law4DevsClient

client = Law4DevsClient()

results = client.search.query("data breach notification")
for r in results.data:
    print(f"[{r.type:12}] {r.framework_slug:8} {r.title or ''}")
    print(f"             ...{r.match_context}...")
    print()
```

### Search within a specific framework

```python theme={null}
results = client.search.query("legitimate interest", framework="gdpr")

print(f"{len(results.data)} GDPR results for 'legitimate interest'")
for r in results.data:
    ref = f"Art. {r.article_number}" if r.article_number else f"Recital {r.recital_number}"
    print(f"  {ref}: {r.match_context[:80]}")
```

### Filter by result type

```python theme={null}
# Only articles
articles = client.search.query("incident response", result_type="article")

# Only requirements
reqs = client.search.query("incident response", result_type="requirement")

print(f"Articles: {len(articles.data)}, Requirements: {len(reqs.data)}")
```

### Search across multiple frameworks manually

```python theme={null}
frameworks_to_search = ["gdpr", "nis2", "cra"]
query = "vulnerability disclosure"

all_results = []
for fw in frameworks_to_search:
    page = client.search.query(query, framework=fw)
    all_results.extend(page.data)

print(f"'{query}' found in {len(all_results)} places across {len(frameworks_to_search)} frameworks")
```

### Paginate through search results

```python theme={null}
query = "security measures"
page = client.search.query(query, per_page=50)

all_results = list(page.data)

# meta.pages is always 0 for search — check links.next instead
while page.links.next:
    page = client.search.query(query, page=page.meta.page + 1, per_page=50)
    all_results.extend(page.data)

print(f"Total results collected: {len(all_results)}")
```

### Display results grouped by framework

```python theme={null}
from collections import defaultdict

results = client.search.query("encryption", per_page=100)

by_framework = defaultdict(list)
for r in results.data:
    by_framework[r.framework_name].append(r)

for fw_name, matches in sorted(by_framework.items()):
    print(f"\n{fw_name} ({len(matches)} matches):")
    for r in matches:
        ref = f"Art. {r.article_number}" if r.article_number else f"Recital {r.recital_number}"
        print(f"  {ref}: {r.match_context[:60]}...")
```

<Tip>
  Combine `framework` and `result_type` filters to narrow results significantly. For example, `result_type="requirement"` limits results to machine-readable obligations, which is useful when building compliance checkers.
</Tip>

<Warning>
  Search queries are matched against parsed text content. Very short queries (one or two characters) may produce unexpected results. Use at least three characters for meaningful searches.
</Warning>
