Overview
Icon for Algolia

Algolia

Sync your product catalog to Algolia for storefront search

medusa-plugin-algolia-plus

A Medusa v2 plugin that syncs your product catalog to Algolia and powers storefront search through the Medusa backend — so your Algolia write key never reaches the browser.

  • Zero application code: register the plugin, set three env vars, and products auto-sync
  • Ships a drop-in InstantSearch Copy to clipboardsearchClient for the storefront
  • Idempotent by design — Copy to clipboardobjectID = product.id, so the index can be rebuilt at any time

Features

  • Automatic sync — product, variant, category, collection, and order events keep the index current
  • Key-safe storefront search — a Copy to clipboard/store/products/search route proxies to Algolia; the admin key stays on the backend
  • Full reindex — one-click catalog rebuild from the admin; running it twice yields no duplicates
  • Stock-accurate availability — derived from inventory levels and refreshed on order events
  • Configurable records — static field overrides, metafield mapping, or a full custom mapper
  • Index settings out of the box — searchable attributes, faceting, and ranking applied on every reindex
  • Production hardening — retry with backoff + jitter, structured logging, never-throw subscribers, workflow compensation
  • Admin UI — Settings → Algolia: connection health, reindex, and per-product re-sync

Requirements

  • Medusa v2 (Copy to clipboard@medusajs/medusa 2.13.5)
  • Node.js Copy to clipboard>=20
  • An Algolia account with a write/admin API key

Installation

npm install medusa-plugin-algolia-plus
# or: pnpm add medusa-plugin-algolia-plus / yarn add medusa-plugin-algolia-plus

The module declares no database models — there is no migration to run.

Setup

Add the following environment variables:

ALGOLIA_APP_ID=your_app_id
ALGOLIA_API_KEY=your_write_api_key
ALGOLIA_PRODUCT_INDEX_NAME=products
# Optional
ALGOLIA_BATCH_SIZE=50 # reindex page size, 11000
ALGOLIA_STOREFRONT_URL=https://shop.example.com # builds each record's `url`
Use a write key, not a Search-Only key. Indexing and settings calls need the Copy to clipboardaddObject, Copy to clipboarddeleteObject, and Copy to clipboardeditSettings ACLs. A Search-Only key fails with "Not enough rights to add an object".

Then register the plugin in Copy to clipboardmedusa-config.js:

const { ALGOLIA_APP_ID, ALGOLIA_API_KEY, ALGOLIA_PRODUCT_INDEX_NAME } = process.env
module.exports = defineConfig({
// ...
plugins: [
{
resolve: "medusa-plugin-algolia-plus",
options: {
appId: ALGOLIA_APP_ID,
apiKey: ALGOLIA_API_KEY, // write key — stays on the backend
productIndexName: ALGOLIA_PRODUCT_INDEX_NAME,
},
},
],
})

Invalid options throw at Medusa startup (Copy to clipboard[algolia] Invalid module options: …), never silently at the first sync.

Configuration

Option Type Default Description Copy to clipboardappId Copy to clipboardstring — Algolia Application ID (required) Copy to clipboardapiKey Copy to clipboardstring — Algolia write key (required) Copy to clipboardproductIndexName Copy to clipboardstring — Product index name (required) Copy to clipboardbatchSize Copy to clipboardnumber (1–1000) Copy to clipboard50 Full-reindex / fan-out page size Copy to clipboardstorefrontUrl Copy to clipboardstring (URL) — Builds each record's Copy to clipboardurl Copy to clipboardcurrencyCodes Copy to clipboardstring[] all Restrict indexed currencies Copy to clipboardproductMapper Copy to clipboardfunction default Replace the record shape entirely Copy to clipboardfieldOverrides Copy to clipboardRecord<string, unknown> — Static fields on every record Copy to clipboardmetadataFields Copy to clipboardRecord<string, string> — Map Copy to clipboardproduct.metadata keys onto record fields Copy to clipboardsearchableAttributes Copy to clipboardstring[] see below Applied at reindex time Copy to clipboardattributesForFaceting Copy to clipboardstring[] see below Applied at reindex time Copy to clipboardcustomRanking Copy to clipboardstring[] Copy to clipboarddesc(availability) Applied at reindex time Copy to clipboardrequestTimeoutMs Copy to clipboardnumber (1k–120k) Copy to clipboard30000 Per-request HTTP timeout Copy to clipboardmaxRetries Copy to clipboardnumber (0–10) Copy to clipboard3 Retries on transient Algolia errors Copy to clipboardretryBaseDelayMs Copy to clipboardnumber (0–60k) Copy to clipboard200 Backoff base delay

Default index settings, applied automatically at the start of every full reindex:

Setting Default Copy to clipboardsearchableAttributes Copy to clipboardtitle, Copy to clipboarddescription, Copy to clipboardvariants.sku, Copy to clipboardtags, Copy to clipboardcategories.name, Copy to clipboardcollection.title Copy to clipboardattributesForFaceting Copy to clipboardsearchable(categories.handle), Copy to clipboardcollection.handle, Copy to clipboardtags, Copy to clipboardavailability Copy to clipboardcustomRanking Copy to clipboarddesc(availability) (in-stock first)

For numeric price filtering, add per-currency facets to Copy to clipboardattributesForFaceting, e.g. Copy to clipboardfilterOnly(price_min.eur).

How It Works

Automatic sync

Thin, never-throwing subscribers keep the index current — a failed sync is logged and can never break a product save:

You do in Medusa In Algolia Create / edit a product Record upserted (or removed if unpublished) Delete a product Record removed Add / edit a variant, change a price Parent product reindexed Rename a category / collection Products in it reindexed Place / cancel / return an order Those products' Copy to clipboardavailability refreshed

