How to Build an AI Product Finder Section for Shopify
A product finder takes 'a waterproof jacket for light hiking under $150' and returns matching products. It needs vector search and filters, and it does not need a chat model.

Short answer: embed every product once, embed each shopper's query at search time, run a vector search with filters for price and availability, and have the theme display the returned products using live data from the store. It does not need a chat model, which makes it faster and cheaper than a chatbot. The pipeline, the filter step, the section code and the failure cases are below. The retrieval design comes from my own recommendation projects.
What is the difference between a product finder and a chatbot?
A finder returns products, and a chatbot returns sentences about products. The finder takes a description, runs retrieval, and shows results with no generated text, so there is no model call to wait for and nothing that can be made up.
That is why a finder is the safer first project. It has two moving parts, embeddings and vector search, and the products shown are real by construction, since they come from the index. In my Manhwa Recommender and drama recommender, a browse carousel skips the language model and the reranker for the same reason: showing a row of results does not need an explanation. If you do want conversation, see how to add an AI chatbot to Shopify.
How does the finder find products?
Five steps run on each query. Only the first two cost money, and both are small.
- The query is embedded into a vector.
- The vector database returns the nearest product chunks.
- Filters narrow the results, such as price ceiling or in-stock only.
- The backend returns product handles.
- The theme fetches live product data and renders cards.
The embedding is a single API call per search. In my RAG project, one embedding plus one generation call cost about one cent, and a finder skips the generation call, so each search is a fraction of that. Your actual cost depends on the embedding model and traffic.
How do I get products into the index?
Use the same sync as a chatbot: a one-time bulk export, then product webhooks for changes. Build one chunk per product from the title, type, vendor, tags, a plain-text description and option values. The details are in how to add an AI chatbot to Shopify.
Store the fields you will filter on as metadata beside the vector, such as product_type, tags, price_min and available. Qdrant Cloud requires a payload index on any field you filter by, so create those indexes when you create the collection. In my project, filters worked on a local embedded store and failed in the cloud until I added them.
How do I turn a sentence into filters?
Two options: let the shopper pick filters in the interface, or have a small model extract them from the sentence. Interface filters are the simplest and need no model. They also give the shopper control.
If you want the sentence "waterproof jacket for light hiking under $150" to set a price limit automatically, ask a language model for structured output, then apply the fields as filters.
# Ask the model for JSON only, and validate it before using it.
# {"max_price": 150, "product_type": "jacket", "must_have": ["waterproof"]}
filters = [FieldCondition(key="price_min", range=Range(lte=parsed["max_price"]))]
if parsed.get("product_type"):
filters.append(FieldCondition(key="product_type", match=MatchValue(value=parsed["product_type"])))
hits = qdrant.search(collection, query_vector=vec, query_filter=Filter(must=filters), limit=24)Validate the model's JSON against a fixed schema, and ignore any field you did not expect. In my Manhwa Recommender, a language model maps a natural-language request onto a fixed taxonomy of about 2,300 tags, and the fixed list is what keeps its output usable. The same rule applies here: constrain the output to values your catalogue actually has.
How do I show live prices and stock?
Return handles from your endpoint, then fetch live data from the store. The backend response is a list of handles ranked by score, and nothing about price.
The theme then requests /products/{handle}.js for each one, which returns the title, price in cents, image and available. Drop products that are not available, and render the rest. Using the store's own data means a sale price or a sold-out variant is correct the moment it changes, even if the index is a few minutes behind.
What does the Liquid section look like?
A section with a search form, a results grid and a deferred script. The endpoint is a section setting, so you can change it without editing code.
<section class="finder" data-endpoint="{{ section.settings.endpoint }}">
<h2>{{ section.settings.heading }}</h2>
<form class="finder__form" role="search">
<label for="finder-q-{{ section.id }}" class="visually-hidden">Describe what you are looking for</label>
<input id="finder-q-{{ section.id }}" name="q" type="search" maxlength="200" required
placeholder="{{ section.settings.placeholder }}">
<button type="submit">Find</button>
</form>
<p class="finder__status" aria-live="polite"></p>
<ul class="finder__grid"></ul>
</section>
<script src="{{ 'finder.js' | asset_url }}" defer></script>
{% schema %}
{
"name": "AI product finder",
"settings": [
{ "type": "text", "id": "heading", "label": "Heading", "default": "Find the right product" },
{ "type": "text", "id": "placeholder", "label": "Placeholder", "default": "Describe what you need" },
{ "type": "url", "id": "endpoint", "label": "Search endpoint" }
],
"presets": [{ "name": "AI product finder" }]
}
{% endschema %}document.querySelectorAll('.finder').forEach((root) => {
const form = root.querySelector('form');
const status = root.querySelector('.finder__status');
const grid = root.querySelector('.finder__grid');
const money = new Intl.NumberFormat(undefined, {
style: 'currency', currency: window.Shopify?.currency?.active || 'USD',
});
form.addEventListener('submit', async (e) => {
e.preventDefault();
status.textContent = 'Searching...';
grid.replaceChildren();
const res = await fetch(root.dataset.endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: form.q.value }),
});
const { handles = [] } = await res.json();
const products = await Promise.all(
handles.map((h) => fetch(`/products/${h}.js`).then((r) => r.json()).catch(() => null))
);
const live = products.filter((p) => p && p.available);
status.textContent = live.length ? `${live.length} products found` : 'No close matches. Try describing it differently.';
for (const p of live) {
const li = document.createElement('li');
const a = Object.assign(document.createElement('a'), { href: p.url, textContent: p.title });
li.append(a, ` ${money.format(p.price / 100)}`);
grid.append(li);
}
});
});Output is built with textContent and DOM calls, so nothing from the response is parsed as HTML. Add product images with p.featured_image and an <img> that has width and height attributes, so the results do not cause layout shift.
What should the finder do when nothing matches?
Say so, and do not show random products. Vector search always returns the nearest items, even when none is close, so set a minimum similarity score and show the empty message below it.
Pick the threshold by testing, not by guessing. Run 30 to 50 real queries, including ones your catalogue cannot satisfy, and note the scores of good and bad results. I have not tuned a threshold for a Shopify store, so I do not quote one. Log every zero-result query. They show which products or descriptions your catalogue lacks.
How do I keep the finder fast?
Debounce the input, cap the results, and load the script after the page. Typing-triggered search should wait about 300 milliseconds after the last keystroke before calling the endpoint, and one request should return no more than about 24 handles.
Fetching product data for each handle adds requests, so keep the number small and render as results arrive. Keep the script off the critical path with defer, per how to speed up a Shopify store without apps. Test the result section on real phones, since the cards are the part shoppers see.
When is the built-in search enough?
When shoppers search with product names and exact terms, keyword search already works. A vector finder helps when people describe needs, uses and occasions rather than names, such as "a gift for someone who runs".
Compare both on a real list of queries before building anything. Take the 50 most common searches from your store's analytics, plus 20 descriptive ones, and check what each approach returns. Build the finder only if the descriptive queries are where search fails today.
If you want a product finder built for your store, see my Shopify development services or get in touch with your catalogue size and the queries that fail today. I have not published a Shopify finder case study yet, and the retrieval approach comes from my Manhwa Recommender.
Related
- How to add an AI chatbot to Shopify (custom RAG)
- Dense vs sparse vs hybrid retrieval compared
- Shopify AI chatbot app vs build your own
- Build a custom AI recommendation engine
Frequently asked questions
What is an AI product finder on Shopify?
A search box or section that understands descriptions in plain language, such as 'warm gift for a runner', and returns matching products, instead of matching only exact keywords.
Does a product finder need an LLM?
Not for the search itself. Embedding the query and running vector search is enough. A language model is optional and only needed to turn a sentence into structured filters like price or color.
How do I show live prices in the results?
Return product handles from your search endpoint, then have the theme fetch each product's live data from /products/{handle}.js and show its current price and availability.
How is this different from Shopify's built-in search?
Keyword search matches words. A vector finder matches meaning and can apply your own filters and ranking. Test both on real queries before deciding whether the difference is worth building.
How do I find out what shoppers search for?
Log every query and every query that returned no good result. Zero-result queries show what your catalogue or product descriptions are missing.
Want an AI that actually knows your catalogue?
I build Shopify chatbots and product finders that answer from your real products instead of guessing — custom-coded into your theme, with no monthly app fee. Tell me what your store needs and I'll tell you what it takes.


