Typical situation: an online store with 50,000 products, search via LIKE queries to MySQL — response time 5-10 seconds. Customers leave, conversion drops. The solution is Algolia, a search SaaS with its own indexing infrastructure and typo-tolerant search. Instead of writing full-text search on PostgreSQL or Elasticsearch, we use a ready-made index, API, and InstantSearch components for the frontend. The main work is to set up data synchronization and configure relevance so that the first results are relevant. Our team has 5+ years of experience with Algolia, completed over 50 integrations, ensuring stability and search speed.
How does Algolia work?
Data is loaded into an index (analogous to a table) as JSON objects with attributes. Search runs on configured fields, accounting for typos, synonyms, and weights. Each object must have a unique objectID. Free plan: 10,000 records, 10,000 search requests per month — enough for small sites. Paid plans expand limits. Pricing is calculated individually based on data volume and required performance.
Why Algolia wins over SQL search?
Algolia's search algorithm is optimized for handling typos, synonyms, and ranking, delivering relevant results instantly (1-10 ms). Unlike SQL LIKE queries that scan the entire table, Algolia uses an inverted index and CDN caching. This reduces response time to milliseconds, regardless of data volume. Additionally, Algolia provides ready-made UI components for React, Vue, Angular, accelerating frontend search development.
How to configure relevance in Algolia?
Relevance is managed through index settings: the order of searchableAttributes assigns field weights, ranking defines sorting factors (typo, distance, popularity). You can also use customRanking — for example, by update date. Through Dashboard or API, set parameters:
$index->setSettings([
'searchableAttributes' => [
'name',
'unordered(category)',
'unordered(description)',
'unordered(tags)',
],
'attributesForFaceting' => [
'filterOnly(price)',
'category',
'in_stock',
],
'attributesToRetrieve' => [
'objectID', 'name', 'price', 'category', 'image_url', 'slug', 'in_stock',
],
'attributesToHighlight' => ['name', 'category'],
'typoTolerance' => true,
'minWordSizefor1Typo' => 4,
'minWordSizefor2Typos' => 8,
'ranking' => [
'typo', 'geo', 'words', 'filters', 'proximity', 'attribute',
'exact', 'custom',
],
'customRanking' => ['desc(updated_at)'],
]);
More details in the official documentation.
Synchronization via Observer
The index must update when data changes. Observer in Laravel:
class ProductObserver {
private SearchClient $algolia;
public function __construct() {
$this->algolia = SearchClient::create(
config('algolia.app_id'),
config('algolia.admin_api_key')
);
}
public function saved(Product $product): void {
$this->algolia->initIndex('products')->saveObject(
$this->toAlgoliaRecord($product)
);
}
public function deleted(Product $product): void {
$this->algolia->initIndex('products')->deleteObject('product-' . $product->id);
}
private function toAlgoliaRecord(Product $product): array {
return [
'objectID' => 'product-' . $product->id,
'name' => $product->name,
'description' => Str::limit(strip_tags($product->description), 300),
'category' => $product->category->name,
'tags' => $product->tags->pluck('name')->toArray(),
'price' => (float)$product->price,
'in_stock' => $product->stock > 0,
'image_url' => $product->thumbnail_url,
'slug' => $product->slug,
'updated_at' => $product->updated_at->timestamp,
];
}
}
Register in AppServiceProvider:
Product::observe(ProductObserver::class);
React search component
import algoliasearch from 'algoliasearch/lite';
import {
InstantSearch,
SearchBox,
Hits,
RefinementList,
Pagination,
Highlight,
Configure,
} from 'react-instantsearch';
const searchClient = algoliasearch(
import.meta.env.VITE_ALGOLIA_APP_ID,
import.meta.env.VITE_ALGOLIA_SEARCH_KEY
);
const ProductHit: React.FC<{ hit: ProductRecord }> = ({ hit }) => (
<a href={`/products/${hit.slug}`} className="flex gap-3 p-3 hover:bg-gray-50 rounded">
<img src={hit.image_url} alt={hit.name} className="w-12 h-12 object-cover rounded" />
<div>
<p className="font-medium">
<Highlight attribute="name" hit={hit} />
</p>
<p className="text-sm text-gray-500">
<Highlight attribute="category" hit={hit} />
</p>
<p className="font-semibold">{hit.price.toLocaleString()} ₽</p>
</div>
</a>
);
export const SiteSearch: React.FC = () => (
<InstantSearch searchClient={searchClient} indexName="products">
<Configure hitsPerPage={20} filters="in_stock:true" />
<SearchBox
placeholder="Search products..."
classNames={{ input: 'w-full border rounded-lg px-4 py-2' }}
/>
<div className="flex gap-6 mt-4">
<aside className="w-48 shrink-0">
<p className="font-medium mb-2">Category</p>
<RefinementList attribute="category" />
</aside>
<div className="flex-1">
<Hits hitComponent={ProductHit} />
<Pagination className="mt-4" />
</div>
</div>
</InstantSearch>
);
Search analytics
Algolia collects clicks and conversions to improve relevance. Setup:
import { createInsightsMiddleware } from 'instantsearch.js/es/middlewares';
import aa from 'search-insights';
aa('init', {
appId: import.meta.env.VITE_ALGOLIA_APP_ID,
apiKey: import.meta.env.VITE_ALGOLIA_SEARCH_KEY,
useCookie: true,
});
// In InstantSearch
<InstantSearch
searchClient={searchClient}
indexName="products"
middlewares={[createInsightsMiddleware({ insightsClient: aa })]}
insights
>
After this, Algolia starts collecting data on which queries get clicks and automatically improves ranking.
Comparison of search solutions
| Parameter | Algolia | Elasticsearch | PostgreSQL full-text |
|---|---|---|---|
| Response time | 1-10 ms | 10-100 ms | 10-100+ ms |
| Typo tolerance | built-in | configurable | no |
| Setup complexity | low | high | medium |
| Cost for small business | free up to 10k records | requires server | free + hosting |
| Frontend components | ready (React, Vue) | requires development | requires development |
Algolia plans table
| Plan | Records | Requests/month | Cost |
|---|---|---|---|
| Free | 10,000 | 10,000 | free |
| Starter | 100,000 | 100,000 | paid |
| Business | 1,000,000 | 1,000,000 | custom |
Typical integration mistakes
- Incorrect
objectID: if not unique, data gets overwritten. Always generate based on record ID. - Missing attributes for faceting: for filters to work, set
attributesForFaceting. - Ignoring
customRanking: without it, results sort only by relevance — for commercial sites, add popularity or date. - Incorrect
typoToleranceconfiguration — may lead to irrelevant results.
Pre-launch checklist
- Check all required index attributes.
- Configure access rights: search-only API key on frontend, admin key only on backend.
- Test synchronization on test data.
- Enable analytics and monitor the first 1000 queries.
- Optimize results with A/B tests (on paid plan).
What's included in the work?
- Algolia index setup: attribute structure, relevance, filters.
- Automatic data synchronization via Observer or webhooks.
- Development of search UI on React (or Vue) with InstantSearch, including faceted filtering.
- Analytics integration to improve ranking.
- Documentation and team training.
- Guarantee of stable operation and post-launch support.
- Turnkey search implementation: from index setup to deployment.
Implementation timeline
Basic integration with indexing via Observer and frontend search: 1–2 days. Adding faceted filtering, analytics, and relevance tuning: 3–4 days. Multilingual indices with synchronization: plus 1–2 days.
Order Algolia implementation today — get a consultation and preliminary cost estimate. Contact us to discuss your project.







