
Search Autocomplete
- 61 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Speed up product discovery with instant search suggestions, fuzzy typo matching, and category-aware results via Algolia or Elasticsearch.
About
Adds instant search autocomplete with typo tolerance and category-aware results backed by Algolia or Elasticsearch. A developer uses it to make product search faster and more forgiving.
- Instant suggestions with fuzzy typo matching
- Category-aware results via Algolia or Elasticsearch
Search Autocomplete by the numbers
- 61 all-time installs (skills.sh)
- Ranked #1,204 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill search-autocompleteAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 61 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Speed up product discovery with instant search suggestions, fuzzy typo matching, and category-aware results via Algolia or Elasticsearch.
Files
Search Autocomplete
Overview
Implement a typeahead search experience that surfaces product suggestions, categories, and content as shoppers type. Combines client-side debouncing with server-side fuzzy matching, applies merchandising rules (boosts, pins, synonyms), and renders a structured dropdown that drives measurable conversion lift.
When to Use This Skill
- When shoppers are failing to find products through browse navigation alone
- When site search click-through rates are below 30% of searches
- When adding a search-as-you-type experience to an existing search endpoint
- When integrating a third-party search service (Algolia, Elasticsearch, Typesense)
- When implementing merchandising rules to boost promoted products in results
- When supporting multi-language storefronts requiring synonym and phonetic matching
Core Instructions
Step 1: Determine the merchant's platform and choose the right approach
| Platform | Recommended Approach | Why |
|---|---|---|
| Shopify | Install Search & Discovery app (free, by Shopify) for synonym/boost configuration + Searchie or Boost Commerce app for full autocomplete dropdown | Search & Discovery improves the built-in Shopify search with synonyms and product boosts; Boost Commerce ($19/mo) adds a fully styled autocomplete dropdown with category results and merchandising rules |
| WooCommerce | Install FiboSearch – AJAX Search for WooCommerce (free/paid) or SearchWP + SearchWP Live Search extension | FiboSearch adds an instant AJAX autocomplete dropdown to the WooCommerce search bar with product images, prices, and category results — no custom code needed |
| BigCommerce | Enable Search Suggestions in Storefront → Search settings + install Klevu Smart Search or Searchspring for advanced autocomplete | BigCommerce's native search has basic autocomplete; Klevu ($449+/mo) and Searchspring add AI-powered autocomplete, synonym management, and merchandising rules |
| Custom / Headless | Build with Algolia InstantSearch.js (recommended) or self-hosted Typesense; implement debounced input, AbortController for race conditions, and ARIA combobox pattern | Algolia offers the best developer experience with a generous free tier (10K searches/month); Typesense is the self-hosted alternative |
Step 2: Configure search autocomplete on your platform
---
Shopify
Search & Discovery app (required baseline — free): 1. Install Search & Discovery from the Shopify App Store 2. Go to Apps → Search & Discovery → Synonyms and add business synonyms:
- Bidirectional: "sneakers" ↔ "trainers" ↔ "shoes"
- One-way: "tv" → "television", "flat screen"
3. Under Boosts, pin high-priority products or collections to appear first for specific queries 4. Under Filter settings, configure which attributes appear as filters alongside search results 5. The app improves Shopify's native predictive search API used by all OS2.0 theme search bars
Boost Commerce app (full autocomplete dropdown): 1. Install Boost Commerce – Product Filter & Search from the Shopify App Store 2. In the app dashboard, configure the Instant Search popup:
- Enable product image + price in suggestions
- Add category/collection suggestions
- Configure the number of product results (recommend 5–8)
3. Set up Merchandising rules in the app: boost new arrivals, pin best sellers, exclude out-of-stock from suggestions 4. Customize the popup's appearance to match your theme colors in the Design settings
---
WooCommerce
FiboSearch (recommended — free tier available): 1. Install FiboSearch – AJAX Search for WooCommerce from WordPress.org 2. Go to FiboSearch → Settings → General 3. Configure what appears in suggestions:
- Products: name, SKU, tags (enable all for best results)
- Categories: enable to show category suggestions
- Pages/Posts: enable if you have blog content
4. Set Fuzzy Search to On — this handles typos like "adids" → "Adidas" 5. Under Appearance, configure the dropdown layout: product image + name + price vs. compact text-only 6. FiboSearch replaces the default WooCommerce search widget — it works with the standard search input, Elementor search widgets, and most theme search bars
SearchWP + Live Search extension: 1. Install SearchWP (paid, from $99/yr) for advanced indexing control 2. Install the SearchWP Live Search extension for real-time autocomplete 3. In the SearchWP admin, configure which product fields are indexed with what weight (name > SKU > description) 4. Enable custom fields and product attributes in the index for spec-based searching
---
BigCommerce
1. Go to Storefront → Search in your BigCommerce control panel 2. Under Search Suggestions, enable Products, Categories, and Brands as suggestion types 3. Set the number of suggestions to show (5–8 for products) 4. Configure Search as you type to start after 2 characters
Klevu Smart Search (advanced autocomplete): 1. Install from the BigCommerce App Marketplace 2. In the Klevu dashboard, configure synonym groups and boosting rules 3. Klevu's autocomplete dropdown automatically shows product images, prices, categories, and trending searches 4. Add custom banners to the search dropdown for specific queries (e.g., show a "Summer Sale" banner when someone searches "dress")
---
Custom / Headless
Debounced input hook with AbortController (prevents race conditions):
// useSearchAutocomplete.js
import { useState, useEffect, useRef, useCallback } from 'react';
function debounce(fn, delay) {
let timer;
return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), delay); };
}
export function useSearchAutocomplete(minChars = 2) {
const [query, setQuery] = useState('');
const [results, setResults] = useState({ products: [], categories: [], suggestions: [] });
const [loading, setLoading] = useState(false);
const abortRef = useRef(null);
const fetchSuggestions = useCallback(
debounce(async (q) => {
if (q.length < minChars) { setResults({ products: [], categories: [], suggestions: [] }); return; }
if (abortRef.current) abortRef.current.abort();
abortRef.current = new AbortController();
setLoading(true);
try {
const res = await fetch(`/api/search/autocomplete?q=${encodeURIComponent(q)}&limit=5`,
{ signal: abortRef.current.signal });
setResults(await res.json());
} catch (err) { if (err.name !== 'AbortError') console.error(err); }
finally { setLoading(false); }
}, 250),
[minChars]
);
useEffect(() => { fetchSuggestions(query); }, [query, fetchSuggestions]);
return { query, setQuery, results, loading };
}Accessible combobox dropdown (ARIA combobox + listbox pattern):
// SearchAutocomplete.jsx
import DOMPurify from 'dompurify'; // sanitize server-provided highlight HTML
export function SearchAutocomplete() {
const { query, setQuery, results, loading } = useSearchAutocomplete();
const [activeIndex, setActiveIndex] = useState(-1);
const inputRef = useRef(null);
const allItems = [...results.categories, ...results.products];
const isOpen = query.length >= 2 && allItems.length > 0;
function handleKeyDown(e) {
if (e.key === 'ArrowDown') { e.preventDefault(); setActiveIndex(i => Math.min(i + 1, allItems.length - 1)); }
if (e.key === 'ArrowUp') { e.preventDefault(); setActiveIndex(i => Math.max(i - 1, -1)); }
if (e.key === 'Enter' && activeIndex >= 0) window.location.href = allItems[activeIndex].url;
if (e.key === 'Escape') { inputRef.current.blur(); setActiveIndex(-1); }
}
return (
<div role="combobox" aria-expanded={isOpen} aria-haspopup="listbox" aria-owns="autocomplete-list">
<input ref={inputRef} type="search" value={query}
onChange={e => { setQuery(e.target.value); setActiveIndex(-1); }}
onKeyDown={handleKeyDown}
aria-autocomplete="list" aria-controls="autocomplete-list"
aria-activedescendant={activeIndex >= 0 ? `item-${activeIndex}` : undefined}
placeholder="Search products..." />
{loading && <span aria-live="polite" className="sr-only">Loading suggestions</span>}
{isOpen && (
<ul id="autocomplete-list" role="listbox" className="autocomplete-dropdown">
{results.categories.map((cat, i) => (
<li key={cat.url} id={`item-${i}`} role="option" aria-selected={activeIndex === i}>
<a href={cat.url}>Category: {cat.name} ({cat.product_count})</a>
</li>
))}
{results.products.map((product, i) => {
const idx = i + results.categories.length;
const highlighted = DOMPurify.sanitize(product._highlightResult?.name?.value ?? product.name);
return (
<li key={product.objectID} id={`item-${idx}`} role="option" aria-selected={activeIndex === idx}>
<a href={product.url} className="product-suggestion">
<img src={product.image} alt="" width="40" height="40" />
<span dangerouslySetInnerHTML={{ __html: highlighted }} />
<span>${product.price}</span>
</a>
</li>
);
})}
<li><a href={`/search?q=${encodeURIComponent(query)}`}>View all results for "{query}"</a></li>
</ul>
)}
</div>
);
}Algolia index configuration (typo tolerance + synonyms + merchandising):
await searchClient.setSettings({
indexName: 'products',
indexSettings: {
searchableAttributes: ['name', 'brand', 'category', 'description'],
customRanking: ['desc(popularity_score)', 'desc(conversion_rate)'],
typoTolerance: 'min',
minWordSizefor1Typo: 5,
synonyms: [
{ objectID: 'shoes', type: 'synonym', synonyms: ['shoes', 'sneakers', 'footwear', 'trainers'] },
],
optionalFilters: ['is_featured:true<score=2>', 'in_stock:true<score=1>'],
},
});Best Practices
- Debounce at 200–300 ms — balances responsiveness and server load; do not go below 150 ms
- Cancel in-flight requests — use
AbortControllerto avoid race conditions when the user types quickly - Highlight matched terms — wrap matched substrings in
<mark>so shoppers see why a result appeared; sanitize server-supplied HTML before rendering - Show a "View all results" link — always provide an escape hatch to the full search results page
- Cache frequent queries — most stores have a small set of high-frequency queries; an LRU cache cuts backend load significantly
- Track no-results queries — log queries returning zero results; these are direct signals for synonym gaps or catalog holes
- Set minChars to 2 — single-character queries produce noise and return no conversion value
Common Pitfalls
| Problem | Solution |
|---|---|
| Stale results when user types fast | Use AbortController to cancel the previous request before issuing a new one |
| Dropdown appears behind sticky header | Set z-index explicitly on the dropdown; use a portal if inside an overflow:hidden ancestor |
| Keyboard navigation focus lost on re-render | Track activeIndex in component state, not DOM focus; re-apply aria-activedescendant on each render |
| Fuzzy matching returns irrelevant results | Configure minWordSizefor1Typo: 5 in Algolia or prefix_length: 2 in Elasticsearch to require a solid stem before fuzzy kicks in |
| Merchandising rules not applying | Rules trigger when the query matches the condition pattern — use anchoring: 'contains' not is for partial matches |
Related Skills
- @faceted-navigation
- @product-page-design
- @accessibility-commerce
- @storefront-theming
{
"context": "Tests whether the agent correctly configures an Algolia products index with the skill-specified searchable attribute priorities, custom ranking fields, typo tolerance settings, synonyms, and merchandising rules using the correct anchoring type.",
"type": "weighted_checklist",
"checklist": [
{
"name": "searchableAttributes order",
"max_score": 10,
"description": "searchableAttributes lists 'name' first and 'description' last (lowest priority), with 'brand' and 'category' appearing in between in that order"
},
{
"name": "customRanking popularity",
"max_score": 8,
"description": "customRanking includes 'desc(popularity_score)' as one of its entries"
},
{
"name": "customRanking conversion",
"max_score": 8,
"description": "customRanking includes 'desc(conversion_rate)' as one of its entries"
},
{
"name": "typoTolerance: min",
"max_score": 10,
"description": "typoTolerance is set to the string value 'min' (not true, false, or 'strict')"
},
{
"name": "minWordSizefor1Typo: 5",
"max_score": 10,
"description": "minWordSizefor1Typo is set to exactly 5"
},
{
"name": "minWordSizefor2Typos: 9",
"max_score": 10,
"description": "minWordSizefor2Typos is set to exactly 9"
},
{
"name": "Synonyms configured",
"max_score": 8,
"description": "At least one synonym group is defined with type: 'synonym' and a synonyms array containing multiple equivalent terms"
},
{
"name": "Rule anchoring: contains",
"max_score": 14,
"description": "The merchandising rule condition uses anchoring: 'contains' (NOT anchoring: 'is') so it matches partial queries"
},
{
"name": "filterPromotes: true",
"max_score": 12,
"description": "The rule consequence includes filterPromotes: true alongside the promote array"
},
{
"name": "Rule promotes correct collection",
"max_score": 10,
"description": "The rule's promote array includes the objectID 'collection-summer-sale' at position 0"
}
]
}
Algolia Search Index Setup for Product Catalog
Problem/Feature Description
A home goods retailer is migrating from a legacy keyword-only search to Algolia. They have a large product catalog (200k SKUs across categories like furniture, kitchen, bedding, and lighting) and have noticed two recurring problems: shoppers searching for "sofa" don't see "couch" results, and shoppers with minor typos (e.g., "lighitng") get zero results. In addition, the merchandising team wants to ensure that newly featured seasonal products appear at the top of search results for relevant queries, and that in-demand items are ranked above obscure catalog entries.
There is also a known business rule: when a shopper searches for anything containing the word "sale", the "Summer Sale Collection" (objectID: collection-summer-sale) should be pinned to position 0. The team has been burned before by using exact-match conditions in rules that silently failed for queries like "big sale" or "sale items".
Your task is to write the Algolia configuration scripts that set up the products index from scratch and save the required merchandising rule. The scripts will be run by the DevOps team using Node.js — they will provide the ALGOLIA_APP_ID and ALGOLIA_ADMIN_KEY environment variables.
Output Specification
Produce the following files:
configure-index.js— script to configure the products index settings (searchable attributes, ranking, typo tolerance, synonyms)configure-rules.js— script to save merchandising rules for the products indexREADME.md— brief notes explaining what each script does and the order to run them
{
"context": "Tests whether the agent builds the server-side autocomplete endpoint with multi-index search, correct Algolia query parameters, merchandising boosts, query result caching, and no-results tracking.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Multi-index parallel search",
"max_score": 10,
"description": "The endpoint queries both 'products' and 'categories' indices (not just products), using Promise.all or equivalent concurrent execution"
},
{
"name": "Products limit 5",
"max_score": 8,
"description": "The products index query requests at most 5 hits (hitsPerPage or equivalent parameter set to 5)"
},
{
"name": "Categories limit 3",
"max_score": 8,
"description": "The categories index query requests at most 3 hits (hitsPerPage or equivalent parameter set to 3)"
},
{
"name": "Products attributesToRetrieve",
"max_score": 10,
"description": "The products query specifies attributesToRetrieve containing all of: objectID, name, image, price, url, category"
},
{
"name": "Categories attributesToRetrieve",
"max_score": 8,
"description": "The categories query specifies attributesToRetrieve containing all of: name, url, product_count"
},
{
"name": "Merchandising optionalFilters",
"max_score": 14,
"description": "The products query includes optionalFilters boosting is_featured:true and in_stock:true using score notation (e.g., 'is_featured:true<score=2>')"
},
{
"name": "LRU cache implementation",
"max_score": 14,
"description": "A cache (LRU or equivalent bounded cache) is implemented to serve repeated identical queries without hitting Algolia again"
},
{
"name": "No-results query logging",
"max_score": 14,
"description": "When all result arrays are empty (zero products and zero categories), the query is logged or recorded for analytics/monitoring purposes"
},
{
"name": "Min chars guard",
"max_score": 8,
"description": "The endpoint returns an empty result set (without querying Algolia) when the query parameter is absent or shorter than 2 characters"
},
{
"name": "attributesToHighlight for names",
"max_score": 6,
"description": "The products query includes attributesToHighlight for 'name' so that highlight markup is returned in the response"
}
]
}
Search Autocomplete API Endpoint
Problem/Feature Description
A growing outdoor gear retailer is launching a new storefront and needs a backend autocomplete API. Their catalog lives in Algolia across two indices: products (150k records) and categories (800 records). The search team has noticed that their existing full-text search endpoint is too slow and returns too much data for the autocomplete use case — they want a dedicated, lean endpoint that returns relevant suggestions fast.
The ops team has also flagged two recurring production incidents on other services: one where popular search terms hammered the Algolia API unnecessarily (costing money and adding latency), and another where their analytics team couldn't identify why certain products weren't being found — they had no visibility into what searches were returning empty results.
Your task is to implement the /api/search/autocomplete endpoint in Node.js/Express using the algoliasearch package. The Algolia app ID and API key will be available as environment variables ALGOLIA_APP_ID and ALGOLIA_SEARCH_KEY. The endpoint must be production-ready and address the two operational concerns raised above.
Output Specification
Produce the following files:
autocomplete.js— the Express route handler implementing the autocomplete endpointREADME.md— brief documentation covering: the response shape, any caching behavior, and how zero-result queries are handled
{
"context": "Tests whether the agent correctly implements the frontend React autocomplete component following skill-specific patterns for debouncing, request cancellation, ARIA accessibility, security, and UX requirements.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Debounce delay range",
"max_score": 10,
"description": "The debounce delay used is between 200 and 300 ms (inclusive) — NOT less than 200 ms or more than 300 ms"
},
{
"name": "AbortController usage",
"max_score": 10,
"description": "The hook uses AbortController (creates a new one per request and calls .abort() on the previous one before issuing a new fetch)"
},
{
"name": "minChars threshold of 2",
"max_score": 8,
"description": "The hook does NOT fire a search request when the query length is less than 2 characters, and clears results in that case"
},
{
"name": "ARIA combobox role",
"max_score": 8,
"description": "The wrapper element has role=\"combobox\" and the dropdown list has role=\"listbox\""
},
{
"name": "ARIA expanded and controls",
"max_score": 8,
"description": "The input element has aria-autocomplete=\"list\" and aria-controls pointing to the listbox; the wrapper has aria-expanded reflecting open state"
},
{
"name": "aria-activedescendant tracking",
"max_score": 8,
"description": "The active keyboard index is stored in component state (not DOM focus), and aria-activedescendant on the input points to the currently active item id"
},
{
"name": "DOMPurify sanitization",
"max_score": 12,
"description": "DOMPurify is imported and used to sanitize server-supplied highlight HTML before it is passed to dangerouslySetInnerHTML or equivalent"
},
{
"name": "Keyboard navigation keys",
"max_score": 10,
"description": "ArrowDown/ArrowUp move the active index, Enter navigates to the selected item's URL, and Escape blurs the input and resets the active index"
},
{
"name": "View all results link",
"max_score": 8,
"description": "The dropdown includes a link or button that navigates the user to the full search results page (e.g., /search?q=...) as an escape hatch"
},
{
"name": "Highlight matched terms",
"max_score": 8,
"description": "Matched substrings in product names are rendered with <mark> or <em> tags (or equivalent emphasis element) so shoppers can see why a result matched"
},
{
"name": "Preload on focus",
"max_score": 10,
"description": "The component fetches or displays trending/popular searches when the input receives focus, before the user has typed anything"
}
]
}
Storefront Search Autocomplete Component
Problem/Feature Description
The UX team at a mid-market fashion retailer has identified that shoppers frequently abandon the site when they can't quickly find products. Exit surveys show that the site's static search bar is a major pain point — shoppers start typing and nothing happens until they hit Enter. Competitors all offer live suggestions as you type, and internal data shows a 23% drop in search-to-purchase conversion compared to industry benchmarks.
The team wants a React search autocomplete component that shows product and category suggestions as the shopper types. The backend API already exists at /api/search/autocomplete and accepts a q query parameter and limit parameter, returning JSON shaped as { products: [...], categories: [...], suggestions: [...] }. Each product has objectID, name, image, price, url, and a _highlightResult.name.value field containing server-rendered HTML with matched substrings already tagged. Each category has name, url, and product_count.
Your job is to build the frontend: a custom React hook and a dropdown UI component. The component should be accessible and handle edge cases gracefully. Consider the experience both for mouse users and for power users navigating entirely by keyboard.
Output Specification
Produce the following files:
useSearchAutocomplete.js— custom React hook encapsulating all data fetching and stateSearchAutocomplete.jsx— the rendered component using the hookSearchAutocomplete.css— basic styles for the dropdown (positioning, z-index, active states)
The component should work standalone: a developer should be able to drop it into any React app and see it work against the /api/search/autocomplete endpoint.
{
"name": "finsi/search-autocomplete",
"version": "0.1.0",
"summary": "Implement typeahead search with fuzzy matching, filters, and merchandising rules",
"skills": {
"search-autocomplete": {
"path": "SKILL.md"
}
}
}