Get started
Import from Algolia
Bring an Algolia index across: its settings (searched fields, facets, sorts from its replicas, ranking, typo tolerance, synonyms, rules, and languages) and its records. Then point your site at the new index.
Moving from Algolia starts with your settings. The dashboard's Import from Algolia reads an Algolia index's settings, replicas, synonyms, and rules, converts them into Findlane settings, and shows what carried over before anything is saved. It can copy the index's records too, or you load them as usual, from your own catalog or with the script below.
What you need
- A Findlane workspace. The import creates an index for you, or replaces the settings of one you already have.
- The Algolia application ID, from your Algolia dashboard.
- An Algolia API key with the
settings,browse, andlistIndexespermissions. The Admin API key works, but a new key with only those three is better, and you can delete it once you've moved. WithoutlistIndexesyou type the index's name instead of choosing it.
Your browser reads from Algolia directly. The key goes from your browser to Algolia only: it isn't sent to Findlane or saved, and it's forgotten when the dialog closes.
Import the settings
- Open the import. On the Indexes page, workspace owners choose Import from Algolia, which creates a new index. To replace an existing index's settings instead, open its Search settings page and choose Import from Algolia… under Import.
- Connect. Enter the application ID and the API key, then Connect.
- Choose the index. Pick the Algolia index to read. Replicas aren't listed, because they become sorts of the index you pick. For a new index, check its name: lowercase letters, digits,
_, and-, starting with a letter. - Read the settings. The import reads the settings, each replica's settings, the synonyms, the rules, and a sample of records, which tells it what type each field holds. This takes a few seconds.
- Check the preview. It lists the searched fields, facets, filters, sorts, ranking, typo tolerance, synonyms, rules, languages, and the field types from the sample, followed by notes on what was carried over differently and what was not carried over. Algolia filters on any number in a record, so the preview also offers the numbers it found, such as
price, to add as filters. - Choose whether to copy the records. Copy its records too is chosen for a new index. On an index that already has records it's left unchosen, because the copied records replace them. It can't be chosen when the records wouldn't fit your plan.
- Apply. Create makes the index with these settings. On an existing index, Apply settings replaces its settings, and an index with records fills in new fields in the background. When copying, the dialog then shows the records arriving, 1,000 at a time.
Nothing changes in Algolia. You can run the import again at any time, for example after changing settings there.
What carries over
| In Algolia | Here |
|---|---|
searchableAttributes | Searchable fields, up to five, weighted 8, 4, 3, 2, and 1 in Algolia's order. An object is searched by its text fields. |
attributesForFaceting | Facets. Attributes marked filterOnly become filters. _tags becomes a filter when records have it. |
numericAttributesForFiltering | Filters. |
| Replicas | Sorts, up to eight, labelled from their field, such as "Price: low to high". A sort here orders every match, where a virtual replica reorders only the most relevant ones. |
customRanking | Custom ranking, up to three fields, which orders equally relevant results. |
Sort attributes ahead of the textual criteria in ranking | Rank first, up to two fields, such as sold-out products last. |
typoTolerance, minWordSizefor1Typo, minWordSizefor2Typos | Typo tolerance, on or off, with the word lengths kept within the range allowed here. |
disableTypoToleranceOnAttributes | Searchable fields that match without typos. |
disableTypoToleranceOnWords | Exact words: single words that must match exactly. |
| Synonyms | Synonyms and one-way synonyms. Alternative corrections and placeholders aren't carried over. |
| Rules | Rules: query patterns become phrases, {facet:brand} becomes the placeholder {brand}, and facet filters, optional filters (as boosts and buries), automatic facet filters, hidden records, query edits, and userData come along. |
queryLanguages, indexLanguages, ignorePlurals, removeStopWords | Languages: English, German, Danish, Norwegian, Swedish, and Icelandic. |
decompoundedAttributes | Compound words, for every searched field. |
_geoloc in records | The location field, when each record has one point. |
attributeForDistinct with distinct on | Group variants, up to 4 records a group, when the attribute holds one text or number value. Grouping only when a search asks for it isn't carried over: here it's on for every search, or off. |
The sample also sets each field's type, so facets, filters, and sorts work before any record arrives.
What doesn't carry over
These settings have no counterpart here, and the preview names each one your index uses:
advancedSyntax, optional words, and removing words when nothing matches.- Personalization, dynamic re-ranking, and neural search.
- In rules: filters written as a
filtersstring, conditions on the end of the query, and filter conditions other than a field's values joined by AND. Rule contexts, conditions on a search's filters, rules for an empty query, time ranges and promoted records carry over: of several time ranges, the one running now or starting next, and promoted records become pins, which show only when they pass the search's filters. - Search-time settings such as
hitsPerPageandattributesToRetrieve. Send them with each search instead.
Rules apply in the order the settings page lists them, up to ten per search, so check their order after importing.
Load your records
Records from Algolia work here as they are: a string objectID, nested objects, lists, _tags, and _geoloc. A record holds up to 256 fields and 1 MB of JSON. See Records.
Copy them in the import
Copy its records too reads every record from Algolia in your browser and sends them to the index as one replacement:
- Searches keep using the index's current records until all have arrived. The index then switches to them in one step.
- A record the index refuses, such as one with text in a number field, is left out. When the copy finishes, the dialog lists each one with the reason.
- If more than 50 records are refused, the copy stops and the index's records stay as they were. A refusal that common usually means a field's type doesn't fit the records.
- Cancelling also leaves the records as they were. Copy again starts over.
The copy runs while the dialog is open, so keep the tab open until it finishes.
If your catalog lives in your own database or store, point the code that feeds Algolia at Findlane too: replaceAllStaged loads the whole catalog, then upsert and delete keep it current. You need a secret API key with the write scope, from the dashboard's API keys page.
Copy records from Algolia with a script
To copy the records from your own server instead, for example on a schedule until you switch, run this with Node.js 18 or later, Bun, or Deno. It reads the Algolia index 1,000 records at a time and stages them in a Findlane index, which switches to them in one commit:
import { SearchServerClient } from "@findlane/server"
import type { JsonRecord } from "@findlane/server"
const appId = process.env.ALGOLIA_APP_ID!
const algoliaKey = process.env.ALGOLIA_API_KEY! // needs the browse permission
const from = "products" // the Algolia index
const to = "products" // the Findlane index
// Every record of the Algolia index, a page at a time.
async function* algoliaRecords() {
const url = `https://${appId}-dsn.algolia.net/1/indexes/${encodeURIComponent(from)}/browse`
let cursor: string | undefined
do {
const response = await fetch(url, {
method: "POST",
headers: { "X-Algolia-Application-Id": appId, "X-Algolia-API-Key": algoliaKey },
body: JSON.stringify(cursor ? { cursor } : { hitsPerPage: 1000 }),
})
if (!response.ok) throw new Error(`Algolia answered ${response.status}: ${await response.text()}`)
const page = (await response.json()) as { hits: JsonRecord[]; cursor?: string }
for (const { _highlightResult, _snippetResult, _rankingInfo, ...record } of page.hits)
yield record as JsonRecord
cursor = page.cursor
} while (cursor)
}
const client = new SearchServerClient({
workspaceId: process.env.FINDLANE_WORKSPACE_ID!,
apiKey: process.env.FINDLANE_API_KEY!,
})
const receipt = await client
.index(to)
.replaceAllStaged(algoliaRecords(), { stageId: `from-algolia-${Date.now()}` })
console.log(`Loaded ${receipt.recordCount} records`)Searches keep using the index's current records until the commit. If the copy stops, run it again with the same stageId to continue: see Replace the whole catalog.
Keep your InstantSearch pages
If your site's search runs on InstantSearch or Autocomplete, it can search Findlane without changing its pages. Findlane answers Algolia's search API, so you point the Algolia client your site already uses at Findlane, with Findlane's application ID and search key. Search boxes, refinement lists, range sliders, sort menus, highlighting, and paging keep working as they are.
- Make the index public. On the index's Public access page, turn on public search and add your site's origins.
- Create the search key. On API keys, under Sites built on InstantSearch, create the key and choose the indexes it opens. The key is public, like a search-only key: each index it opens is held to its public search settings and the sites it allows. The application ID is your workspace ID.
- Check the names. Your site asks for indexes by their Algolia names. The index answers to its own name and to the names the import kept: the Algolia index's, and each replica's as the sort it became. Under Names… you can add others, such as your Query Suggestions index, which then answers from the index's query suggestions.
- Point the client at Findlane. Pass the application ID, the key, and Findlane's host:
// algoliasearch 5
import { liteClient as algoliasearch } from "algoliasearch/lite"
const searchClient = algoliasearch("YOUR_WORKSPACE_ID", "fsk_…", {
hosts: [{ url: "api.findlane.dev", accept: "readWrite", protocol: "https" }],
})// algoliasearch 4
import algoliasearch from "algoliasearch/lite"
const searchClient = algoliasearch("YOUR_WORKSPACE_ID", "fsk_…", {
hosts: [{ url: "api.findlane.dev" }],
})The Algolia extensions for Magento and WordPress don't let you change the host in their settings, so stores using them need a small change in their theme or a module to pass hosts.
What it answers
- Searches: one query or several at once, and searches of a facet's values, such as a searchable brand list.
- Filters:
facetFilters,numericFilters,tagFilters, andfiltersstrings. Filters combine as Algolia's do: ANDs of OR groups. One OR group may mix different fields, with up to four parts. - Results: highlights and snippets with the tags you ask for, facet counts and stats, paging up to the first 1,000 results with up to 50 a page, sorts by replica name, and
aroundLatLngandinsideBoundingBoxwhen the index allows location search. - Query Suggestions indexes: answered from the index's suggestions.
- Optional filters: each
optionalFiltersentry, afield:valueor a list of them, boosts the records matching it, so records matching more come first, as Algolia adds their scores. A negated entry, such asbrand:-Puma, or one with a negative score, buries them instead. Scores count only by their sign. - Facet order:
renderingContent.facetOrderinglists the facets counted, in the order asked, so InstantSearch'sDynamicWidgetsshow them. The import keeps the Algolia index's facet order. - Rules:
ruleContextsbecome contexts, which rules with a context condition fire on. Rules' banners come inuserData, as{ banner, link, title, position }, and a rule's redirect inrenderingContent.redirect.url, where InstantSearch's widgets look. The importer carries a rule's redirect and its first banner over. - Grouping:
distinctworks on indexes that group variants: 0 orfalseshows every record, and a number that many of each group's.
Parameters with no counterpart here are left out, and the response's x-findlane-ignored header names them. These include typo settings sent with a search, personalization, and optional filters on fields the index doesn't have.
Click and conversion events
InstantSearch's insights (the search-insights library) sends clicks, views and conversions to Algolia's Insights API. Point it at Findlane too, and they become the index's events, which feed analytics, revenue from search and Bought together:
import aa from "search-insights"
aa("init", { appId: "YOUR_WORKSPACE_ID", apiKey: "fsk_…", host: "https://api.findlane.dev" })- Clicks keep their places, and the query they came from: with
clickAnalytics, a result'squeryIDnames its search. - Conversions count when they're add-to-carts or purchases (
eventSubtype), with each product's price and quantity fromobjectData. A purchase's order ID is made from the user token, time and products, so the same event sent twice is one order. Conversions without a subtype, and events on filters, are left out. - The user token is the visitor ID when the index takes visitor IDs and the token fits one, as Algolia's anonymous tokens do.
- Each index is held to the sites it allows, as its searches are.
A query that asks for results counts as a search. The queries InstantSearch adds only to count a refined facet's values, and searches of facet values, don't count.
When you're ready, move to the SDK
The compatible API is there so switching doesn't have to start with a rewrite, and it's a fine place to stay while you compare. Findlane's own browser SDK and React components speak its API directly, so nothing is lost in translation, and they reach the parts Algolia's request format has no room for:
- Related results when a search's words find nothing, and did-you-mean suggestions.
- One request per search: facet counts for refined filters come with the results, not as extra queries.
- Lists, recommendations, and click and purchase events that feed Bought together and your analytics.
The React components replace InstantSearch's widgets one at a time, so you can move a page or a widget at a time.
Check, then switch
- Compare results. Try your most common searches in the index's Playground and next to your live site. Search tests pin the results that must not change, and every settings change you preview is checked against them.
- Keep both up to date. Until you switch, send each catalog change to both services, so either can answer.
- Search from your site. Add your site's origins on the index's Public access page, then search with the browser SDK, the React components, or the script tag. The quick start shows each. Or keep your InstantSearch pages and point their client here.
- Switch, and keep the Algolia index until you're sure. Then delete the API key you made for the import.
Moving a large catalog, or several indexes? Write to hello@findlane.dev and we'll help with the move.