A product is in search only while Copy to clipboardstatus === "published"; unpublishing removes it and republishing re-adds it under the same id.

Full reindex

Copy to clipboardPOST /admin/algolia/sync returns Copy to clipboard202 immediately and walks the whole catalog page by page (Copy to clipboardbatchSize), applying index settings first. Trigger it from Settings → Algolia → Reindex all products. It is the catch-all repair for any staleness, and is safe to run at any time.

Availability

Medusa 2.13.5 emits no inventory-level event, so availability is tracked through order events: placing an order reserves stock, cancel/return releases it. A variant counts as available when it is not inventory-managed, allows backorder, or has Copy to clipboardstocked − reserved ≥ required.

Two changes can't be caught in real time and are repaired by a full reindex: a direct admin stock-level edit, and deleting a category, collection, or single variant.

The Algolia record

The default mapper produces one record per product:

{
"objectID": "prod_123", // always the product id
"title": "Cool Shirt",
"handle": "cool-shirt",
"description": "A very cool shirt",
"thumbnail": "https://cdn/thumb.jpg",
"images": [{ "id": "img_1", "url": "https://cdn/1.jpg" }],
"categories": [{ "id": "cat_1", "name": "Shirts", "handle": "shirts" }],
"collection": { "id": "col_1", "title": "Spring", "handle": "spring" },
"tags": ["summer"],
"variants": [{ "id": "var_1", "sku": "SHIRT-S", "prices": { "eur": 1999 } }],
"price_min": { "eur": 1999 }, // per currency, across variants
"price_max": { "eur": 2999 },
"availability": true,
"url": "https://shop.example.com/products/cool-shirt"
}

Prices are keyed by lowercase currency code, in minor units.

Customizing it

// 1. Static fields on every record
fieldOverrides: { brand: "Acme" }
// 2. Project product.metadata onto record fields
metadataFields: { material: "material", season: "season_facet" }
// 3. Replace the shape entirely
import type { ProductMapper } from "medusa-plugin-algolia-plus"
const productMapper: ProductMapper = (product) => ({
objectID: product.id, // must equal the product id
name: product.title,
})

Storefront Integration

The package ships an InstantSearch Copy to clipboardsearchClient that points at the Medusa route, so no Algolia key is needed in the browser:

import { createAlgoliaSearchClient } from "medusa-plugin-algolia-plus/storefront/create-search-client"
export const searchClient = createAlgoliaSearchClient({
backendUrl: process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL!,
publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY!,
})
<InstantSearch searchClient={searchClient} indexName="products">
<SearchBox />
<RefinementList attribute="categories.handle" />
<Hits />
<Pagination />
</InstantSearch>

The full InstantSearch widget ecosystem works unchanged. Pass a custom Copy to clipboardfetchFn for SSR or extra headers.

API Endpoints

Method Route Description Copy to clipboardPOST Copy to clipboard/admin/algolia/sync Trigger a full reindex (returns Copy to clipboard202) Copy to clipboardGET Copy to clipboard/admin/algolia/sync Connection health, index name, current options Copy to clipboardPOST Copy to clipboard/admin/algolia/products/:id Re-sync a single product synchronously Copy to clipboardPOST Copy to clipboard/store/products/search Search; returns the raw Algolia Copy to clipboardSearchResponse

curl -X POST http://localhost:9000/store/products/search \
-H "content-type: application/json" \
-H "x-publishable-api-key: pk_..." \
-d '{"query":"shirt","hitsPerPage":12}'

Body fields: Copy to clipboardquery, Copy to clipboardpage, Copy to clipboardhitsPerPage (1–200), Copy to clipboardfilters, Copy to clipboardfacetFilters, Copy to clipboardnumericFilters, Copy to clipboardfacets, Copy to clipboardattributesToRetrieve. Invalid bodies fail with a structured Copy to clipboard400.

Exports

import {
algoliaModule,
ALGOLIA_MODULE,
AlgoliaModuleService,
syncProductsWorkflow,
deleteProductsFromAlgoliaWorkflow,
productToAlgoliaRecord,
resolveAlgoliaOptions,
AlgoliaEvents,
} from "medusa-plugin-algolia-plus"
import type { ProductMapper, AlgoliaOptions } from "medusa-plugin-algolia-plus"

Copy to clipboardAlgoliaModuleService exposes Copy to clipboardindexData, Copy to clipboardretrieveFromIndex, Copy to clipboarddeleteFromIndex, Copy to clipboardsearch, Copy to clipboardconfigureIndexSettings, Copy to clipboardhealthCheck, and Copy to clipboardmapProducts.

Troubleshooting

Symptom Cause / fix Copy to clipboard[algolia] Invalid module options at startup A required env var is missing — intended fail-fast Copy to clipboardNot enough rights to add an object You used a Search-Only key — switch to a write key "Index products does not exist" The index is created on the first write — fix the key, then reindex No "Algolia" in Settings, or routes 404 Plugin not built, or env not set, so it isn't registered Store search returns Copy to clipboard503 Algolia module not registered (missing env)

Development

pnpm install
pnpm typecheck # tsc --noEmit (module + admin)
pnpm test # 79 unit tests across 9 suites
pnpm build # medusa plugin:build → .medusa/server

License

MIT

You may also like

Browse all integrations

Build your own

Develop your own custom integration

Build your own integration with our API to speed up your processes. Make your integration available via npm for it to be shared in our Library with the broader Medusa community.

gift card interface

Ready to build your custom commerce setup?