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

# Smart Search

> Reference for the SearchService class in the Tybrite SDK.

The `SearchService` class (accessed via `client.search`) provides both traditional keyword-based search and advanced AI-powered semantic search capabilities.

## Methods

### `searchProducts`

Fast, keyword-based search optimized for exact matches, SKUs, and product names. It uses case-insensitive partial matching to find relevant results quickly.

```typescript theme={null}
const result = await client.search.searchProducts({
  q: 'headphones', // You can use 'q' or 'query'
  limit: 10
});

console.log(`Found ${result.totalResults} results`);
// Each result: { productId, score, matchReason: "Text match" }
```

```json Response theme={null}
{
  "query": "headphones",
  "results": [
    { "productId": "69fbb1fe-6b96-4e7b-b86d-07c3799aa626", "score": 1, "matchReason": "Text match" }
  ],
  "totalResults": 1
}
```

***

### `semanticSearch`

AI-powered, meaning-based search that understands intent and context. This allows customers to find products using natural language descriptions even if they don't know the exact product name.

<Note>
  **Key Support:** Both **Secret Keys** and **Publishable Keys** are supported for semantic search, allowing you to implement AI-powered search directly in your frontend.
</Note>

```typescript theme={null}
const result = await client.search.semanticSearch({
  requestBody: {
    query: 'wireless earbuds for the gym',
    limit: 8,
    minScore: 0.5 // Optional: raise the similarity floor to return only strong matches (default 0.3)
  }
});

// Each result: { productId, score } ranked by semantic similarity
result.results.forEach(r => console.log(`${r.productId} — score ${r.score}`));
```

```json Response theme={null}
{
  "query": "wireless earbuds for the gym",
  "results": [
    { "productId": "f4992a40-38a1-4ebd-9390-3ecfb9d10093", "score": 0.89 },
    { "productId": "f6a2629e-f899-4615-b17a-e78e2e4c35a4", "score": 0.88 },
    { "productId": "7d425c0a-50e7-4e39-af79-6f7945f9dfa8", "score": 0.85 },
    { "productId": "69fbb1fe-6b96-4e7b-b86d-07c3799aa626", "score": 0.83 }
  ],
  "totalResults": 50
}
```

#### Personalized results

Pass `personalize: true` together with a signed-in customer's session token (the `x-auth-token`
header) to nudge results toward that shopper's preferences. Query relevance stays primary —
relevance is blended with the shopper's preference signal, not replaced — so results remain
on-topic. Without a customer session, or for a shopper with no preference signal yet, ranking is
by query relevance only.

```typescript theme={null}
const personalized = new Tybrite({
  apiKey: 'tybrite_pk_live_...',
  headers: { 'x-auth-token': customerSessionToken },
});

const result = await personalized.search.semanticSearch({
  requestBody: { query: 'gear for the gym', limit: 5, personalize: true }
});
// → same { query, results: [{ productId, score }], totalResults } shape as above,
//   re-ranked to blend query relevance with this shopper's preference signal.
```

## Comparison: Text vs. Semantic

| Feature      | `searchProducts` (Text)           | `semanticSearch` (AI)                     |
| :----------- | :-------------------------------- | :---------------------------------------- |
| **Logic**    | Case-insensitive keyword matching | Meaning-based matching via AI embeddings  |
| **Best For** | SKUs, Model numbers, Exact names  | Natural language, Intent, "Vibes"         |
| **Example**  | "MacBook Pro", "SKU-990"          | "a laptop for professional video editing" |
| **Speed**    | Ultra-fast                        | Fast                                      |

***

<Tip>
  **Zero-Result Fallback:** A powerful UX pattern is to first call `searchProducts`. If `totalResults` is 0, gracefully fallback to `semanticSearch` to suggest products that might still interest the user.
</Tip>

***

<Note>
  **Why is `semanticSearch` a `POST`?** `POST /v1/search` is intentionally accessible to publishable keys despite using the `POST` verb. It is a read-only operation — `POST` is used purely to support complex JSON request bodies (query, `minScore`, filters). No state is mutated and no `403` is returned for publishable keys.
</Note>

## Response Codes

Both methods accept **publishable** and **secret** keys. `searchProducts` is `GET`; `semanticSearch` is `POST` (read-only).

| Code  | Meaning                                                                             |
| :---- | :---------------------------------------------------------------------------------- |
| `200` | Search results returned (may be empty — check `totalResults`).                      |
| `400` | Missing `query`/`q` parameter, invalid `limit`, or malformed request body.          |
| `401` | Invalid or missing API key.                                                         |
| `429` | Rate limit exceeded.                                                                |
| `500` | Internal server error or upstream embedding-service failure (semantic search only). |
