Skip to content
Start free

Your data

Set up search

Start from what people will type: list the searches, set the index up for each kind, keep them working with search tests, and tune from analytics. With an AI agent, in the dashboard, or in code.

Good search starts from the searches, not the settings. Write down what people will type and what each search should find, set the index up for those searches, and save them as search tests, so a later change can't break them without you seeing. Once people search, analytics show what to fix next.

This page goes through the steps once, then shows them with an AI agent, in the dashboard, and in code. It starts once you know what a record is (Plan your records). The Shopify app, the WooCommerce plugin, and product feeds make the records for you, so stores on them start here.

List the searches

Before you change a setting, write down 20 to 30 searches, and what each should find first. Take them from:

  • Your current search's analytics: its top searches, and those that found nothing. If you're moving from another search service, import its settings too.
  • Google Search Console: the searches that bring people to your site say what they call your products.
  • Your menus and best sellers: category names, top brands, and the products that sell most.
  • The people who answer customers: what customers ask for by phone, by chat, or in the shop, in their words.

Then add a few hard ones: a typo, a plural, a word written apart, a product code, and something you don't sell. A running shop's list starts like this:

SearchShould find first
cadenceCadence Road Knit Running Shoe
trail shoes waterproofWaterproof trail shoes
40211The product with that code
sneakersRunning shoes, though the records say "trainers"
cadenseCadence Road Knit Running Shoe, despite the typo
returnsThe returns page
kayakNothing sold here, so the closest products, or none

Most searches are of a few kinds, and each kind has settings that make it work:

KindSearches such asWhat makes them work
Namescadence, cadence road knitThe title as the first searchable field, with the most weight. If your search box searches with each letter typed, shortPrefixes, so the first letters find something.
Codes40211, 3.5mm, a model numberA searchable field of their own, with typos: false (fields without typos), since a near miss is a different product.
Brandsstridewell, pumaThe brand as a searchable field after the title, and as a facet. exactWords for brands a typo away from other words, so puma doesn't find pump.
Categoriesrunning shoes, jacketsThe category as a searchable field and a facet. When accessories come before the thing, such as laces for running shoes, a rule that boosts the category.
Attributesred jacket, waterproof, size 11Colors, materials, and tags in a searchable list, weighted below the title, and as facets. A rule with a placeholder, such as size {sizes}, turns a value in the query into a filter.
Other wordssneakers for trainers, hoodie for hooded sweatshirtSynonyms. A one-way synonym when a broad word should find narrower ones, but not the other way round: shoes finds boots, and boots finds only boots.
Word formsjackets, Schuhe, kjólar, barna afmælilanguages for plurals and common words, Icelandic word forms, and compound words for words written together or apart.
Typoscadense, protienTypo tolerance, on by default. Did you mean corrects what it doesn't reach, and tells shoppers what was searched.
Prices and intentunder 100, giftsRules: under {number} filters prices up to the number and searches the rest (placeholders), and gifts can boost products tagged as gifts.
Pagesreturns, shipping, opening hoursA rule with a redirect to the page.
Not sold herekayakRelated results show the products closest in meaning, when they're close enough, on paid plans. Analytics lists these searches as demand (why, and fixes).

An index searches up to five fields. When you have more, put fields that work alike in one list, such as colors, materials, and tags in tags, and leave text that's only shown, such as a care guide, unsearched.

Docs, articles, and listings get searches of the same kinds. Their recipes have settings to start from: docs and help centers, articles and research, and listings and places.

Decide what comes first

Relevance orders most searches. Three settings change the order for all of them, so set them once:

  • Rank first puts what should always lead first, such as products in stock.
  • Custom ranking orders equally good matches, such as by units sold in the last 30 days.
  • Learn from clicks, once a store has traffic, puts the products shoppers pick most for a search first.

For one search or one category page, use a rule or merchandising, not a setting that changes every search.

Run each search on your list in the index's Playground. Why this result? shows what each result matched and how, such as through a typo or a synonym, and the rules that moved it. When a search finds the wrong thing, change one setting and search again.

Save them as search tests

Each search that works becomes a search test:

  • A result that must come first: inTop, such as the Cadence shoe in the top 3 for cadence.
  • A search that must keep finding plenty: minResults, such as 20 for trail shoes.
  • A result that must stay out: notInTop, such as the gift card out of the top 20 for shoes.

In the Playground, Save as test makes one from a result. From then on, Preview changes on the Search settings page shows the tests a change would break, and the searches it changes, before you save it.

