Overview
Text search combines semantic text understanding with visual similarity to find relevant products. Use the visualWeight parameter to balance between text matching and visual similarity.
Basic Usage
import { Refine } from '@refine-ai/sdk';
const refine = new Refine({
apiKey: process.env.REFINE_API_KEY,
organizationId: 'org_abc123',
catalogId: 'cat_xyz789'
});
const results = await refine.search.text({
query: 'red running shoes',
topK: 20
});
results.results.forEach(product => {
console.log(`${product.title} - $${product.price}`);
});
Parameters
The search query. Natural language queries like “summer dress for wedding” work best.
Number of results to return. Recommended: 12-48 for grid layouts.
Balance between text and visual search (0.0 to 1.0).
0.0 = Pure text matching
1.0 = Pure visual similarity
0.3 = Text-primary with visual boost (default)
Array of filters to apply. See Filters for operators.
Sorting configuration with field and order (‘ascending’ | ‘descending’).
With Filters and Sorting
const results = await refine.search.text({
query: 'summer dress',
topK: 24,
visualWeight: 0.5,
filters: [
{ field: 'price', operator: 'gte', value: 50 },
{ field: 'price', operator: 'lte', value: 200 },
{ field: 'metadata.color', operator: 'in', value: ['red', 'blue', 'green'] },
{ field: 'stock', operator: 'gt', value: 0 }
],
sortBy: {
field: 'price',
order: 'ascending'
}
});
Response
interface SearchResponse {
results: SearchResultItem[];
filterOptions?: FilterOption[];
serveId: string;
totalResults: number;
}
interface SearchResultItem {
productId: string;
title: string;
price: number;
imageUrl: string;
metadata: Record<string, any>;
score: number;
}
Array of matching products, ordered by relevance.
Available filter values based on the result set. Useful for building faceted navigation.
Unique identifier for this search serve. Used internally for event tracking.
Total number of matching products (before topK limit). Use for pagination UI.
Tracking Search Results
Always track search results to power analytics and improve recommendations:
const results = await refine.search.text({ query: 'shoes', topK: 20 });
const searchContext = refine.events.trackSearch(
'shoes',
results.results,
{
surface: 'search_results',
totalResults: results.totalResults
}
);
// When user clicks a product
searchContext.trackClick(productId, position);
// When a product becomes visible
searchContext.trackView(productId, position);
// When user adds to cart
searchContext.trackAddToCart(productId);
See Event Tracking for more details.
Visual Weight Recommendations
The optimal visualWeight depends on your product category:
| Category | Recommended Weight | Reason |
|---|
| Fashion/Apparel | 0.5 - 0.7 | Visual appearance is primary |
| Electronics | 0.2 - 0.4 | Specs and text matter more |
| Home Goods | 0.4 - 0.6 | Balanced |
| Art/Decor | 0.7 - 0.9 | Almost purely visual |
| Books | 0.1 - 0.2 | Text is primary |
| Jewelry | 0.6 - 0.8 | Visual details matter |
A/B test different visual weights to find the optimal balance for your specific catalog and user behavior.
Use topK with offset for pagination:
const PAGE_SIZE = 24;
let currentPage = 0;
async function loadPage(page: number) {
const results = await refine.search.text({
query: 'shoes',
topK: PAGE_SIZE,
// Note: offset is handled server-side with pagination tokens
});
currentPage = page;
return results;
}
For best performance, prefer “Load More” patterns over traditional pagination. Each new search request is independent and provides fresh relevance scoring.
Error Handling
import {
RefineValidationError,
RefineAuthError,
RefineRateLimitError
} from '@refine-ai/sdk';
try {
const results = await refine.search.text({ query: 'shoes', topK: 20 });
} catch (error) {
if (error instanceof RefineValidationError) {
console.error('Invalid search parameters:', error.message);
} else if (error instanceof RefineAuthError) {
console.error('Check your API key');
} else if (error instanceof RefineRateLimitError) {
console.error('Rate limited, retry after:', error.retryAfter);
}
}
Complete Example
import { Refine, RefineValidationError } from '@refine-ai/sdk';
const refine = new Refine({
apiKey: process.env.REFINE_API_KEY,
organizationId: 'org_abc123',
catalogId: 'cat_xyz789'
});
async function performSearch(query: string, filters: Filter[] = []) {
try {
const results = await refine.search.text({
query,
topK: 24,
visualWeight: 0.5,
filters,
sortBy: { field: 'relevance', order: 'descending' }
});
// Track the search
const searchContext = refine.events.trackSearch(query, results.results, {
surface: 'search_results',
totalResults: results.totalResults
});
return {
products: results.results,
total: results.totalResults,
filterOptions: results.filterOptions,
trackClick: (productId: string, position: number) => {
searchContext.trackClick(productId, position);
}
};
} catch (error) {
if (error instanceof RefineValidationError) {
return { products: [], total: 0, error: 'Invalid search' };
}
throw error;
}
}
Next Steps