---
updatedAt: 2025-09-09T21:10:51.000Z
agentTools:
  projectIndex: https://dev.tapcart.com/llms.txt
---

# Overview

The Tapcart `searchClient` allows blocks to fetch product, recommendation, and filter data from different integrations. The `searchClient` follows a strategy pattern with a base class (`BaseSearchClient`) that provides common functionality and abstract methods that concrete implementations must provide. This architecture allows for extensive customization while maintaining consistency across different search providers. You can use and customize the `searchClient` at the block level. You can share the `searchClient` across all blocks on the layout, or create instances of the `searchClient` for individual blocks.

The following doc outlines:

* Core Architecture & Types
* Common methods
* Access patterns
* Tapcart Patterns
* Customizations

### Supported Integrations

| Integration   | Status      | Availability         |
| :------------ | :---------- | :------------------- |
| Algolia       | supported   | All Pages and Blocks |
| Nosto         | supported   | All Pages and Blocks |
| Search Spring | supported   | All Pages and Blocks |
| Fast Simon    | supported   | All Pages and Blocks |
| Google Search | coming soon | None                 |
| Searchanise   | coming soon | None                 |

## Core Architecture & Types

The `searchClient` uses TypeScript interfaces and abstract classes to provide a consistent API across different search providers.

### Core Interfaces

```typescript
interface SearchParams {
  query?: string
  sort?: string
  filters?: Record<string, Set<string>>
  collection?: string
  page?: number
  productsPerPage?: number
}

interface SearchResponse<T = any> {
  products: T[]
  page: number
  totalPages: number
  totalProducts: number
  facets?: Record<string, any>
  nextPage?: number | null
  hasMore: boolean
}

interface QueryParams {
  collectionHandle?: string
  collectionId?: string
  sort_by?: string
  filter?: string[]
  searchQuery?: string
  [key: string]: any
}

interface FormattedFilter {
  title: string
  image: string | null
  tag: string
  amount: number
  isSelected: boolean
  collectionId: string | null
  min: number | null
  max: number | null
}

interface FormattedFacet {
  title: string
  filters: FormattedFilter[]
  field: string | null
  multiSelect: boolean | null
  id: string | null
}

interface SearchConfig {
  "sort-options"?: Array<{
    label: string
    key: string
  }>
  "filter-options"?: Array<{
    label: string
    key: string
  }>
  enabled: boolean
  name: string
  [key: string]: any
}
```

### Base Search Client Structure

```typescript
// Base search client interface
export abstract class BaseSearchClient<T = any> {
  // Public methods for state management
  // Protected methods for customization
  // Abstract methods that are implemented by the integration classes
}
```

## Data Flow

```mermaid
graph TD
    A[Code.js Block] --> B[useSearchContext/useSearchInstance]
    B --> C[Search Client Instance]
    C --> D[useInfiniteScroll/useRecommendations]
    D --> E[searchClient.fetcher/getRecommendations]
    E --> F[Provider API]
    F --> G[Response Processing]
    G --> H[Product Data]
    H --> I[UI Rendering]

    C --> J[State Management]
    J --> K[Filters/Sort/Collection]
    K --> L[applyBaseParamsToIntegration]
    L --> E
```

## Best Practices

1. **Always bind methods** when overriding to preserve `this` context
2. **Call original methods** when extending functionality to maintain base behavior
3. **Handle errors gracefully** in custom implementations
4. **Clean up event listeners** to prevent memory leaks
5. **Cache expensive operations** in custom implementations
6. **Validate input parameters** in custom methods