After launch

Real searches show what your list missed. In the first weeks, look at the index's analytics each week:

  • Searches with no results: add the fixes that make sense from why, and fixes.
  • Top queries: look at the first results of the 20 most searched.
  • Searches without clicks: results that didn't look right to shoppers.
  • Clicked further down: searches whose shoppers pick a result below the top three, which may belong higher (where clicks land).
  • Rising searches: new demand, and things you may not sell yet.
  • Rule hits, on the Search settings page: rules that fire on searches they shouldn't, or on none.

Save a test for each search you fix. The weekly report emails the main numbers on Mondays.

With an AI agent

Connect the MCP server, and an agent can do every step above. It reads your data, but it doesn't know your shoppers, so tell it:

  • What you sell, and who searches: professionals who type part numbers, or gift shoppers who type "for dad".
  • The languages people search in.
  • Your list of searches, and what each should find first.
  • What isn't public, such as cost prices and supplier details, so it stays out of the records.
  • For a live index, to preview each change and not save one that breaks a search test.

To set up a new index:

Set up Findlane search for our products, from data/products.json.
We sell running and trail gear. Shoppers search in English and
Icelandic, often by model name, size, or code. These searches must
work, with what should come first:

- cadence: Cadence Road Knit Running Shoe
- trail shoes waterproof: waterproof trail shoes
- 40211: the product with that code
- sneakers: running shoes
- returns: go to /pages/returns

Save them as search tests, and tell me which you couldn't make work,
and why.

In Claude Code, /mcp__findlane__add-search starts the same way, and asks for your searches if you don't give them.

To tune a live index:

Look at the last 30 days of searches in our products index: top
queries, searches that found nothing, and searches whose shoppers
click below the top three. Propose fixes, preview each with
compare_settings against our search tests, and wait for my yes
before saving. Save a search test for each fix.

/mcp__findlane__fix-no-results starts from the searches that found nothing.

In the dashboard

Without an agent or code, in this order:

  1. Records: upload a JSON file on the index's Records page, or connect the Shopify app, the WooCommerce plugin, or a product feed.
  2. Search settings: until anyone changes them, Use these settings puts the suggested settings for your kind of data in the form. Check them against your list, section by section:
    • Matching: the searchable attributes, in order and with weights, typo tolerance and exact words, compound words, and languages.
    • Ranking and sorting: custom ranking, rank first, learn from clicks, sorts, and variants.
    • Filters and facets: what shoppers narrow by.
    • Synonyms and rules: other words, and fixes for single searches.
    • Suggestions: query suggestions, did you mean, and related results.
  3. Playground: run each search on your list. Open Why this result? for those that find the wrong thing, and Save as test for those that work.
  4. Merchandising: if you want an order of your own, arrange your main category pages and most searched words.
  5. Public access: allow your site's origins, so its pages can search.
  6. Analytics, once people search.

In code

The server SDK does the same. Start from the recipe for your data, such as products, then check your list and save it as tests:

import { SearchServerClient } from "@findlane/server"

const client = new SearchServerClient({
  workspaceId: process.env.FINDLANE_WORKSPACE_ID!,
  apiKey: process.env.FINDLANE_API_KEY!,
})
const products = client.index("products")

// What each search on the list finds first.
const list = ["cadence", "trail shoes waterproof", "40211", "sneakers"]
for (const q of list) {
  const { hits } = await products.search({ q, limit: 3 })
  console.log(q, hits.map((hit) => hit.record.title))
}

// Searches that must keep working.
await products.setSearchTests([
  {
    id: "cadence",
    q: "cadence",
    expect: { objectID: "stridewell-cadence-road-knit", inTop: 3 },
  },
  { id: "trail-shoes", q: "trail shoes", expect: { minResults: 20 } },
  {
    id: "no-gift-card",
    q: "shoes",
    expect: { objectID: "gift-card", notInTop: 20 },
  },
])

// A change is saved only when it breaks no test.
const settings = await products.getSettings()
const synonyms = settings.synonyms ?? []
const next = {
  ...settings,
  synonyms: [...synonyms, ["sneakers", "trainers", "running shoes"]],
}
const comparison = await products.compareSettings(next)
if (comparison.tests.every((test) => test.after || !test.before)) {
  await products.replaceSettings(next)
}

For a search that finds the wrong thing, search with explain: true to see what each result matched (explain results).