Appearance
How product search works β
MyChatBot's product search is a smart, multi-step search: a single query is matched several ways at once β by meaning, by keywords, by category, and (optionally) by product image β then blended and reranked so your agent gets one clean, ranked product list back. Read this page when you want the whole flow at a glance before tuning filters, prompts, or image search.
Your agent reaches this search over the Product (commerce) MCP. The catalog it searches is whatever product feed you connected in the app.
In the app: connect a catalog
Product search runs against a product feed you connect under Knowledge base β Products (app.mychatbot.app/knowledge-base). Add or refresh a feed there, and MyChatBot indexes it so your agent can search it. The Connect AI tools button on the Products card gives you the ready-made MCP URL to point an agent (or Claude / Cursor) at that catalog.
Direct vs agentic search β
There are two ways your agent can search a catalog, chosen per integration by the Agentic Search toggle in the app. You'll find it when you configure a Products, Product Feed, Product Spreadsheet, or Instagram products source. The toggle governs only product search β FAQ and document knowledge is always simply referenced, with no modes.
| Direct β toggle OFF (default) | Agentic β toggle ON | |
|---|---|---|
| How it works | One semantic lookup against your catalog; the matching products are handed straight to the assistant | A small search agent works the query in steps β discovers a category's filters/attributes, runs several refined searches, and compares β before answering |
| Filters | Supported | Supported, and the agent chooses them itself |
| Custom search prompt | β | You can give it guidance on how to search your catalog |
| Speed | Fastest | A bit slower (it does more work) |
| Best for | Straightforward "find me X" queries | Vague, comparative, or attribute-heavy questions on large / complex catalogs |
Rule of thumb
Start with direct (toggle off) for speed. Turn on Agentic Search when your catalog is large and attribute-rich, or when customers ask nuanced, multi-constraint questions ("a warm waterproof jacket under $150 for hiking"). The step-by-step pipeline below is a single direct lookup β agentic mode simply runs that lookup several times, refining as it goes.
You flip this toggle where you connect the catalog β see Getting inventory in. For Instagram catalogs, the same toggle lives in the Instagram products setup. See also the Search tools reference, Filters, attributes & params, and Troubleshooting.
Cheat sheet β
The search runs top-to-bottom. Each step below operates on the results of the step above it.
| # | Step | What it does | Skipped when |
|---|---|---|---|
| 1 | Understand the query | Matches the query both by meaning (semantic) and by exact words | Query is code-like (SKU/barcode) or a pasted URL β semantic match dropped so exact matching wins |
| 2 | Search the whole catalog | Blends meaning + product-name + keyword + exact-phrase matches into one ranked list | β |
| 3 | Attribute-filter fallback | Retries a filtered search a different way if the first pass came back empty | No filters used, or the first pass already returned results |
| 4 | Pick the best categories | Groups results by category and ranks the most relevant categories | β |
| 5 | Rank inside each category | Re-runs the same blended search inside each top category, in parallel | β |
| 6 | Rerank | A relevance model reorders the list for a cleaner top result | enable_reranking=false, β€1 result, or a code/URL query |
| 7 | Blend in an image match | Mixes a product-image match into the text results | No image_url supplied |
You build filters β the search never parses natural language
semantic_product_search matches the whole query string, but it only enforces the filters your agent constructs. There is no natural-language-to-filter extraction: nothing turns "red", "summer", or "under $50" into constraints for you. Splitting the shopper's sentence into query text plus structured filters is the agent's job β see From a shopper sentence to a search call.
How the search index is organized β
Each catalog you connect gets its own search index. The search reads it three ways:
| View | What it holds | Used by |
|---|---|---|
| Whole catalog | Every product β matchable by meaning, name, and keywords, plus your filterable attributes | Steps 2β4 (blend + category discovery) |
| Per-category slice | The same products, scoped to a single leaf category | Step 5 (per-category ranking) |
| Image index | A visual fingerprint of each product image | Step 7 (image blending) |
Exact names and phrases outrank loose semantic matches
Steps 2 and 5 blend four kinds of match β meaning (semantic), product-name keywords, general keywords, and exact phrases. Name and exact-phrase matches are deliberately weighted to win over loosely-semantic ones, which is why a specific product name usually surfaces its exact item at rank 1. MyChatBot tunes this relevance balance for your catalog β contact support if you need it adjusted.
Where each filter kind resolves β
Every filters operator is enforced as a hard constraint on a broad, category-less search β a filter is never silently dropped. The kinds differ only in whether they also guide candidate retrieval:
| Filter kind | Example filter | On a broad, category-less search |
|---|---|---|
| Equality / membership | color eq red, stickers in [β¦] | β Enforced β and guides candidate retrieval |
| String substring | name contains ASHEN | β Enforced (case-insensitive) β and guides candidate retrieval |
| Range / negation / prefix | price lt 50, country ne UK, name startswith Ele | β
Enforced as a strict constraint on results (doesn't steer retrieval β keep intent in query) |
Step by step β
1. Understand the query β
The query is matched both semantically (by meaning) and by exact words. Two query shapes skip the semantic step to protect exact matching:
- Code-like β SKUs, barcodes, model numbers.
- URL-like β a pasted product link.
For these, the semantic match is dropped so exact/code matching dominates, and reranking (step 6) is skipped β they already have a decisive exact answer.
2. Search the whole catalog β
The four match types above run against the whole-catalog index and are blended into one list. Any caller-supplied filters are applied as a hard constraint on every match type β all ten operators are enforced. Equality / membership (eq / in) and string substrings (contains) additionally guide which candidates are retrieved; range, ne, and prefix filters constrain the results without steering retrieval. The search fetches extra depth internally so later steps have headroom to rerank.
3. Attribute-filter fallback β
Defense-in-depth for catalogs indexed before searchable attributes existed. If a filtered search comes back empty or errors, the search retries once through the typed per-category attribute columns. It only engages when filters are present, so it can never change a healthy, non-empty result.
Filters suddenly return nothing on an older catalog
If a filter that used to work starts returning [] on an older catalog, its searchable attributes were probably indexed before this feature existed. The fallback auto-heals most requests, but the permanent fix is a full re-index β not a self-serve toggle. In the app, remove and re-add the product integration (Knowledge base β Products), or contact MyChatBot support with your integration and they'll run a full re-index. See Filters, attributes & params.
4. Pick the best categories β
Results are grouped by category and each category is scored by how highly its products ranked. Category order is then:
- Term-match categories first β categories whose top products contain all query terms in their name.
- Frequency-ranked categories β the remaining highest-scoring categories.
5. Rank inside each category β
The selected top categories are searched concurrently, each against its own per-category slice, using the identical blended search from step 2.
Big catalogs fan out wide
A query that spans many categories runs many category searches at once, which can be slow on a very large catalog. If searches feel slow or time out, keep queries specific (or split a huge catalog into more focused integrations), and contact support to tune how many categories are searched.
6. Rerank β
If reranking is on (the default), the relevance service is available, and there's more than one result, the blended list is reordered by a relevance model for a cleaner top result. Reranking is skipped for code-like and URL-like queries β they already have a decisive exact ranking β and a rerank failure falls back to the pre-rerank order.
7. Blend in an image match β
When image_url is supplied, an image-fingerprint search runs against the image index and is blended with the text results. If the image step fails, the search falls back to the text results. Deep dive: Image search.
Copy-paste: a full agentic query β
The agent-facing tool is semantic_product_search on the Product (commerce) MCP. A text + filter call:
json
{
"tool": "semantic_product_search",
"arguments": {
"query": "waterproof winter boots",
"limit": 20,
"enable_reranking": true,
"truncate_description": true,
"filters": [
{ "attribute": "color", "operator": "eq", "value": "black" },
{ "attribute": "stickers", "operator": "in", "value": ["ΠΠΎΠ΄Π°ΡΡΠ½ΠΎΠΊ", "Sale"] }
]
}
}Returns { count, products[], categories[] } β the categories[] list reflects the category selection from step 4, so your agent can offer to drill down.
When the shopper supplies only part of a product name, filter the reserved top-level name field with contains:
json
{
"tool": "semantic_product_search",
"arguments": {
"query": "evening dress",
"filters": [
{ "attribute": "name", "operator": "contains", "value": "ASHEN" }
]
}
}contains is a case-insensitive literal substring match, so this can return a product named The Ashen Evening Dress. It requires a nonblank string; * and ? are treated as ordinary characters rather than wildcards. Use eq/in, not contains, for membership in list-shaped fields β a native list such as stickers or a comma-separated coverage list. contains matches inside words (contains "Neath" matches Rosneath), while eq matches the exact value or an exact list element (element match is case-insensitive).
A text + image call (triggers step 7):
json
{
"tool": "semantic_product_search",
"arguments": {
"query": "red evening dress",
"image_url": "https://example.com/photo.jpg",
"limit": 10
}
}In the app: get the MCP URL
You don't hand-write the endpoint. Open Knowledge base β Products, click Connect AI tools on the catalog's card, and copy the generated Product MCP URL (https://product.mychatbot.app/mcp/<account>/<integration>/stream) or the ready-made claude mcp add β¦ command / Cursor config. Full setup: Product (commerce) MCP.
From a shopper sentence to a search call β
A sentence like "red summer dresses under $50" is not a single call β the agent has to split it into free-text intent (query) and structured constraints (filters), and route the range part correctly. Map each fragment to where it belongs:
| Fragment | Goes to | Why |
|---|---|---|
dress (the thing) + summer (descriptor) | query: "summer dress" | Drives the blended search and category discovery; summer stays in text unless the catalog exposes a filterable season attribute (check with get_category_attributes) |
red | filter: { "attribute": "color", "operator": "eq", "value": "red" } | A hard equality constraint β works on a whole-catalog search |
under $50 | filter: { "attribute": "price", "operator": "lt", "value": 50 } | A range constraint β enforced on the whole-catalog search too, as long as the stored price values read as plain numbers (see the tip below) |
So the sentence can resolve in one call:
json
{
"tool": "semantic_product_search",
"arguments": {
"query": "summer dress",
"limit": 20,
"filters": [
{ "attribute": "color", "operator": "eq", "value": "red" },
{ "attribute": "price", "operator": "lt", "value": 50 }
]
}
}When you'd rather browse one category deterministically (a full on-budget listing instead of ranked recall), split it into the classic two-call flow:
Step 1 β broad search: apply the eq constraint and let the search surface candidate categories.
json
{
"tool": "semantic_product_search",
"arguments": {
"query": "summer dress",
"limit": 20,
"filters": [
{ "attribute": "color", "operator": "eq", "value": "red" }
]
}
}Read categories[] from the response and pick the dresses leaf category (say its id is dresses_042).
Step 2 β list that leaf category with the price ceiling:
json
{
"tool": "filter_category_products",
"arguments": {
"category_id": "dresses_042",
"filters": [
{ "attribute": "color", "operator": "eq", "value": "red" },
{ "attribute": "price", "operator": "lt", "value": 50 }
],
"limit": 100
}
}A price ceiling is enforced on the broad search too
price lt 50 on a broad semantic_product_search call clips the results β every operator is enforced, category or not. The bound may be a number or a numeric string (50 / "50" behave identically), and the comparison is numeric even when the attribute is stored as text. The one practical caveat is about the values: they must read as plain numbers β a decorated price like "1 200 Π³ΡΠ½" cannot be range-compared (next tip). Use the two-call category flow when you want a complete on-budget listing rather than the ranked top matches.
Confirm price is actually a filterable attribute
price can be used as a range filter only when your feed exposed it as a filterable attribute whose values read as numbers β a numeric-typed attribute is ideal, and a text attribute holding plain numeric values ("50") works too; decorated text ("1 200 Π³ΡΠ½") does not. Verify per category with get_category_attributes(category_id) (is price in attribute_names[]?) and get_category_attribute_values(category_id, "price") (do the values look like plain numbers?). If the feed buried price somewhere unusual and it wasn't picked up as a filterable attribute, the agent can still see it in the product details but can't filter by it β and a price lt 50 filter silently matches nothing. Fixing this needs a full re-index (not a self-serve toggle): remove and re-add the integration in Knowledge base β Products, or contact MyChatBot support with your integration.
All ten operators, both tools, one contract
eq, ne, gt, gte, lt, lte, in, contains, startswith, and endswith carry the same semantics on semantic_product_search and the category tools. contains is case-insensitive and applies only to string fields; startswith/endswith are case-sensitive and test the whole stored string; ne also excludes case-insensitive list elements; ranges compare numerically only when the value is numeric. Full operator reference: Search tools.
Best practices β
Do
- Decompose the shopper's sentence yourself β send free-text intent as
query, and build hard constraints (color, size, in-stock) as structuredfilters. The search does no natural-language-to-filter extraction. - Let the search pick categories β send a clean natural-language
queryand readcategories[]back to guide follow-ups (and to get thecategory_idyou need for range filters). - Use
filtersfor hard constraints (color, size, in-stock), not for describing intent β intent belongs inquery. - Use
name contains <fragment>when the shopper knows only part of a product name; do not add wildcard characters. - Set
enable_reranking=falsefor pure SKU / code lookups; reranking adds latency with no benefit there. - Reach for
get_products_by_idswhen you already know the exact IDs β skip the whole ranking flow.
Don't
- Don't range-filter attributes whose values don't read as plain numbers β confirm with
get_category_attribute_valuesbefore relying on a price clip; decorated values like"1 200 Π³ΡΠ½"cannot be compared. Bounds may be numbers or numeric strings. - Don't stuff SKUs into range filters β code-like attributes are excluded from the filterable attribute copy; put codes in
queryor useget_products_by_ids. - Don't assume rank stability with generic product names β a common word in many product names can flip rank 1; filter by category or vendor first, or contact support to tune relevance.
- Don't paste an image expecting it to override a text-disambiguated answer β image matches are blended, not authoritative (see the rank-1 guard in Image search).
Test it β
Regression-test with the known-hits pattern: define a query plus the product IDs you expect, run semantic_product_search, and assert the IDs appear. Introspect a catalog first with get_category_attributes, get_category_attribute_values, and get_available_filters (facets) to learn what's actually filterable β including whether price holds values that read as plain numbers. Full walkthrough: Testing search.
See also β
- Getting inventory in β feeds, parsers, and how records land in the search index
- Search tools reference β every MCP tool, its arguments, and what it returns
- Filters, attributes & params β equality vs. range filters, and how relevance is tuned
- Search prompts β prompt patterns that steer the search
- Image search β image fingerprints, confidence tiers, and the rank-1 guard
- Testing search β known-hits regression tests and catalog introspection
- Product (commerce) MCP β MCP URL, transport, and the full tool list
- Troubleshooting & best practices β stale attributes, orphan catalogs, and rank instability