No-Results Queries
The recovery loop — detecting zero-result queries, closing the gap with synonyms, curations, or content, and measuring the improvement.
A no-result query is a search that returned zero hits. It is the single highest-signal event in your search analytics: the user told you exactly what they wanted, and you told them you have nothing. Every no-result query is either a relevance miss (you have the answer but didn't find it) or a content gap (you don't have it).
This page is the playbook for triaging that data.
How no-results are detected
The public search handler records type: "zero_results" on SearchUsageEvent when found === 0. The Top Queries panel surfaces these in a dedicated cut, and the dashboard exposes a no-results-rate KPI tile.
The events also carry:
- The raw
querystring. - The
filterBythat was active (often the cause of the zero). - The
indexSlug. - The
locale. - A
searchTimeMsso you can detect timeouts vs true empties.
Reading the no-results panel
const zr = await orpc.search.topQueries.call({
organizationId,
period: "30d",
filter: { zeroResults: true },
limit: 50,
});Sort by search count. The top 10–20 are the queries to act on this week; the long tail is for content-team backlog.
Three columns to read together:
| Column | Insight |
|---|---|
query | The literal user phrase. |
searches | How many distinct sessions hit this empty. |
withFilter | Whether the query had a filterBy active — a "zero with filter" is often filter-induced, not catalog-missing. |
A query like iphone 15 with 200 zero-result searches and 0 filters is a content gap. The same query with 200 zero-results and filterBy: "brand:=Samsung" is a filter UX problem — the user picked an incompatible filter.
Triage flow
For each top no-result query, in order:
Step 1 — Is it a typo or a known synonym?
Run the query in the Search Preview. If a fuzzy match would have worked but didn't (typo tolerance off, or the query is too long for fuzz):
- Check typo-tolerance settings — see Filters, sorting & pagination.
- Add a synonym if it's a regional or brand-equivalent term.
Step 2 — Is it a real product/article with a vocabulary mismatch?
Search your catalog directly (without the user's query). If you find the right document, the answer was in the index but the user's words didn't reach it:
- Add a synonym mapping (e.g.
"airpods" → "wireless earbuds"). - Add the alternate term to the document's
tagsordescription(if you control the catalog). - Boost relevant fields in
queryBy.
Step 3 — Is it a filter-induced zero?
If withFilter is true and the underlying query has matches without the filter:
- This is a UX issue, not a content issue. Detect filter-induced zeros in the client and show "Clear filters to see X more results".
- Long-term: in the widget, disable filter values that would produce zero, given the current query (see "graceful filter pruning" in the widget docs).
Step 4 — Is it a content gap?
If neither the synonym fix nor the filter fix applies, you genuinely don't have the answer. This is content team work:
- Add the missing product / article.
- Re-ingest.
- Mark the query as "watched" in the dashboard so you measure the recovery.
Measuring recovery
After applying a fix, watch the same query over the next two periods:
const before = await orpc.search.topQueries.call({
organizationId,
period: "30d",
offsetDays: 30,
filter: { zeroResults: true },
});
const after = await orpc.search.topQueries.call({
organizationId,
period: "30d",
filter: { zeroResults: true },
});A successful fix shows the query dropping out of the zero-result list in the "after" window. If it's still there, the fix didn't take — typically because the reindex hasn't run yet, or the synonym was added to the wrong index.
The no-results-rate KPI
The dashboard KPI tile is:
no-results rate = zero-result searches / total searchesIn a healthy storefront, target under 5 %. Above 10 % usually means a serious catalog / vocabulary mismatch. Above 20 % almost always means a routing bug — the wrong index is being queried.
Track this weekly. A sudden jump usually correlates with a recent deploy (new schema field, new locale, new connector) and bisects easily against the Activity feed.
Bulk patterns
For very high-cardinality catalogs, scanning no-result queries one by one is unreasonable. Two bulk patterns:
Cluster by token
Take the top 500 no-result queries, lowercase / tokenise, and find the most common shared tokens. A cluster of zero-result queries that all contain a single token — for example "airpods" showing up in "airpods", "airpods pro", "new airpods" — is one fix (add the term) that wipes out the whole cluster.
Cluster by brand / category
Same idea but along your facet dimensions. If 200 zero-result queries all parse to "Brand: Acme, Category: phones", you're missing an entire product line.
The Export flow returns the raw rows; both clusters are 20-line scripts away.
Recovery via AI fallback
When all else fails, the no-result UX is the natural surface for a fallback:
- Run a semantic-search hybrid pass when keyword returns zero.
- Or fire an AI answer over the closest related products and let the user pivot.
Don't make this the default — both add latency and cost — but on the no-result branch, the cost is justified because the alternative is showing the user nothing.
Telemetry on the recovery itself
If you enable an AI fallback, instrument it:
trackEvent({
type: "search_query",
query,
metadata: { fallback: "ai_answer", originalFound: 0 },
});You can then compute "AI fallback effectiveness" — how often a zero-result session that triggered a fallback ended in a click — and decide whether the fallback is paying for itself.
Related pages
- Analytics overview
- Queries
- Relevance tuning — where synonyms and curations live
- Semantic search — the typical fallback for no-results
- AI answers
- Search workspace — the preview tool to test fixes