docsearch Documentation

Blue_book: The easiest way to add search to your documentation.

4,382 stars TypeScript TypeScript 54 files · ~70,631 tokens #algolia#docsearch#documentation#javascript#react#search#typescript
RAW Doc

Technical Documentation: algolia/docsearch

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (README.md)


DocSearch crawls your documentation, pushes the content to an Algolia index and provides a dropdown search experience on your website.

Preview

Usage

Don't have your Algolia credentials yet? Apply to DocSearch!

JavaScript

Installation

sh
bun add @docsearch/js@5
# or
npm install @docsearch/js@5

If you don’t want to use a package manager, you can use a standalone endpoint:

html
<script src="https://cdn.jsdelivr.net/npm/@docsearch/js@5"></script>

Get started

To get started, you need a container for your DocSearch component to go in. If you don’t have one already, you can insert one into your markup:

html
<div id="docsearch"></div>

Then, insert DocSearch into it by calling the docsearch function and providing the container. It can be a CSS selector or an Element.

Make sure to provide a container (for example, a div), not an input. DocSearch generates a fully accessible search box for you.

js app.js
import docsearch from '@docsearch/js';

import '@docsearch/css';

docsearch({
  container: '#docsearch',
  appId: 'YOUR_APP_ID',
  indices: ['YOUR_INDEX_NAME'],
  apiKey: 'YOUR_SEARCH_API_KEY',
});

React

Installation

bash
bun add @docsearch/react@5
# or
npm install @docsearch/react@5

If you don’t want to use a package manager, you can use a standalone endpoint:

html
<script src="https://cdn.jsdelivr.net/npm/@docsearch/react@5"></script>

Get started

DocSearch generates a fully accessible search box for you.

jsx app.js
import { DocSearch } from '@docsearch/react';

import '@docsearch/css';

function App() {
  return (
    <DocSearch
      appId="YOUR_APP_ID"
      apiKey="YOUR_SEARCH_API_KEY"
      indices=["YOUR_ALGOLIA_INDEX"]
    />
  );
}

export default App;

Styling

Read documentation →

MCP plugins

Client plugins for the public DocSearch MCP endpoint are in mcp/plugins/docsearch. They connect ChatGPT, Codex, Cursor, and Claude Code to https://mcp.algolia.com/1/docsearch/mcp for current public developer documentation.

DocSearch is made of the following repositories:

Used by

DocSearch is used by Bootstrap, Cheerio, Element Plus, Authelia, MDX, VitePress and many more.


Generated with usedby.dev

License

MIT


Packages Website Docs Agent Studio Getting Started (`packages/website/docs/agent-studio/getting-started.mdx`)


title: Get started with Agent Studio

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

DocSearch v5 uses Agent Studio as its only AI backend. The public option is still named askAi, so you can add AI without learning a second DocSearch configuration shape.

Don't add an agentStudio flag. There's no AI backend selector in v5.

If you already have an Ask AI assistant, see Migrate Ask AI to Agent Studio.

Before you begin

  1. Create and publish an Agent Studio agent.
  2. Copy its agent ID. DocSearch calls this value agentId in its public API.
  3. Create a Search API key that can search the indices used by DocSearch and Agent Studio. Don't expose an Admin API key.
  4. Note your Algolia application ID and DocSearch index name.

Add DocSearch

Install the React package and styles:

bash
npm install @docsearch/react@^5 @docsearch/css@^5
bash
yarn add @docsearch/react@^5 @docsearch/css@^5
bash
pnpm add @docsearch/react@^5 @docsearch/css@^5
bash
bun add @docsearch/react@^5 @docsearch/css@^5

Render DocSearchAI, not the search-only DocSearch component:

tsx title="search.tsx"
import { DocSearchAI } from '@docsearch/react';
import '@docsearch/css';

export function Search() {
  return (
    <DocSearchAI
      appId="YOUR_APPLICATION_ID"
      apiKey="YOUR_SEARCH_API_KEY"
      indices={['YOUR_DOCSEARCH_INDEX']}
      askAi={{
        agentId: 'YOUR_AGENT_ID',
      }}
    />
  );
}

See the React package reference for all DocSearchAI props and exported types.

Install the JavaScript package and styles:

bash
npm install @docsearch/js@^5 @docsearch/css@^5
bash
yarn add @docsearch/js@^5 @docsearch/css@^5
bash
pnpm add @docsearch/js@^5 @docsearch/css@^5
bash
bun add @docsearch/js@^5 @docsearch/css@^5

Add a container to your page:

html title="index.html"
<div id="docsearch"></div>

Initialize DocSearch with your Agent Studio agent:

js title="load-docsearch.js"
import docsearch from '@docsearch/js';
import '@docsearch/css';

docsearch({
  container: '#docsearch',
  appId: 'YOUR_APPLICATION_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  indices: ['YOUR_DOCSEARCH_INDEX'],
  askAi: {
    agentId: 'YOUR_AGENT_ID',
  },
});

See the JavaScript package reference for the complete API.

Configure more Agent Studio features

Use the askAi object to add:

Use the Docusaurus adapter

The v5 Docusaurus adapter requires themeConfig.docsearch.askAi to be an object with agentId. It rejects the string shorthand and the removed agentStudio property. Keep appId, apiKey, and keyword-search indices at the top level.

See the Docusaurus adapter guide for its full configuration and validation rules.


Packages Website Docs Mcp Overview (`packages/website/docs/mcp/overview.mdx`)


title: DocSearch MCP sidebar_label: Overview

DocSearch MCP lets AI clients search public developer documentation in the DocSearch corpus.

Use it when an assistant needs information from published documentation instead of relying only on its training data. Connect an MCP-compatible client to this endpoint:

text
https://mcp.algolia.com/1/docsearch/mcp

The endpoint doesn't require authentication. You don't need an Algolia application ID, search API key, or DocSearch application.

What DocSearch MCP provides

DocSearch MCP exposes documentation search through the Model Context Protocol. Your client calls its tools, receives ranked documentation excerpts and source URLs, and uses those results to answer your question.

Use DocSearch MCP for public documentation about libraries, frameworks, SDKs, APIs, CLI tools, and cloud services. It doesn't provide access to:

  • Private or unpublished documentation
  • Internal repositories
  • DocSearch crawler or administration operations
  • Algolia indices or credentials
  • General programming advice outside the indexed documentation

How searches work

For most searches, provide a product name and a focused question. DocSearch resolves the matching documentation set and searches it in one call.

Use the two-step workflow when a question covers several products or when you need to select the documentation set yourself. First resolve candidate sets, then query the selected set IDs.

Available tools

`algolia_docsearch_search_docs`

Use this one-shot tool for most searches. Set library to the official product, SDK, or platform name. Set query to the documentation question.

The tool resolves the best matching documentation set and returns ranked content. If the product name is ambiguous, it returns candidate documentation sets instead.

`algolia_docsearch_resolve_docset`

Use this tool first in the manual workflow. It returns candidate documentation sets with a docset_id, title, description, and ranking signals.

`algolia_docsearch_query_docs`

Use this tool with one or more docset_id values returned by algolia_docsearch_resolve_docset. Pass several IDs when the question covers more than one product.

Security and service limits

Connect only to the HTTPS endpoint shown on this page. Don't add Algolia credentials to the MCP configuration. Send documentation questions, not secrets or confidential data, to the hosted service.

DocSearch MCP searches public content and returns external documentation to your client. Review generated answers and commands before you use them.

:::note[Service terms]

Algolia DocSearch MCP is a free service and is provided by Algolia "AS IS" and "AS AVAILABLE" without warranty of any kind. Algolia may suspend, modify, or discontinue the service at any time at its sole discretion. Algolia disclaims all obligation and liability arising from or related to your use of DocSearch MCP. You must comply with all applicable laws and government regulations when you use the service.

:::

Next steps


Packages Website Docs Packages Overview (`packages/website/docs/packages/overview.mdx`)


title: DocSearch packages

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

DocSearch v5 provides keyword search, AI answers powered by Agent Studio, and lower-level packages for custom integrations.

Start with @docsearch/js for a browser integration or @docsearch/react for a React application. Both packages support the same keyword search options.

Choose a package

Package Use it for
@docsearch/js JavaScript sites, including sites that don't use React. The default entry includes keyword search and Ask AI.
@docsearch/react React applications. Choose DocSearch for keyword search or DocSearchAI for keyword search and Ask AI.
@docsearch/css The complete button and modal stylesheet. See Styling.
@docsearch/core Shared state, keyboard handling, and the provider for the Composable API.
@docsearch/modal Search button, keyword modal, and Ask AI modal components for the Composable API.
@docsearch/sidepanel React Sidepanel components for persistent AI conversations.
@docsearch/sidepanel-js JavaScript wrapper for the AI Sidepanel.

If your Docusaurus site uses the DocSearch adapter, follow the Docusaurus adapter guide.

Choose a search experience

Use keyword search when you only need results from Algolia indices. It has no Ask AI runtime.

  • JavaScript: import @docsearch/js/docsearch.
  • React: render DocSearch from @docsearch/react.

Keyword search and Ask AI

Use the AI-capable integration when you have an Agent Studio assistant.

  • JavaScript: use the default @docsearch/js export.
  • React: render DocSearchAI from @docsearch/react.

Create and configure the assistant before adding it to DocSearch. See Get started with Agent Studio.

Composable and hybrid experiences

Use the Composable API to control the provider, button, and modal separately. Use hybrid mode to combine the modal with the AI Sidepanel.

For an existing v4 integration, read Migrate from v4 and v5 breaking changes.


Packages Website Docs Packages Core Overview (`packages/website/docs/packages/core/overview.mdx`)


title: Core package

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

@docsearch/core provides the React state shared by DocSearch views. It owns open and close state, keyboard events, theme selection, lifecycle callbacks, initial queries, and imperative controls. It doesn't render a search interface by itself.

Install

bash
npm install @docsearch/core@^5
bash
yarn add @docsearch/core@^5
bash
pnpm add @docsearch/core@^5
bash
bun add @docsearch/core@^5

Packages such as @docsearch/modal and @docsearch/sidepanel consume this provider. For component composition instructions, see the Composable API guide.

Configure shared behavior

tsx title="searchstate.tsx"
import { DocSearch } from '@docsearch/core';

export function SearchState({ children }: { children: React.ReactNode }) {
  return (
    <DocSearch
      theme="dark"
      initialQuery="authentication"
      keyboardShortcuts={{
        'Ctrl/Cmd+K': true,
        '/': false,
        'Ctrl/Cmd+I': true,
      }}
      onReady={() => track('docsearch_ready')}
      onOpen={() => track('search_opened')}
      onClose={() => track('search_closed')}
      onSidepanelOpen={() => track('assistant_opened')}
      onSidepanelClose={() => track('assistant_closed')}
    >
      {children}
    </DocSearch>
  );
}

The default shortcuts enable Control/Command+K, /, and Control/Command+I. Slash doesn't open the modal while focus is in an input, select, textarea, or editable element.

Use a ref

tsx title="searchstate.tsx"
import { DocSearch, type DocSearchRef } from '@docsearch/core';
import { useRef } from 'react';

export function SearchState({ children }: { children: React.ReactNode }) {
  const ref = useRef<DocSearchRef>(null);

  return (
    <>
      <button type="button" onClick={() => ref.current?.open()}>
        Open search
      </button>
      <DocSearch ref={ref}>{children}</DocSearch>
    </>
  );
}

The ref can open and close registered views and report their state. See the core API reference. For interactions between views, see Hybrid Mode.

Read provider state

Call useDocSearch only beneath DocSearch. The hook throws outside the provider.

tsx title="searchstatus.tsx"
import { useDocSearch } from '@docsearch/core';

export function SearchStatus() {
  const { docsearchState, openModal, closeModal } = useDocSearch();

  return (
    <button
      type="button"
      onClick={docsearchState === 'ready' ? openModal : closeModal}
    >
      {docsearchState === 'ready' ? 'Open search' : 'Close search'}
    </button>
  );
}

Use the higher-level modal and Sidepanel packages for their standard triggers. Read context directly when your interface needs custom controls.


Packages Website Docs Packages Docusaurus Adapter Getting Started (`packages/website/docs/packages/docusaurus-adapter/getting-started.mdx`)


title: Docusaurus adapter

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Use @docsearch/docusaurus-adapter to add keyword search, a search results page, Ask AI, and an Ask AI Sidepanel to Docusaurus.

Before you start

Collect these values:

  • An Algolia application ID.
  • A Search API key with access to your DocSearch indices.
  • At least one DocSearch index name.
  • An Agent Studio assistant ID if you want Ask AI or the Sidepanel. Follow Get started with Agent Studio to create one.

Use Node.js 20 or later, Docusaurus 3.10.2 or later in the Docusaurus 3 release line, and React 18 or 19.

Install the adapter

Install @docsearch/docusaurus-adapter@^5:

bash
npm install @docsearch/docusaurus-adapter@^5
bash
yarn add @docsearch/docusaurus-adapter@^5
bash
pnpm add @docsearch/docusaurus-adapter@^5
bash
bun add @docsearch/docusaurus-adapter@^5

Keep @docusaurus/preset-classic. Don't add @docusaurus/theme-search-algolia as another search integration.

Add the adapter to plugins. Configure it under themeConfig.docsearch:

js title="docusaurus.config.mjs"
export default {
  plugins: ['@docsearch/docusaurus-adapter'],
  themeConfig: {
    docsearch: {
      appId: 'YOUR_APPLICATION_ID',
      apiKey: 'YOUR_SEARCH_API_KEY',
      indices: [{ name: 'YOUR_INDEX_NAME' }],
    },
  },
};

indices is required and must contain at least one index. Use an object to set search parameters for one index:

js title="docusaurus.config.mjs"
indices: [
  {
    name: 'docs',
    searchParameters: {
      facetFilters: ['language:en'],
      attributesToRetrieve: [
        'content',
        'hierarchy',
        'type',
        'url',
        'version',
      ],
    },
  },
],

Start Docusaurus and open the search modal. The adapter also creates /search and links to it from the modal. Change or disable that route with searchPage.

Add Ask AI

Set askAi to an object with your Agent Studio assistant ID:

js title="docusaurus.config.mjs"
export default {
  plugins: ['@docsearch/docusaurus-adapter'],
  themeConfig: {
    docsearch: {
      appId: 'YOUR_APPLICATION_ID',
      apiKey: 'YOUR_SEARCH_API_KEY',
      indices: [{ name: 'YOUR_INDEX_NAME' }],
      askAi: {
        assistantId: 'YOUR_ASSISTANT_ID',
      },
    },
  },
};

The adapter uses Agent Studio for Ask AI. Pass an object, not an assistant ID string. It reuses the root appId, apiKey, and first keyword index unless you configure dynamic Agent Studio indices.

Add the Sidepanel

Set sidePanel at the root of docsearch. You must also configure askAi:

js title="docusaurus.config.mjs"
docsearch: {
  appId: 'YOUR_APPLICATION_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  indices: [{ name: 'YOUR_INDEX_NAME' }],
  askAi: {
    assistantId: 'YOUR_ASSISTANT_ID',
  },
  sidePanel: true,
},

Pass an object instead of true to configure its placement, width, questions, translations, memory, or indices. The modal and Sidepanel share the DocSearch provider. Review hybrid mode for their responsive behavior.

Next steps


Packages Website Docs Packages Js Getting Started (`packages/website/docs/packages/js/getting-started.mdx`)


title: JS package

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

Use @docsearch/js to render DocSearch into an HTML element. The default entry includes keyword search and Ask AI. A separate entry includes keyword search only.

Before you start

Collect your Algolia application ID, Search API key, and index name. To add Ask AI, also create an assistant in Agent Studio and copy its assistant ID.

Install the packages

bash
npm install @docsearch/js@^5 @docsearch/css@^5
bash
yarn add @docsearch/js@^5 @docsearch/css@^5
bash
pnpm add @docsearch/js@^5 @docsearch/css@^5
bash
bun add @docsearch/js@^5 @docsearch/css@^5

Add a container where you want the search button:

html title="index.html"
<div id="docsearch"></div>

Pass a container element or a selector that matches one. Don't pass an input; DocSearch renders the search button and input.

Add keyword search and Ask AI

Import the default entry and provide an askAi configuration:

js title="app.js"
import docsearch from '@docsearch/js';

import '@docsearch/css';

const search = docsearch({
  container: '#docsearch',
  appId: 'YOUR_APP_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  indices: ['YOUR_INDEX_NAME'],
  askAi: {
    assistantId: 'YOUR_ASSISTANT_ID',
  },
});

The default entry bundles both experiences. askAi accepts an assistant ID string or a configuration object. See the JavaScript API reference.

Add keyword search only

Import the /docsearch entry to exclude Ask AI code:

js title="app.js"
import docsearch from '@docsearch/js/docsearch';

import '@docsearch/css';

const search = docsearch({
  container: '#docsearch',
  appId: 'YOUR_APP_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  indices: ['YOUR_INDEX_NAME'],
});

Load DocSearch from a CDN

Load the complete stylesheet and one JavaScript bundle. Both UMD bundles expose window.docsearch.

Keyword search and Ask AI

html title="index.html"
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@docsearch/css@^5/dist/style.css"
/>
<script src="https://cdn.jsdelivr.net/npm/@docsearch/js@^5/dist/umd/index.js"></script>
<script>
  window.docsearch({
    container: '#docsearch',
    appId: 'YOUR_APP_ID',
    apiKey: 'YOUR_SEARCH_API_KEY',
    indices: ['YOUR_INDEX_NAME'],
    askAi: {
      assistantId: 'YOUR_ASSISTANT_ID',
    },
  });
</script>

Keyword search only

html title="index.html"
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@docsearch/css@^5/dist/style.css"
/>
<script src="https://cdn.jsdelivr.net/npm/@docsearch/js@^5/dist/umd/docsearch.js"></script>
<script>
  window.docsearch({
    container: '#docsearch',
    appId: 'YOUR_APP_ID',
    apiKey: 'YOUR_SEARCH_API_KEY',
    indices: ['YOUR_INDEX_NAME'],
  });
</script>

Don't load both UMD bundles on the same page. The second bundle replaces the same window.docsearch global.

Control the instance

docsearch() returns a DocSearchInstance:

js title="app.js"
const search = docsearch({
  container: '#docsearch',
  appId: 'YOUR_APP_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  indices: ['YOUR_INDEX_NAME'],
  askAi: 'YOUR_ASSISTANT_ID',
});

search.open();
search.close();
search.openAskAi({ query: 'How do I configure search?' });

// Unmount DocSearch when your application removes this view.
search.destroy();

Use openAskAi() only with the default AI-capable entry.

Next steps


Packages Website Docs Packages Modal Overview (`packages/website/docs/packages/modal/overview.mdx`)


title: Modal package

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

@docsearch/modal provides the DocSearch search button, keyword-search modal, and Agent Studio-enabled modal for React. Render these components inside the DocSearch provider from @docsearch/core.

For the complete component workflow, see the Composable API guide.

Install

bash
npm install @docsearch/core@^5 @docsearch/modal@^5 @docsearch/css@^5
bash
yarn add @docsearch/core@^5 @docsearch/modal@^5 @docsearch/css@^5
bash
pnpm add @docsearch/core@^5 @docsearch/modal@^5 @docsearch/css@^5
bash
bun add @docsearch/core@^5 @docsearch/modal@^5 @docsearch/css@^5

Import the main stylesheet once, near your application entry point.

tsx title="search.tsx"
import { DocSearch } from '@docsearch/core';
import { DocSearchButton, DocSearchModal } from '@docsearch/modal';

import '@docsearch/css';

export function Search() {
  return (
    <DocSearch>
      <DocSearchButton />
      <DocSearchModal
        appId="YOUR_APPLICATION_ID"
        apiKey="YOUR_SEARCH_API_KEY"
        indices={['YOUR_INDEX_NAME']}
      />
    </DocSearch>
  );
}

Use a search-only API key. Don't expose an Algolia Admin API key in browser code.

Add Agent Studio

In v5, Ask AI uses Agent Studio. Pass an Agent Studio agent ID through askAi. There's no agentStudio boolean in the v5 API.

tsx title="search.tsx"
import { DocSearch } from '@docsearch/core';
import { DocSearchAskAiModal, DocSearchButton } from '@docsearch/modal';

import '@docsearch/css';

export function Search() {
  return (
    <DocSearch>
      <DocSearchButton />
      <DocSearchAskAiModal
        appId="YOUR_APPLICATION_ID"
        apiKey="YOUR_SEARCH_API_KEY"
        indices={['YOUR_INDEX_NAME']}
        askAi="YOUR_AGENT_ID"
      />
    </DocSearch>
  );
}

The askAi object also supports custom tools, conversation memory, and dynamic indices. See the DocSearchAskAiModal API.

Set provider options

The modal package reads theme, keyboard shortcut, and lifecycle state from DocSearch.

tsx title="search.tsx"
<DocSearch
  theme="dark"
  keyboardShortcuts={{ 'Ctrl/Cmd+K': true, '/': false }}
  onOpen={() => track('search_opened')}
  onClose={() => track('search_closed')}
>
  <DocSearchButton />
  <DocSearchModal
    appId="YOUR_APPLICATION_ID"
    apiKey="YOUR_SEARCH_API_KEY"
    indices={['YOUR_INDEX_NAME']}
  />
</DocSearch>

See the @docsearch/core API for provider props and refs.

Load smaller entry points

The package exposes component-specific entry points for code splitting:

tsx title="search.tsx"
import { DocSearchAskAiModal } from '@docsearch/modal/askai';
import { DocSearchButton } from '@docsearch/modal/button';
import { DocSearchModal } from '@docsearch/modal/modal';

See the modal API reference for all exports and props.


Packages Website Docs Packages React Getting Started (`packages/website/docs/packages/react/getting-started.mdx`)


title: React package

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

@docsearch/react exports separate components for keyword search and Ask AI. Choose the component that matches your application.

Before you start

Collect your Algolia application ID, Search API key, and index name. To add Ask AI, create an assistant in Agent Studio and copy its assistant ID.

Install the packages

bash
npm install @docsearch/react@^5 @docsearch/css@^5
bash
yarn add @docsearch/react@^5 @docsearch/css@^5
bash
pnpm add @docsearch/react@^5 @docsearch/css@^5
bash
bun add @docsearch/react@^5 @docsearch/css@^5

The package supports React and React DOM versions from 16.8 through 19.

Render DocSearch when your site only needs keyword results:

jsx title="search.jsx"
import { DocSearch } from '@docsearch/react';

import '@docsearch/css';

export function Search() {
  return (
    <DocSearch
      appId="YOUR_APP_ID"
      apiKey="YOUR_SEARCH_API_KEY"
      indices={['YOUR_INDEX_NAME']}
    />
  );
}

DocSearch doesn't include the Ask AI experience.

Add keyword search and Ask AI

Render DocSearchAI and pass the Agent Studio assistant:

jsx title="search.jsx"
import { DocSearchAI } from '@docsearch/react';

import '@docsearch/css';

export function Search() {
  return (
    <DocSearchAI
      appId="YOUR_APP_ID"
      apiKey="YOUR_SEARCH_API_KEY"
      indices={['YOUR_INDEX_NAME']}
      askAi={{
        assistantId: 'YOUR_ASSISTANT_ID',
      }}
    />
  );
}

askAi also accepts the assistant ID as a string. Use the object form for Agent Studio search parameters, dynamic indices, tools, memory, and prompt suggestions.

Control DocSearch with a ref

Both components forward a DocSearchRef:

tsx title="search.tsx"
import { useRef } from 'react';
import { DocSearchAI, type DocSearchRef } from '@docsearch/react';

export function Search() {
  const searchRef = useRef<DocSearchRef>(null);

  return (
    <>
      <button
        type="button"
        onClick={() =>
          searchRef.current?.openAskAi({
            query: 'How do I configure search?',
          })
        }
      >
        Ask about setup
      </button>
      <DocSearchAI
        ref={searchRef}
        appId="YOUR_APP_ID"
        apiKey="YOUR_SEARCH_API_KEY"
        indices={['YOUR_INDEX_NAME']}
        askAi="YOUR_ASSISTANT_ID"
      />
    </>
  );
}

Use open() and close() for keyword search. Sidepanel methods become useful when you register a Sidepanel through hybrid mode.

Next steps


Packages Website Docs Packages Sidepanel Js Getting Started (`packages/website/docs/packages/sidepanel-js/getting-started.mdx`)


title: Sidepanel JS package

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

@docsearch/sidepanel-js mounts the Agent Studio Sidepanel into an existing HTML element. It bundles its rendering dependencies and returns an imperative instance.

Install

bash
npm install @docsearch/sidepanel-js@^5 @docsearch/css@^5
bash
yarn add @docsearch/sidepanel-js@^5 @docsearch/css@^5
bash
pnpm add @docsearch/sidepanel-js@^5 @docsearch/css@^5
bash
bun add @docsearch/sidepanel-js@^5 @docsearch/css@^5

Add a container to your page:

html title="index.html"
<div id="docsearch-sidepanel"></div>

Mount the Sidepanel and retain the returned instance:

js title="load-sidepanel.js"
import sidepanel from '@docsearch/sidepanel-js';

import '@docsearch/css';
import '@docsearch/css/dist/sidepanel.css';

const assistant = sidepanel({
  container: '#docsearch-sidepanel',
  appId: 'YOUR_APPLICATION_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  agentId: 'YOUR_AGENT_ID',
  onReady() {
    console.info('DocSearch sidepanel is ready');
  },
});

Use a search-only API key. The agentId is an Agent Studio agent ID.

Open with a question

Pass an initial message to open:

js title="load-sidepanel.js"
assistant.open({
  query: 'How do I configure a search-only API key?',
});

Call assistant.destroy() before removing the container or remounting another Sidepanel in it.

Load from a CDN

html title="index.html"
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@docsearch/css@^5/dist/style.css"
/>
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@docsearch/css@^5/dist/sidepanel.css"
/>

<div id="docsearch-sidepanel"></div>

<script src="https://cdn.jsdelivr.net/npm/@docsearch/sidepanel-js@^5/dist/umd/index.js"></script>
<script>
  const assistant = docsearchSidepanel({
    container: '#docsearch-sidepanel',
    appId: 'YOUR_APPLICATION_ID',
    apiKey: 'YOUR_SEARCH_API_KEY',
    agentId: 'YOUR_AGENT_ID',
  });
</script>

See the JavaScript Sidepanel API for configuration, Agent Studio options, callbacks, and instance methods.


Packages Website Docs Packages Sidepanel Getting Started (`packages/website/docs/packages/sidepanel/getting-started.mdx`)


title: Sidepanel package

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

@docsearch/sidepanel provides composable React components for an Agent Studio chat panel.

Install

bash
npm install @docsearch/core@^5 @docsearch/sidepanel@^5 @docsearch/css@^5
bash
yarn add @docsearch/core@^5 @docsearch/sidepanel@^5 @docsearch/css@^5
bash
pnpm add @docsearch/core@^5 @docsearch/sidepanel@^5 @docsearch/css@^5
bash
bun add @docsearch/core@^5 @docsearch/sidepanel@^5 @docsearch/css@^5

Render the Sidepanel

Import both the main DocSearch stylesheet and the Sidepanel stylesheet.

tsx title="helpassistant.tsx"
import { DocSearch } from '@docsearch/core';
import { Sidepanel, SidepanelButton } from '@docsearch/sidepanel';

import '@docsearch/css';
import '@docsearch/css/dist/sidepanel.css';

export function HelpAssistant() {
  return (
    <DocSearch>
      <SidepanelButton />
      <Sidepanel
        appId="YOUR_APPLICATION_ID"
        apiKey="YOUR_SEARCH_API_KEY"
        agentId="YOUR_AGENT_ID"
      />
    </DocSearch>
  );
}

Use a search-only API key. The agentId is an Agent Studio agent ID. V5 doesn't provide the legacy Ask AI backend or an agentStudio switch.

The default button and panel float over the page. Press Control+I or Command+I to toggle the panel, and press Escape to close it.

Configure the provider

Set the theme and lifecycle callbacks on DocSearch.

tsx title="helpassistant.tsx"
<DocSearch
  theme="dark"
  keyboardShortcuts={{ 'Ctrl/Cmd+I': true }}
  onSidepanelOpen={() => track('assistant_opened')}
  onSidepanelClose={() => track('assistant_closed')}
>
  <SidepanelButton variant="inline" />
  <Sidepanel
    appId="YOUR_APPLICATION_ID"
    apiKey="YOUR_SEARCH_API_KEY"
    agentId="YOUR_AGENT_ID"
  />
</DocSearch>

Continue with advanced use cases or review the Sidepanel API. For a combined search and assistant experience, see Hybrid Mode.


Packages Website Docs Api (`packages/website/docs/api.mdx`)


title: API references

Choose the reference for the package in your application:

For an end-to-end example, start with the package overview.

`container`

See the @docsearch/js API for the JavaScript container option.

Translations

See the React API for the shared translation structure.

`askAi`

See Get started with Agent Studio for AI configuration.


Packages Website Docs Composable Api (`packages/website/docs/composable-api.mdx`)


title: Composable API

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

The composable API gives you control over where DocSearch renders, when its modal code loads, and how the rest of your application opens or closes it.

Use this API in React applications. For the connected component reference, see the modal package overview.

Choose a modal

DocSearch v5 provides two modal components. Render one modal for each DocSearch provider.

Component Use it for
DocSearchModal Keyword search without Ask AI
DocSearchAskAiModal Keyword search and Ask AI in the same modal

DocSearchAskAiModal includes keyword search. Don't render both modal components to add Ask AI.

The composable components come from three packages:

Install the packages

Install matching v5 versions of the DocSearch packages:

bash
npm install @docsearch/core@^5 @docsearch/modal@^5 @docsearch/css@^5
bash
yarn add @docsearch/core@^5 @docsearch/modal@^5 @docsearch/css@^5
bash
pnpm add @docsearch/core@^5 @docsearch/modal@^5 @docsearch/css@^5
bash
bun add @docsearch/core@^5 @docsearch/modal@^5 @docsearch/css@^5

Wrap the button and keyword modal in one DocSearch provider. Pass a public search-only API key to the provider; its descendants use these credentials by default.

tsx title="keywordsearch.tsx"
import { DocSearch } from '@docsearch/core';
import { DocSearchButton, DocSearchModal } from '@docsearch/modal';
import type { JSX } from 'react';

import '@docsearch/css/dist/style.css';

interface KeywordSearchProps {
  appId: string;
  apiKey: string;
  indexName: string;
}

export function KeywordSearch({
  appId,
  apiKey,
  indexName,
}: KeywordSearchProps): JSX.Element {
  return (
    <DocSearch appId={appId} apiKey={apiKey}>
      <DocSearchButton
        translations={{
          buttonText: 'Search docs',
          buttonAriaLabel: 'Search documentation',
        }}
      />
      <DocSearchModal indices={[indexName]} />
    </DocSearch>
  );
}

The provider opens the modal when a user selects the button, presses Ctrl/Command+K, or presses / outside an editable field. Closing the modal returns focus to DocSearchButton.

Add keyword search and Ask AI

Replace DocSearchModal with DocSearchAskAiModal. Create the assistant in Agent Studio, then configure its ID on the provider.

tsx title="searchwithaskai.tsx"
import { DocSearch } from '@docsearch/core';
import { DocSearchAskAiModal, DocSearchButton } from '@docsearch/modal';
import type { JSX } from 'react';

import '@docsearch/css/dist/style.css';

interface SearchWithAskAiProps {
  appId: string;
  apiKey: string;
  indexName: string;
  agentId: string;
}

export function SearchWithAskAi({
  appId,
  apiKey,
  indexName,
  agentId,
}: SearchWithAskAiProps): JSX.Element {
  return (
    <DocSearch appId={appId} apiKey={apiKey}>
      <DocSearchButton />
      <DocSearchAskAiModal
        indices={[indexName]}
        askAi={agentId}
      />
    </DocSearch>
  );
}

The askAi prop accepts an assistant ID string or an object with agentId. Use the object form when you need options such as indices, searchParameters, suggestedQuestions, promptSuggestions, tools, or memory. Set appId and apiKey on an individual modal or Sidepanel only when they must override the provider's defaults.

Understand the shared state

DocSearch holds one state value and shares it with its descendants:

State Meaning
ready No modal or Sidepanel is open.
modal-search The keyword search view is open.
modal-askai Ask AI is open in the modal.
sidepanel The Ask AI Sidepanel is open.

The connected components manage these transitions for you:

  • DocSearchButton calls its own onClick handler, then opens keyword search.
  • Each modal registers itself with the provider and renders in a React portal only while a modal state is active.
  • DocSearchModal reads the provider's initial query and close action.
  • DocSearchAskAiModal also reads and updates the Ask AI state.

Use useDocSearch in a component under the provider when your application needs declarative access to this state.

tsx
import { useDocSearch } from '@docsearch/core';
import type { JSX } from 'react';

export function SearchControls(): JSX.Element {
  const { closeModal, docsearchState, openModal, onAskAiToggle } =
    useDocSearch();

  return (
    <div>
      <span>Search state: {docsearchState}</span>
      <button type="button" onClick={openModal}>
        Open search
      </button>
      <button type="button" onClick={() => onAskAiToggle(true)}>
        Open Ask AI
      </button>
      <button type="button" onClick={closeModal}>
        Close search
      </button>
    </div>
  );
}

Only call onAskAiToggle(true) when the provider contains DocSearchAskAiModal or a compatible Ask AI view.

Control DocSearch with a ref

Attach a DocSearchRef to the provider when non-React code or a parent component must control DocSearch.

tsx
import { DocSearch, type DocSearchRef } from '@docsearch/core';
import { DocSearchAskAiModal, DocSearchButton } from '@docsearch/modal';
import { useRef, type JSX } from 'react';

interface ControlledSearchProps {
  appId: string;
  apiKey: string;
  indexName: string;
  agentId: string;
  onReady?: () => void;
  onOpen?: () => void;
  onClose?: () => void;
}

export function ControlledSearch(props: ControlledSearchProps): JSX.Element {
  const searchRef = useRef<DocSearchRef>(null);

  return (
    <DocSearch
      ref={searchRef}
      onReady={props.onReady}
      onOpen={props.onOpen}
      onClose={props.onClose}
    >
      <DocSearchButton />
      <button
        type="button"
        onClick={() =>
          searchRef.current?.openAskAi({
            query: 'How do I configure DocSearch?',
          })
        }
      >
        Ask a question
      </button>
      <DocSearchAskAiModal
        appId={props.appId}
        apiKey={props.apiKey}
        indices={[props.indexName]}
        askAi={props.agentId}
      />
    </DocSearch>
  );
}

The ref exposes these methods and read-only values. initialMessage has a required query and optional messageId and suggestedQuestionId fields.

The provider accepts onReady, onOpen, onClose, onSidepanelOpen, and onSidepanelClose. onReady runs after mount. The other callbacks run once when their corresponding view changes state, not every time React renders.

`open`

type: () => void

Opens keyword search.

`close`

type: () => void

Returns the provider to ready.

`openAskAi`

type: (initialMessage?: InitialAskAiMessage) => void

Opens Ask AI in a registered Sidepanel on desktop, or in the modal otherwise.

`openSidepanel`

type: (initialMessage?: InitialAskAiMessage) => void

Opens a registered Sidepanel. It does nothing when no Sidepanel is registered.

`isReady`

type: readonly boolean

Reports whether the provider is mounted.

`isOpen`

type: readonly boolean

Reports whether a modal view is open.

`isSidepanelOpen`

type: readonly boolean

Reports whether the Sidepanel is open.

`isSidepanelSupported`

type: readonly boolean

Reports whether desktop hybrid mode is available.

Load the modal on demand

Import the button eagerly and split the larger modal into another JavaScript chunk. The following Ask AI example preloads that chunk on hover, focus, or touch, then renders it only after the provider opens a modal state.

text
/* Detailed source-code truncated for AI context efficiency. */

Render the provider and connected components only in the browser. The modal wrappers read document.body and window.scrollY when they render.

Use the exact entry points

Use the package root for convenience or a subpath to keep eager bundles focused.

Import Exports
@docsearch/core DocSearch, useDocSearch, their types, keyboard utilities, and theme utilities
@docsearch/modal DocSearchButton, DocSearchModal, DocSearchAskAiModal, and their prop types
@docsearch/modal/button DocSearchButton, DocSearchButtonProps
@docsearch/modal/modal DocSearchModal, DocSearchModalProps
@docsearch/modal/askai DocSearchAskAiModal, DocSearchAskAiModalProps

The lower-level React entry points are @docsearch/react/button, @docsearch/react/modal, and @docsearch/react/askaiModal. They don't connect themselves to the composable provider. Use them only when you intend to manage portal rendering, refs, initialScrollY, close behavior, and Ask AI state yourself.

Load the styles

For either complete modal, import the combined stylesheet once:

ts
import '@docsearch/css/dist/style.css';

The combined stylesheet contains variables, button styles, keyword modal styles, and Ask AI modal styles. It doesn't contain Sidepanel styles.

For a keyword-only CSS bundle, import the layers in this order:

ts
import '@docsearch/css/dist/_variables.css';
import '@docsearch/css/dist/button.css';
import '@docsearch/css/dist/modal.css';

Add @docsearch/css/dist/_askai.css when you use DocSearchAskAiModal. Bundlers can also load the same files through @docsearch/react/style, @docsearch/react/style/button, @docsearch/react/style/modal, @docsearch/react/style/askai, and @docsearch/react/style/variables.

API summary

API Required configuration Provider-managed behavior
DocSearch children State, credentials defaults, theme, initial query, shortcuts, focus restoration, lifecycle callbacks, and DocSearchRef
DocSearchButton None Button ref, theme, shortcuts, and opening keyword search
DocSearchModal At least one indices entry or deprecated indexName; appId and apiKey must be set here or on DocSearch Open state, close action, initial scroll position, initial query, theme, and shortcuts
DocSearchAskAiModal The keyword modal configuration plus askAi Keyword modal behavior, Ask AI state, Ask AI transitions, and hybrid detection
useDocSearch A parent DocSearch provider Reads the context and throws when used outside the provider

DocSearchButton accepts native React button props and translations. The connected wrapper doesn't accept theme or keyboardShortcuts; set those on DocSearch.

Both connected modal wrappers accept the corresponding low-level modal options, except the state and lifecycle fields supplied by the provider. Explicit appId and apiKey props override their respective provider values. Consult the modal API before adding options.


Packages Website Docs Crawler Configuration Visual (`packages/website/docs/crawler-configuration-visual.mdx`)


title: Crawler interface

import useBaseUrl from '@docusaurus/useBaseUrl';

Use the Algolia Crawler interface to manage crawl settings and monitor indexing. These settings are separate from your installed DocSearch frontend package version.

DocSearch tab

The Crawler UI now includes a dedicated DocSearch tab. This tab provides everything you need to implement DocSearch on your site, including:

  • Implementation code: Starter snippets for integrating DocSearch into your frontend. For v5, compare the snippet with the current package guide.
  • API keys: Your unique Application ID and Search API Key for connecting to your Algolia index.
  • Documentation links: Access to review your records, explore documentation, and join the support Discord.

Trigger a new crawl

Head over to the Overview section to start, restart or pause your crawls and view a real-time summary.

Monitor your crawls

The Monitoring section helps you find crawl errors or improve your search results.

Update your config

You can update your crawler configuration in two ways:

Visual configuration: Edit common options without writing code in the visual configuration interface.

Code editor: For advanced configuration, use the live code editor to modify your configuration and test URLs with the URL tester.

URL tester

From the editor, you can use the URL tester to debug selectors or see how the crawler interprets your site.

Suggestions

The Suggestions section in the Crawler UI provides actionable feedback to help you improve your crawl and data extraction. After each crawl, you'll see recommendations for:

  • Fixing redirect or domain issues
  • Addressing ignored or failed URLs
  • Adding missing sitemaps

Each suggestion includes a description, a solution, and links to relevant documentation or monitoring tools.


Packages Website Docs Crawler (`packages/website/docs/crawler.mdx`)


title: DocSearch x Algolia Crawler

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Use this page to resolve common crawler questions. If you need more help, contact us on Discord or through Algolia support.

For more troubleshooting guidance, read the Crawler FAQ:

For questions related to the DocSearch program, please see our DocSearch program FAQ.

How often will you crawl my website?

Crawls are scheduled at a random time once a week. You can configure this schedule from the config file or trigger one manually from the Crawler interface.

Why do I have duplicate content in my results?

This can happen when you have more than one URL pointing to the same content, for example with ./docs, ./docs/ and ./docs/index.html.

Configure canonical URLs on your website. For more information, read Google's Consolidate duplicate URLs guide.

Use exclusionPatterns to exclude duplicate URL patterns.

Are the [`docsearch-scraper`][9] and [`docsearch-configs`][10] repositories still maintained?

The legacy scraper infrastructure is deprecated. You can still run a legacy scraper instance and use its index with the historical DocSearch v3 UI. For current frontend integrations, choose a DocSearch v5 package. The scraper or crawler version doesn't determine the frontend package version.

How do I migrate?

Every owner should have received a migration email from Algolia with the details. If you were not part of the previous index owners, or the maintainer has changed, you can request access via our support page.

Use the migration email to complete these steps:

  • Join the Algolia application with the invite included in the email
  • Update your frontend integration with the credentials received in the email. For v5, follow the JavaScript or React guide.

<Tabs
groupId="language"
aria-label="Programming language"
defaultValue="react"
values={[
{ label: 'React', value: 'react', },
{ label: 'JavaScript', value: 'js', },
]
}>

jsx title="search.tsx"
<DocSearch
  appId="YOUR_NEW_ALGOLIA_APP_ID"
  apiKey="YOUR_NEW_ALGOLIA_SEARCH_API_KEY"
  indices={['YOUR_INDEX_NAME']} // The index name doesn't change.
/>
js title="search.js"
docsearch({
  container: '#docsearch',
  appId: 'YOUR_NEW_ALGOLIA_APP_ID',
  apiKey: 'YOUR_NEW_ALGOLIA_SEARCH_API_KEY',
  indices: ['YOUR_INDEX_NAME'], // The index name doesn't change.
});

What should I do with my legacy config and credentials?

Use the credentials for your current Algolia application. Don't use legacy credentials for new frontend integrations.

You should use the dedicated web interface to make any changes to your index.

Why do I see two Algolia apps in my dashboard?

We did not remove access to the legacy DocSearch application (BH4D9OD16A) to give you the time to get familiar with our new infrastructure. BH4D9OD16A will remain available until the migration has been completed for all the DocSearch users.

Search yields no results

If your search does not yield any results, but there is no error in your browser developer tools, there might be an issue with your index.

Check the following settings:

  1. Confirm that your crawler configuration matches your website structure.

    Use a configuration template for your website generator as a starting point. Test your selectors with the URL tester.

  2. Confirm that your index settings are current. If they aren't, the search preview displays a banner.

    The crawler applies index settings only when it creates an index, which keeps the Algolia dashboard as the source of truth. If you changed your configuration significantly or moved to a different website generator, delete the index from the Algolia dashboard before starting a new crawl.

Can I delete my crawler?

Don't delete the default crawler associated with your DocSearch application. Creating a replacement might not preserve the program configuration.

What if I delete my DocSearch Crawler?

Contact us on Discord or email us at the address below.

Can I use the crawler on password-protected sites?

The crawler included with DocSearch applications can't access password-protected sites that require a login. To crawl these sites, choose an Algolia plan and add a crawler. Pay-as-you-go plans include a crawler, but the free tier has usage limits.


Packages Website Docs Create Crawler (`packages/website/docs/create-crawler.mdx`)


title: Create a new crawler

import useBaseUrl from '@docusaurus/useBaseUrl';

Create a new crawler

:::info

DocSearch apps created after July 2, 2024 can use the Algolia Crawler UI to set up and manage crawls. This guide covers adding your domain, verifying ownership, creating a crawler, and running your first test crawl. Open the Crawler UI at dashboard.algolia.com/crawler.

If you signed up before July 2, 2024, you can still use the Crawler UI, but creating and managing a crawler is more streamlined for users who joined after that date.

Learn more about the Crawler interface.

:::

Add domains

  1. Sign in to the Algolia dashboard.
  2. In the left sidebar, select Data sources.
  3. Select Crawler:
    • Click Add your domain and enter the domains or subdomains you want to crawl (e.g., example.com, www.example.com).
    • If you’ve already added a domain, click the Domains tab.
  4. Click Add domain.

Note: Verify your domain within 7 days of adding it. The DocSearch team must also approve the domain before you can crawl it.

Verify your domain

You must verify ownership of each domain you want to crawl. The default method is email verification, but you can also use a meta tag, HTML file, robots.txt, or DNS record.

Meta tag

  1. In the Meta tag tab, click Copy to copy the verification tag.
  2. Add the tag to your site's <head> section.
  3. Publish your site and click Verify now in the Crawler dashboard.

HTML file

  1. In the HTML file tab, click Copy to copy the verification file content.
  2. Save it as a new HTML file and upload it to your web server.
  3. Add the file’s URL in the dashboard and click Verify now.

robots.txt

  1. In the Robots.txt tab, click Copy to copy the verification code.
  2. Paste it into your site's robots.txt file.
  3. Publish and click Verify now.

DNS

  1. In the DNS tab, copy the provided DNS TXT record.
  2. Add it to your DNS provider’s settings.
  3. Click Verify now after the record propagates (may take up to 72 hours).

Create a new crawler

After you verify your domain and the DocSearch team approves it:

  1. Go to the Crawler page in the dashboard.
  2. Click New Crawler and fill in:
    • Crawler name (descriptive)
    • App ID (your Algolia application ID)
    • Start URL (usually your home page)
    • Crawler template (choose a template or default)
  3. Click Create to finish and run a test crawl.

Run the test crawl

The initial crawl visits up to 100 URLs to test access and extraction. Monitor its progress on the Overview page. After it finishes, review the extracted records in the Algolia dashboard.

Creating a crawler doesn't install or select a DocSearch frontend version. After indexing, choose a DocSearch v5 package or framework integration.

Next steps

  • Edit your crawler configuration for scheduled crawls, inclusion/exclusion rules, and extraction settings.
  • Use the Crawler’s suggestions for further optimization.
  • For more details, see the Algolia Crawler documentation.

Packages Website Docs Docsearch Program (`packages/website/docs/docsearch-program.md`)


title: DocSearch program

Use this page to learn about the DocSearch program. If you need more help, contact us on Discord or through Algolia support.

For questions about the DocSearch crawler, see the Crawler FAQ.

What do I need to install on my side?

After your content is indexed, add a DocSearch v5 frontend package with the application ID, Search API key, and index name from your Algolia application.

DocSearch uses the Algolia Crawler to index your content. Use the Crawler interface to create, monitor, edit, and start crawlers. For crawler questions, see the Crawler FAQ. Crawler configuration and frontend package versions are independent.

How much does it cost?

The DocSearch program is free.

Search infrastructure can be costly for open source projects, so the DocSearch program is free. In exchange, keep the "Search by Algolia" logo next to the search results.

If you can't display the logo, create an Algolia account and run DocSearch on your own. Depending on the size of your documentation, you might need a paid plan. Free plans can hold up to 10,000 records.

What data are you collecting?

We extract data from your website markup and store it in a custom JSON format in your Algolia DocSearch index. The selectors in your crawler configuration determine what data to extract.

As the website owner, you can access your Algolia application to review indexed data, analyze anonymized searches, and manage your team.

Where is my data hosted?

We host DocSearch data on Algolia servers with replicas around the world. For more information, see the Algolia infrastructure documentation and privacy policy.

How do I upgrade my DocSearch app?

Choose an option based on your goal.

Upgrade #1: I want a specific feature, like Rules, added to my existing DocSearch application

Contact Algolia support to discuss your requirements.

Removing the logo makes the project ineligible for the free DocSearch program. Instead, host the open source legacy DocSearch crawler or use an Algolia API client. Both options require a new Algolia application, and usage charges may apply.

Upgrade #3: Algolia is awesome, I want to use it for my whole site

Contact the Algolia sales team to choose a plan. After creating your application, adapt a crawler configuration template for the new crawler.

Can I use DocSearch on non-doc pages?

The free DocSearch program crawls only documentation pages for open source projects and technical blogs. To index other parts of your website, create an Algolia account and choose one of these options:

Can you index code samples?

Yes, but we do not recommend it.

Code samples can help users understand a method, but repeated boilerplate adds noise to search results.

A documentation website I like does not use DocSearch. What can I do?

If a documentation website does not use DocSearch, file an issue in its repository that explains how DocSearch could help. You can also contact us on Discord.

How did we build this website?

We built this website with Docusaurus. Endi helped inspire the project. Read our tribute to Endi.

Can I share the `apiKey` in my repo?

The apiKey from the DocSearch team is a search-only API key, so you can share it publicly and track it in version control. If you run the scraper yourself, create a search-only key and don't share your Admin API key.

Why is the email API key different in the dashboard?

Every Algolia application has a default "Search API Key" in the dashboard. That key lets you list indices, retrieve settings, and search every index in your application. For DocSearch applications, the acceptance email includes a search-only API key scoped to your DocSearch index. To recover this key, contact Algolia support.

How do I rotate my API keys?

Contact Algolia support.

Can I have multiple projects under the same Algolia application?

Use one Algolia application per project. Apply to the DocSearch program for each additional project.

Why?

The information of the initially applied project is used everywhere when we deploy your app:

  • The scope of your API keys
  • The name of your Algolia application/Crawler
  • The indices we generate
  • The allowed domains of your Crawler

This information helps us scope support requests to the correct project.

Support

:::caution

Before contacting support, read the relevant documentation.

Here are some links to help you:

Visit Algolia Academy to learn more about Algolia.

:::

Algolia doesn't provide support for the DocSearch UI library, but support is available for these products:

For any issue related to the DocSearch UI library, please open a GitHub issue.


Packages Website Docs Docsearch (`packages/website/docs/docsearch.mdx`)


title: Get started with DocSearch

DocSearch v5 provides separate packages for JavaScript, React, composable interfaces, and framework integrations.

Start with the package overview to choose an integration:

To upgrade an existing integration, follow Migrating from v4.

Installation

Install instructions depend on your package. Open the package guide above for commands and required styles.


Packages Website Docs Docusaurus Adapter (`packages/website/docs/docusaurus-adapter.mdx`)


title: Docusaurus adapter

Use @docsearch/docusaurus-adapter to add DocSearch v5 to a Docusaurus site.


Packages Website Docs Examples (`packages/website/docs/examples.mdx`)


title: Examples

Use these guides for production-ready examples:

For JavaScript setup examples, see Get started with @docsearch/js.


Packages Website Docs How Does It Work (`packages/website/docs/how-does-it-work.mdx`)


title: How does it work?

import useBaseUrl from '@docusaurus/useBaseUrl';

DocSearch setup has three parts: join the DocSearch program, index your content, and add a frontend package or framework integration.

You apply

First, confirm that your website qualifies, then apply for DocSearch. The onboarding flow validates your domain against the program requirements.

If automated validation can't determine eligibility, the application might require a manual review.

Index your content

After approval, create a dedicated crawler in your Algolia application. Its configuration file defines which URLs to crawl, which URLs to ignore, and which selectors extract your content hierarchy.

Run a test crawl, review the extracted records, and configure recurring crawls. Use the Crawler interface to adjust the configuration as your website changes.

With the Crawler, comes a dedicated interface for you to:

  • Start, schedule and monitor your crawls
  • Edit and test your crawler configuration

With the Algolia application comes access to the dashboard for you to:

  • Browse your index and see how your content is indexed
  • Review analytics to understand how search performs
  • Trials for other Algolia features
  • Team management

Add DocSearch to your website

Choose a DocSearch v5 package or supported framework integration. Configure it with your application ID, Search API key, and index name. The frontend queries the Algolia index and displays the results.

Crawler versions, record schema versions, and frontend package versions are separate. In particular, crawler recordVersion: 'v3' describes the indexed record schema, not the DocSearch UI version. You can upgrade the v5 frontend packages without recreating the crawler. Keep the "Search by Algolia" logo next to your search results.


Packages Website Docs Hybrid Mode (`packages/website/docs/hybrid-mode.mdx`)


title: Hybrid mode

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

Hybrid mode starts in the DocSearch modal, then moves an Ask AI request into the Sidepanel. Users can scan keyword results in a focused overlay and continue an AI conversation beside the page.

The handoff carries the prompt and its identifiers. It doesn't submit the same prompt in both interfaces.

Prerequisites

Before you add hybrid mode:

  • Use matching v5 DocSearch package versions.
  • Configure a searchable Algolia index and a public search-only API key.
  • Create an assistant in Agent Studio.
  • Decide whether you need React, JavaScript, or the DocSearch Docusaurus adapter.

Read the package references for core, modal, Sidepanel, JavaScript, Sidepanel JavaScript, and the Docusaurus adapter when you need options beyond this workflow.

Understand the handoff

An Ask AI action can come from a typed prompt, a suggested question, a prompt suggestion in keyword results, or a saved conversation.

DocSearch represents the action as an InitialAskAiMessage:

ts
interface InitialAskAiMessage {
  query: string;
  messageId?: string;
  suggestedQuestionId?: string;
}

Preserve the complete object during a manual handoff:

  • query becomes the first prompt when the Sidepanel starts a conversation.
  • suggestedQuestionId is sent with the prompt so Agent Studio can identify the selected suggestion.
  • messageId lets the Sidepanel restore a locally stored conversation. If it can't find that conversation, it starts a new one with query.

Add hybrid mode

React

Install the connected React packages and CSS:

bash
npm install @docsearch/core@^5 @docsearch/modal@^5 @docsearch/sidepanel@^5 @docsearch/css@^5
bash
yarn add @docsearch/core@^5 @docsearch/modal@^5 @docsearch/sidepanel@^5 @docsearch/css@^5
bash
pnpm add @docsearch/core@^5 @docsearch/modal@^5 @docsearch/sidepanel@^5 @docsearch/css@^5
bash
bun add @docsearch/core@^5 @docsearch/modal@^5 @docsearch/sidepanel@^5 @docsearch/css@^5

Render DocSearchAskAiModal and Sidepanel under the same DocSearch provider. The Sidepanel registers itself with the provider after mount. From then on, desktop Ask AI actions move to the Sidepanel automatically.

tsx title="hybridsearch.tsx"
import { DocSearch } from '@docsearch/core';
import { DocSearchAskAiModal, DocSearchButton } from '@docsearch/modal';
import { Sidepanel, SidepanelButton } from '@docsearch/sidepanel';
import type { JSX } from 'react';

import '@docsearch/css/dist/style.css';
import '@docsearch/css/dist/sidepanel.css';

interface HybridSearchProps {
  appId: string;
  apiKey: string;
  keywordIndexName: string;
  agentId: string;
  onReady?: () => void;
  onOpen?: () => void;
  onClose?: () => void;
  onSidepanelOpen?: () => void;
  onSidepanelClose?: () => void;
}

export function HybridSearch({
  appId,
  apiKey,
  keywordIndexName,
  agentId,
  onReady,
  onOpen,
  onClose,
  onSidepanelOpen,
  onSidepanelClose,
}: HybridSearchProps): JSX.Element {
  return (
    <DocSearch
      onReady={onReady}
      onOpen={onOpen}
      onClose={onClose}
      onSidepanelOpen={onSidepanelOpen}
      onSidepanelClose={onSidepanelClose}
    >
      <DocSearchButton />
      <DocSearchAskAiModal
        appId={appId}
        apiKey={apiKey}
        indices={[keywordIndexName]}
        askAi={{ agentId }}
      />

      <SidepanelButton />
      <Sidepanel
        appId={appId}
        apiKey={apiKey}
        agentId={agentId}
      />
    </DocSearch>
  );
}

SidepanelButton gives users a direct Ask AI entry point. You can omit it without disabling hybrid handoff. Keep Sidepanel mounted so it can register before a user submits an Ask AI request.

React lifecycle callbacks

Put lifecycle callbacks on DocSearch so they observe the shared state.

During the automatic React handoff, the state changes directly from modal-askai to sidepanel. That transition calls onSidepanelOpen; it doesn't call onClose.

`onReady`

type: () => void | optional

Runs when the provider mounts.

`onOpen`

type: () => void | optional

Runs when a modal opens from ready or sidepanel.

`onClose`

type: () => void | optional

Runs when a modal changes directly to ready.

`onSidepanelOpen`

type: () => void | optional

Runs when the state changes to sidepanel.

`onSidepanelClose`

type: () => void | optional

Runs when the state leaves sidepanel.

JavaScript

The JavaScript packages create independent DocSearch and Sidepanel instances. Connect them with interceptAskAiEvent.

bash
npm install @docsearch/js@^5 @docsearch/sidepanel-js@^5 @docsearch/css@^5
bash
yarn add @docsearch/js@^5 @docsearch/sidepanel-js@^5 @docsearch/css@^5
bash
pnpm add @docsearch/js@^5 @docsearch/sidepanel-js@^5 @docsearch/css@^5
bash
bun add @docsearch/js@^5 @docsearch/sidepanel-js@^5 @docsearch/css@^5

Add one mount element for each instance:

html title="index.html"
<div id="docsearch"></div>
<div id="docsearch-sidepanel"></div>

Create the Sidepanel first so the interceptor always has a target. The mobile check in this example matches the React integration: mobile users stay in the Ask AI modal, while desktop users move to the Sidepanel.

ts title="search.ts"
import docsearch, { type DocSearchInstance } from '@docsearch/js';
import sidepanel, { type SidepanelInstance } from '@docsearch/sidepanel-js';

import '@docsearch/css/dist/style.css';
import '@docsearch/css/dist/sidepanel.css';

const appId = 'YOUR_APP_ID';
const apiKey = 'YOUR_SEARCH_API_KEY';
const keywordIndexName = 'YOUR_KEYWORD_INDEX_NAME';
const agentId = 'YOUR_AGENT_ID';
const mobileQuery = window.matchMedia('(max-width: 768px)');

let search: DocSearchInstance | undefined;
let panel: SidepanelInstance | undefined;

panel = sidepanel({
  container: '#docsearch-sidepanel',
  appId,
  apiKey,
  agentId,
  onReady: () => {
    document.body.setAttribute('data-sidepanel-ready', '');
  },
  onOpen: () => {
    search?.close();
    document.body.setAttribute('data-sidepanel-open', '');
  },
  onClose: () => {
    document.body.removeAttribute('data-sidepanel-open');
  },
});

search = docsearch({
  container: '#docsearch',
  appId,
  apiKey,
  indices: [keywordIndexName],
  askAi: agentId,
  interceptAskAiEvent: (initialMessage) => {
    if (mobileQuery.matches) {
      return false;
    }

    search?.close();
    panel?.open(initialMessage);
    return true;
  },
  onReady: () => {
    document.body.setAttribute('data-docsearch-ready', '');
  },
  onOpen: () => {
    panel?.close();
    document.body.setAttribute('data-search-open', '');
  },
  onClose: () => {
    document.body.removeAttribute('data-search-open');
  },
});

The root @docsearch/js export includes Ask AI. The keyword-only JavaScript entry point is @docsearch/js/docsearch; don't use that entry point for hybrid mode because it has no Ask AI action to intercept.

How `interceptAskAiEvent` works

interceptAskAiEvent runs before the modal changes to Ask AI or sends a message.

  • Return true after another interface accepts the request. DocSearch clears the keyword query and skips all default Ask AI behavior.
  • Return false or undefined to keep the default Ask AI modal flow.
  • Pass initialMessage unchanged to sidepanelInstance.open(initialMessage) so conversation and suggestion IDs survive.

Keep the onOpen callbacks that close the other instance. They prevent two interfaces from staying open when application code calls search.open(), search.openAskAi(), or panel.open() directly.

The JavaScript instances expose these lifecycle callbacks and controls:

  • The DocSearch instance accepts the onReady, onOpen, and onClose callbacks, and exposes open(), close(), openAskAi(), destroy(), isReady, and isOpen.
  • The Sidepanel instance accepts the onReady, onOpen, and onClose callbacks, and exposes open(), close(), destroy(), isReady, and isOpen.

Call both destroy() methods if your application removes the mount elements or tears down the page without a full navigation.

Add hybrid mode to Docusaurus

Hybrid mode is supported through @docsearch/docusaurus-adapter. The adapter loads the v5 modal and Sidepanel, connects their state, and applies the mobile behavior described in this guide.

Install the adapter and keep @docusaurus/preset-classic:

bash
npm install @docsearch/docusaurus-adapter@^5
bash
yarn add @docsearch/docusaurus-adapter@^5
bash
pnpm add @docsearch/docusaurus-adapter@^5
bash
bun add @docsearch/docusaurus-adapter@^5

Configure DocSearch under themeConfig.docsearch. Set top-level sidePanel to true or to a Sidepanel options object.

js title="docusaurus.config.mjs"
export default {
  plugins: ['@docsearch/docusaurus-adapter'],
  themeConfig: {
    docsearch: {
      appId: 'YOUR_APP_ID',
      apiKey: 'YOUR_SEARCH_API_KEY',
      indices: [{ name: 'YOUR_INDEX_NAME' }],
      askAi: {
        agentId: 'YOUR_AGENT_ID',
      },
      sidePanel: true,
      contextualSearch: true,
      searchPage: { path: 'search' },
    },
  },
};

The adapter requires askAi to be an object with agentId; it doesn't accept the string shorthand in Docusaurus configuration. It also requires askAi whenever sidePanel is set.

Don't put sidePanel inside askAi. Don't configure this adapter under themeConfig.algolia. If you need function-valued custom tools, pass them through a swizzled @theme/SearchBar component because Docusaurus removes functions while serializing theme configuration.

The built-in @docusaurus/theme-search-algolia integration doesn't provide this v5 Sidepanel configuration. Use the DocSearch adapter for this workflow.

Mobile behavior

The React provider treats viewports that match (max-width: 768px) as mobile. On those viewports, an Ask AI action stays in the modal even when a Sidepanel is registered. This avoids moving the conversation into the desktop Sidepanel layout.

The provider updates this decision on window resize. The Sidepanel also avoids focusing its prompt automatically on mobile because opening the virtual keyboard can disrupt the layout.

The JavaScript packages don't share a provider, so they don't apply the hybrid mobile decision to your interceptor. Add the matchMedia branch shown in the JavaScript example when you want the same behavior.

Load the styles

Hybrid mode needs both style bundles:

ts title="search.ts"
import '@docsearch/css/dist/style.css';
import '@docsearch/css/dist/sidepanel.css';

style.css includes shared variables, the button, keyword modal, and Ask AI modal. sidepanel.css adds the Sidepanel layout and imports the shared variables it needs.

If your bundler resolves the React style entry points, @docsearch/react/style and @docsearch/react/style/sidepanel load the same bundles. Import each bundle once.

Troubleshoot hybrid mode

Ask AI stays in the modal on desktop

Confirm that Sidepanel is mounted under the same DocSearch provider before the Ask AI action. The provider enables automatic handoff only after the Sidepanel registers. Also confirm that the viewport is wider than 768 pixels.

Both the modal and Sidepanel submit the prompt

Return true from interceptAskAiEvent after calling panel.open(initialMessage). Returning false or no value tells the modal to continue its default flow.

Mobile users open the Sidepanel

In JavaScript integrations, check (max-width: 768px) in the interceptor and return false on a match. React and the Docusaurus adapter already make this decision.

The Sidepanel loses a suggestion or saved conversation

Pass the complete initialMessage object to open(). Rebuilding it with only query discards suggestedQuestionId and messageId.

A callback doesn't run during React handoff

Expect onSidepanelOpen, not onClose, when React changes directly from the modal to the Sidepanel. Use the shared provider callbacks rather than treating modal close as the handoff signal.

Two JavaScript interfaces remain open

Close the search instance in the Sidepanel's onOpen, and close the Sidepanel in the search instance's onOpen. This also covers programmatic calls that bypass the interceptor.

The interface is unstyled

Import both style.css and sidepanel.css. Check that your bundler includes CSS imports from dependencies.

Docusaurus rejects the configuration

Use themeConfig.docsearch, pass askAi as an object, and put sidePanel beside askAi. Install @docsearch/docusaurus-adapter@^5 instead of configuring hybrid mode through the built-in Algolia theme.

Server rendering fails with `window` or `document` errors

Mount the composable React components only in the browser. The Docusaurus adapter handles this boundary and lazy-loads the modal and Sidepanel client-side.


Packages Website Docs Integrations (`packages/website/docs/integrations.md`)


title: Supported integrations

Documentation frameworks can embed DocSearch in the websites they generate. A framework integration configures the frontend; your Algolia Crawler and index remain separate.

Framework integrations

If you use one of the following tools, follow its documentation to enable DocSearch. Framework documentation can target a different DocSearch frontend release, so check its package compatibility before adopting v5.

If you maintain a similar tool and want us to add it to the list, open a pull request and contribute to Code Exchange.


Packages Website Docs Manage Your Crawls (`packages/website/docs/manage-your-crawls.mdx`)


title: Legacy crawler interface

:::caution

This crawler interface is deprecated and no longer maintained. It isn't a DocSearch frontend version. For current instructions, use the Crawler interface guide. Open the current interface at dashboard.algolia.com/crawler.

:::

import useBaseUrl from '@docusaurus/useBaseUrl';

DocSearch comes with the Algolia Crawler web interface that allows you to configure how and when your Algolia index will be populated.

Trigger a new crawl

Head over to the Overview section to start, restart or pause your crawls and view a real-time summary.

Monitor your crawls

The monitoring section helps you find crawl errors or improve your search results.

Update your config

The live editor allows you to update your config file and test your URLs (URL tester).

Search preview

The legacy editor's Search preview tab renders results with the historical DocSearch v3 frontend. This preview doesn't require your website to use that frontend version. For current integrations, see the v5 package guides.

URL tester

From the editor, your can use the URL tester to debug selectors or how we crawl your website.


Packages Website Docs Migrating From Legacy (`packages/website/docs/migrating-from-legacy.mdx`)


title: Migrating from the legacy scraper

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Introduction

This guide covers the historical migration from the self-hosted DocSearch scraper to the Algolia Crawler. It is separate from upgrading the frontend UI. For the current frontend, choose a DocSearch v5 package.

What's new?

Indexing infrastructure

DocSearch indexing now uses the Algolia Crawler. The DocSearch helper extracts records in place of the legacy DocSearch scraper.

You don't need to install local scraper tooling to maintain or update your index.

Use the legacy interface or the current Crawler interface to:

  • Start, schedule and monitor your crawls
  • Edit your config file from our live editor
  • Test results with the historical DocSearch v3 or DocSearch v4 previews

These preview versions don't set the crawler record schema or the frontend package installed on your website. Likewise, crawler recordVersion: 'v3' names a record schema, not DocSearch UI v3.

Algolia application and credentials

We've received a lot of requests asking for:

  • A way to manage team members
  • Browse and see how Algolia records are indexed
  • See and subscribe to other Algolia features

These features are available in your Algolia application.

FAQ

You can find answers related to the DocSearch migration in our Crawler FAQ page.

Config file key mapping

Below are the keys that can be found in the legacy DocSearch configs and their translation to an Algolia Crawler config. For more detailed information on the Algolia Crawler, see the official documentation.

legacy current description
start_urls startUrls Now accepts URLs only, see helpers.docsearch to handle custom variables
page_rank pageRank Can be added to the recordProps in helpers.docsearch, should be passed as a string
js_render renderJavaScript Unchanged
js_wait renderJavascript.waitTime See documentation of renderJavaScript
index_name removed, see actions Handled directly in the actions
sitemap_urls sitemaps Unchanged
stop_urls exclusionPatterns Supports micromatch
selectors_exclude removed Should be handled in the recordExtractor and helpers.docsearch
custom_settings initialIndexSettings Unchanged
scrape_start_urls removed Can be handled with exclusionPatterns
strip_chars removed # are removed automatically from anchor links, edge cases should be handled in the recordExtractor and helpers.docsearch
conversation_id removed Not needed anymore
nb_hits removed Not needed anymore
sitemap_alternate_links removed Not needed anymore
stop_content removed Should be handled in the recordExtractor and helpers.docsearch

Packages Website Docs Migrating From V4 (`packages/website/docs/migrating-from-v4.mdx`)


title: Migrate from DocSearch v4

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

DocSearch v5 separates keyword search from the AI experience and uses Agent Studio for Ask AI. Plan the migration around the experience your site provides.

Review the complete v5 breaking changes before releasing.

1. Upgrade packages

Upgrade every DocSearch package in the integration together with the ^5 range.

bash
npm install @docsearch/react@^5 @docsearch/css@^5
bash
yarn add @docsearch/react@^5 @docsearch/css@^5
bash
pnpm add @docsearch/react@^5 @docsearch/css@^5
bash
bun add @docsearch/react@^5 @docsearch/css@^5
bash
npm install @docsearch/js@^5 @docsearch/css@^5
bash
yarn add @docsearch/js@^5 @docsearch/css@^5
bash
pnpm add @docsearch/js@^5 @docsearch/css@^5
bash
bun add @docsearch/js@^5 @docsearch/css@^5

If you use the Composable API or Sidepanel, also upgrade @docsearch/core@^5, @docsearch/modal@^5, @docsearch/sidepanel@^5, or @docsearch/sidepanel-js@^5.

JavaScript without Ask AI

The v4 root export rendered the combined component. In v5, the root export is AI-capable and the /docsearch subpath is keyword-only.

Change the import:

diff title="app.js"
-import docsearch from '@docsearch/js';
+import docsearch from '@docsearch/js/docsearch';

Your keyword options can remain unchanged while you migrate deprecated options in a later step.

For a CDN integration, replace the root bundle with the keyword-only UMD file:

diff title="index.html"
-<script src="https://cdn.jsdelivr.net/npm/@docsearch/js@4"></script>
+<script src="https://cdn.jsdelivr.net/npm/@docsearch/js@^5/dist/umd/docsearch.js"></script>

JavaScript with Ask AI

Keep the root import. It now renders the AI-capable DocSearchAI component:

js title="app.js"
import docsearch from '@docsearch/js';

docsearch({
  container: '#docsearch',
  appId: 'YOUR_APP_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  indices: ['YOUR_INDEX_NAME'],
  askAi: {
    agentId: 'YOUR_AGENT_ID',
  },
});

For a CDN integration, use dist/umd/index.js. It exposes window.docsearch, as v4 did.

React without Ask AI

Keep DocSearch, but remove any AI props. In v5 it renders keyword search only:

jsx title="search.jsx"
import { DocSearch } from '@docsearch/react';

<DocSearch
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['YOUR_INDEX_NAME']}
/>;

React with Ask AI

Replace DocSearch with DocSearchAI:

diff title="search.jsx"
-import { DocSearch } from '@docsearch/react';
+import { DocSearchAI } from '@docsearch/react';

-<DocSearch
+<DocSearchAI
   appId="YOUR_APP_ID"
   apiKey="YOUR_SEARCH_API_KEY"
   indices={['YOUR_INDEX_NAME']}
   askAi={{ agentId: 'YOUR_AGENT_ID' }}
 />

DocSearchAI requires askAi. The string shorthand remains supported:

jsx title="search.jsx"
<DocSearchAI askAi="YOUR_AGENT_ID" {...searchProps} />

3. Move Ask AI to Agent Studio

V5 removes the legacy Ask AI token and chat transport. Create the agent in Agent Studio before switching production traffic. If you already have an Ask AI assistant, follow Migrate Ask AI to Agent Studio.

Rename assistantId to agentId. Remove agentStudio from askAi. Agent Studio is the only Ask AI backend in v5.

diff title="app.js"
askAi: {
-  assistantId: 'YOUR_ASSISTANT_ID',
+  agentId: 'YOUR_AGENT_ID',
-  agentStudio: true,
 }

The v4 Agent Studio form keyed search parameters by index name. V5 keeps that shape and removes the legacy flat form:

diff title="app.js"
askAi: {
-  assistantId: 'YOUR_ASSISTANT_ID',
+  agentId: 'YOUR_AGENT_ID',
   searchParameters: {
-    filters: 'language:en',
-    attributesToRetrieve: ['title', 'content', 'url'],
+    docs: {
+      filters: 'language:en',
+      attributesToRetrieve: ['title', 'content', 'url'],
+    },
   },
 }

Agent Studio search parameters support filters, attributesToRetrieve, restrictSearchableAttributes, and distinct. They don't support facetFilters in this object. Put fixed facet conditions in filters, or configure dynamic Agent Studio indices.

V5 adds askAi.indices, askAi.tools, askAi.memory, and askAi.promptSuggestions. Keep all Agent Studio configuration inside askAi. Keep interceptAskAiEvent at the component or docsearch() root because it controls view routing.

4. Move keyword configuration to `indices`

indexName and root searchParameters both have been removed in v5.

diff title="app.js"
docsearch({
   appId: 'YOUR_APP_ID',
   apiKey: 'YOUR_SEARCH_API_KEY',
-  indexName: 'docs',
-  searchParameters: {
-    facetFilters: ['language:en'],
-  },
+  indices: [
+    {
+      name: 'docs',
+      searchParameters: {
+        facetFilters: ['language:en'],
+      },
+    },
+  ],
 });

Use one item per index. DocSearch queries them in array order.

5. Update result customization

Existing transformItems, hitComponent, resultsFooterComponent, transformSearchClient, navigation, Insights, and translation props remain available.

V5 changes the result markup and adds breadcrumbs, source sections, facets, and badges. Review custom CSS, DOM selectors, screenshots, and tests that depend on v4 markup.

To show a badge from a custom record property, add the property to the per-index attributesToRetrieve, then set resultBadgeKey:

jsx title="search.jsx"
<DocSearch
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={[
    {
      name: 'docs',
      searchParameters: {
        attributesToRetrieve: [
          'hierarchy.lvl0',
          'hierarchy.lvl1',
          'hierarchy.lvl2',
          'hierarchy.lvl3',
          'hierarchy.lvl4',
          'hierarchy.lvl5',
          'hierarchy.lvl6',
          'content',
          'type',
          'url',
          'version',
        ],
      },
    },
  ]}
  resultBadgeKey="version"
/>

6. Verify styles and package exports

The full stylesheet remains available from @docsearch/css and the CDN dist/style.css file:

js title="app.js"
import '@docsearch/css';

The React package adds split style entries for variables, button, modal, Ask AI, and Sidepanel. See Styling.

@docsearch/js now defines an exports map. Replace unsupported deep imports with @docsearch/js or @docsearch/js/docsearch. Continue to use documented React subpaths such as @docsearch/react/button, /modal, /sidepanel, and /version; their generated file names changed, but the package subpaths remain the public API.

7. Verify programmatic controls

The JavaScript function returns a DocSearchInstance with open, close, openAskAi, destroy, isReady, and isOpen. Use openAskAi only with the default AI-capable entry.

React forwards DocSearchRef. It also exposes openSidepanel, isSidepanelOpen, and isSidepanelSupported for hybrid mode.

Test these cases before release:

  • Open and close by button, Ctrl/Cmd+K, /, and Escape.
  • Search every configured index and apply every facet.
  • Open Ask AI, send follow-up questions, submit feedback, and restore a conversation.
  • Exercise any custom tools and memory authentication.
  • Verify custom hit links, result footers, translations, badges, and Insights events.
  • Verify mobile behavior. Hybrid mode uses the modal instead of the Sidepanel on mobile.

8. Update framework integrations

If Docusaurus manages DocSearch configuration, follow the Docusaurus adapter guide. For custom provider, button, and modal layouts, review the Composable API.


Packages Website Docs Record Extractor (`packages/website/docs/record-extractor.md`)


title: Record Extractor

Introduction

:::info

This page documents the helpers.docsearch method. See the Algolia Crawler documentation for information about the Algolia Crawler.

:::

Set the recordExtractor parameter on an action to extract each page. Its function returns the data to index as an array of JSON objects.

The helpers are functions for extracting content and generating Algolia records.

Usage

The most common way to use the DocSearch helper is to return its result to the recordExtractor function.

js
recordExtractor: ({ helpers }) => {
  return helpers.docsearch({
    recordProps: {
      lvl0: {
        selectors: "header h1",
      },
      lvl1: "article h2",
      lvl2: "article h3",
      lvl3: "article h4",
      lvl4: "article h5",
      lvl5: "article h6",
      content: "main p, main li",
    },
  });
},

Manipulate the DOM with Cheerio

The Cheerio instance ($) allows you to manipulate the DOM:

js
recordExtractor: ({ $, helpers }) => {
  // Removing DOM elements we don't want to crawl
  $(".my-warning-message").remove();

  return helpers.docsearch({
    recordProps: {
      lvl0: {
        selectors: "header h1",
      },
      lvl1: "article h2",
      lvl2: "article h3",
      lvl3: "article h4",
      lvl4: "article h5",
      lvl5: "article h6",
      content: "main p, main li",
    },
  });
},

Provide fallback selectors

Fallback selectors can be useful when retrieving content that might not exist in some pages:

js
recordExtractor: ({ $, helpers }) => {
  return helpers.docsearch({
    recordProps: {
      // `.exists h1` will be selected if `.exists-probably h1` does not exists.
      lvl0: {
        selectors: [".exists-probably h1", ".exists h1"],
      },
      lvl1: "article h2",
      lvl2: "article h3",
      lvl3: "article h4",
      lvl4: "article h5",
      lvl5: "article h6",
      // `.exists p, .exists li` will be selected.
      content: [
        ".does-not-exists p, .does-not-exists li",
        ".exists p, .exists li",
      ],
    },
  });
},

Provide raw text (`defaultValue`)

Only the lvl0 and custom variables selectors support this option

You might want to structure your search results differently than your website, or provide a defaultValue to a potentially non-existent selector:

js
recordExtractor: ({ $, helpers }) => {
  return helpers.docsearch({
    recordProps: {
      lvl0: {
        // It also supports the fallback DOM selectors syntax!
        selectors: ".exists-probably h1",
        defaultValue: "myRawTextIfDoesNotExists",
      },
      lvl1: "article h2",
      lvl2: "article h3",
      lvl3: "article h4",
      lvl4: "article h5",
      lvl5: "article h6",
      content: "main p, main li",
      // The variables below can be used to filter your search
      language: {
        // It also supports the fallback DOM selectors syntax!
        selectors: ".exists-probably .language",
        // Since custom variables are used for filtering, we allow sending
        // multiple raw values
        defaultValue: ["en", "en-US"],
      },
    },
  });
},

Indexing content for faceting

These selectors also support defaultValue and fallback selectors

To index content for frontend filters, such as version or language, define custom variables in recordProps. The helper adds them to each matching Algolia record:

js
recordExtractor: ({ helpers }) => {
  return helpers.docsearch({
    recordProps: {
      lvl0: {
        selectors: "header h1",
      },
      lvl1: "article h2",
      lvl2: "article h3",
      lvl3: "article h4",
      lvl4: "article h5",
      lvl5: "article h6",
      content: "main p, main li",
      // The variables below can be used to filter your search
      foo: ".bar",
      language: {
        // It also supports the fallback DOM selectors syntax!
        selectors: ".does-not-exists",
        // Since custom variables are used for filtering, we allow sending
        // multiple raw values
        defaultValue: ["en", "en-US"],
      },
      version: {
        // You can send raw values without `selectors`
        defaultValue: ["latest", "stable"],
      },
    },
  });
},

The version, language, and foo attributes are then available in your records:

json
{
  "foo": "valueFromBarSelector",
  "language": ["en", "en-US"],
  "version": ["latest", "stable"]
}

Add every filter attribute to the index's attributesForFaceting, then expose up to five of them with the v5 facets option. If you display one with resultBadgeKey, also add that attribute to attributesToRetrieve; see the resultBadgeKey reference.

V5 result breadcrumbs use the hierarchy.lvl0 through hierarchy.lvl6 values generated from your selectors. Keep the heading levels ordered and include the hierarchy attributes in attributesToRetrieve.

Boost search results with `pageRank`

This parameter allows you to boost records using a custom ranking attribute built from the current pathsToMatch. Pages with highest pageRank will be returned before pages with a lower pageRank. The default value is 0 and you can pass any numeric value as a string, including negative values.

Search results are sorted by weight (desc), so you can have both boosted and non boosted results. The weight of each result will be computed for a given query based on multiple factors: match level, position, etc. and the pageRank value will be added to this final weight. The pageRank on its own may not be enough to influence the results of your query depending on how your overall ranking is set up. If changing the pageRank value doesn't influence your search results enough, even with large values, move weight.pageRank higher in the Ranking and Sorting page for your index.

You can view the computed weight directly from the Algolia dashboard (dashboard.algolia.com->search->perform a search->mouse hover over the "ranking criteria" icon bottom right of each record). That will give you an idea of what pageRank value is acceptable for your case.

js
{
  indexName: "YOUR_INDEX_NAME",
  pathsToMatch: ["https://YOUR_WEBSITE_URL/api/**"],
  recordExtractor: ({ $, helpers, url }) => {
    const isDocPage = /\/[\w-]+\/docs\//.test(url.pathname);
    const isBlogPage = /\/[\w-]+\/blog\//.test(url.pathname);
    return helpers.docsearch({
      recordProps: {
        lvl0: {
          selectors: "header h1",
        },
        lvl1: "article h2",
        lvl2: "article h3",
        lvl3: "article h4",
        lvl4: "article h5",
        lvl5: "article h6",
        content: "article p, article li",
        pageRank: isDocPage ? "-2000" : isBlogPage ? "-1000" : "0",
      },
    });
  },
},

Reduce the number of records

If you encounter the Extractors returned too many records error when your page outputs more than 750 records, the aggregateContent option helps you reduce the number of records at the content level of the extractor.

js
{
  indexName: "YOUR_INDEX_NAME",
  pathsToMatch: ["https://YOUR_WEBSITE_URL/api/**"],
  recordExtractor: ({ $, helpers }) => {
    return helpers.docsearch({
      recordProps: {
        lvl0: {
          selectors: "header h1",
        },
        lvl1: "article h2",
        lvl2: "article h3",
        lvl3: "article h4",
        lvl4: "article h5",
        lvl5: "article h6",
        content: "article p, article li",
      },
      aggregateContent: true,
    });
  },
},

Reduce the record size

If you encounter the Records extracted are too big error, your records or source page might contain too much information. The recordVersion option reduces record size by removing fields used only by the DocSearch v2 UI.

js
{
  indexName: "YOUR_INDEX_NAME",
  pathsToMatch: ["https://YOUR_WEBSITE_URL/api/**"],
  recordExtractor: ({ $, helpers }) => {
    return helpers.docsearch({
      recordProps: {
        lvl0: {
          selectors: "header h1",
        },
        lvl1: "article h2",
        lvl2: "article h3",
        lvl3: "article h4",
        lvl4: "article h5",
        lvl5: "article h6",
        content: "article p, article li",
      },
      recordVersion: "v3",
    });
  },
},

`recordProps` API Reference

`lvl0`

type: Lvl0 | required

ts
type Lvl0 = {
  selectors: string | string[];
  defaultValue?: string;
};

`lvl1`, `content`

type: string | string[] | required

`lvl2`, `lvl3`, `lvl4`, `lvl5`, `lvl6`

type: string | string[] | optional

`pageRank`

type: number | optional

See the live example

Custom variables

type: string | string[] | CustomVariable | optional

ts
type CustomVariable =
  | {
      defaultValue: string | string[];
    }
  | {
      selectors: string | string[];
      defaultValue?: string | string[];
    };

Define custom variables in recordProps. You can use them with v5 facets and per-index filters.

`helpers.docsearch` API Reference

`aggregateContent`

type: boolean | default: true | optional

This option groups the Algolia records created at the content level of the selector into a single record for its matching heading.

`recordVersion`

type: 'v3' | 'v2' | default: v2 | optional

This option selects the crawler record schema. It doesn't select the DocSearch UI package version. Set it to v3 to remove fields used only by the DocSearch v2 UI. The v3 value is also the current record schema for DocSearch v5 frontends.

`indexHeadings`

type: boolean | { from: number, to: number } | default: true | optional

This option tells the crawler if the headings (lvlX) should be indexed.

  • When false, only records for the content level will be created.
  • When from, to is provided, only records for the lvlX to lvlY will be created.

Packages Website Docs Required Configuration (`packages/website/docs/required-configuration.mdx`)


title: Required configuration

Follow these requirements so the crawler can extract structured records from your website. Update your markup and crawler configuration where needed.

:::info

If your website uses one of the supported framework integrations, its generated markup might already meet these requirements. Confirm that the crawler selectors match your framework and version.

:::

Generic configuration example

Start with the default DocSearch configuration template. For more customization options, see complex record extractors.

If you use a framework integration, see the configuration templates.

docsearch-default.js

text
/* Detailed source-code truncated for AI context efficiency. */

recordVersion: 'v3' selects the crawler record schema. It isn't the DocSearch UI version and works with the v5 frontend packages. If you expose lang, language, or version as v5 facets, add those attributes to attributesForFaceting. Keep a badge attribute in attributesToRetrieve when you pass it to resultBadgeKey.

Overview of a clear layout

Use a page layout that separates documentation content from navigation and other page elements:

Use the main blue element as your .DocSearch-content container. Follow the next guidelines to structure its contents.

Use the right classes as [`recordProps`][2]

Add static classes to identify each content role. These classes don't need to change the page's appearance. The crawler uses them to extract structured records.

  • Add a static DocSearch-content class to the main container for your text. This container is usually a <main> or <article> element.

  • Configure every searchable lvl element outside the main documentation container, such as a sidebar item, as a global selector. The crawler adds these elements to every record from the page. Keep levels in increasing order in the document flow: lvlX should follow lvlY when X > Y.

  • Use standard heading elements, such as h1, h2, and h3, for lvlX selectors. You can also use static classes. Add a unique id or name attribute to each matching element.

  • Give every element that matches an lvlX selector a unique id or name attribute. DocSearch uses this anchor to open the page at the matching element.

  • V5 builds result breadcrumbs from the populated hierarchy.lvl0 through hierarchy.lvl6 attributes. Keep heading levels ordered, avoid gaps where possible, and retrieve the full hierarchy object.

  • Wrap every element that matches the recordProps.content selector in a `` or <li> element. Split text into focused blocks, and don't nest matching elements because this creates duplicate records.

  • Keep the content structure consistent throughout the document.

Introduce global information as meta tags

The crawler automatically extracts information from DocSearch-specific meta tags:

html title="index.html"
<meta name="docsearch:language" content="en" />
<meta name="docsearch:version" content="1.0.0" />

The crawler adds the content value of these meta tags to every record extracted from the page. Each tag's name attribute must follow the docsearch:$NAME pattern, where $NAME is the record attribute to set.

The docsearch:version meta tag can be a set of comma-separated tokens, each of which is a version relevant to the page. These tokens must be compliant with the SemVer specification or only contain alphanumeric characters (e.g. latest, next, etc.). As facet filters, these version tokens are case-insensitive.

For example, add the following meta tag to assign two versions to every record on a page:

html title="index.html"
<meta name="docsearch:version" content="2.0.0-alpha.62,latest" />

The crawler adds the following version attribute to each record:

json title="record.json"
{
  "version": ["2.0.0-alpha.62", "latest"]
}

Add these attributes to attributesForFaceting. You can then use them in per-index facetFilters or expose up to five controls with the v5 facets option. To show version in each result, retrieve it and set resultBadgeKey to version.

Nice to have

  • Keep your sitemap up to date so the crawler can identify changed pages. The crawler also discovers eligible links from crawled pages.

  • Ensure that every page provides its full context. Use global elements where appropriate.

  • Make your documentation content available without client-side JavaScript rendering. If your website requires JavaScript rendering, set renderJavaScript: true in your configuration.

Any questions? Connect with us on Discord or support.


Packages Website Docs Styling (`packages/website/docs/styling.md`)


title: Styling DocSearch

Use @docsearch/css to style DocSearch v5.

The package provides a complete stylesheet and separate bundles for the button, keyword modal, Ask AI interface, and sidepanel. See CSS bundles and exports to choose the files for your integration.


Packages Website Docs Templates (`packages/website/docs/templates.mdx`)


title: Config Templates

import useBaseUrl from '@docusaurus/useBaseUrl';

Use these crawler configuration templates as a starting point for supported website generators. To add or update a template, contact us on Discord or open a pull request.

If you want to better understand the default parameters of the configs below, take a look at the Crawler documentation.

Getting started

After approval, the onboarding flow creates a crawler with your URL and Algolia credentials. If it detects one of the listed generators, it can assign the matching template. Otherwise, it applies the default template.

These templates configure indexing, not the installed DocSearch frontend package. In a template, recordVersion: 'v3' means the crawler's v3 record schema; it doesn't mean DocSearch UI v3.

For v5 facets, add each custom filter attribute to attributesForFaceting and expose no more than five keys in the frontend. For resultBadgeKey, add the selected property to attributesToRetrieve. Keep hierarchy.lvl0 through hierarchy.lvl6 populated and retrievable so v5 can render result breadcrumbs. See the v5 JavaScript API reference.

Update a template

You can manually update the crawler template by going to dashboard.algolia.com, click "Data sources", select your crawler, and go to the editor page. From there you can edit the JavaScript directly. Note that you can make draft changes without saving, test the changes using the "URL Tester", and then "Save" once you're happy with your changes.

Default template

default.js

text
/* Detailed source-code truncated for AI context efficiency. */

Docusaurus v1 template

docusaurus-v1.js

text
/* Detailed source-code truncated for AI context efficiency. */

Docusaurus v2 and later template

docusaurus-v2.js

text
/* Detailed source-code truncated for AI context efficiency. */

Astro Starlight Template

starlight.js

text
/* Detailed source-code truncated for AI context efficiency. */

Vuepress v1 Template

vuepress-v1.js

text
/* Detailed source-code truncated for AI context efficiency. */

Vuepress v2 Template

vuepress-v2.js

text
/* Detailed source-code truncated for AI context efficiency. */

Vitepress Template

vitepress.js

text
/* Detailed source-code truncated for AI context efficiency. */

Rspress Template

rspress.js

text
/* Detailed source-code truncated for AI context efficiency. */

pkgdown Template

pkgdown.js

text
/* Detailed source-code truncated for AI context efficiency. */

Packages Website Docs Tips (`packages/website/docs/tips.md`)


DocSearch works with many website structures, but consistent structure can improve relevance and indexing time. Follow these recommendations to improve your DocSearch results.

Use a `sitemap.xml`

If you provide a sitemap in your crawler configuration, DocSearch uses it to find pages to index. The crawler also follows eligible links on those pages.

Add a sitemap.xml to your website if you don't have one. A sitemap can reduce indexing time and gives you more control over which pages are indexed.

Sitemaps can also improve search engine optimization. For more information, see the sitemaps specification.

Structure the hierarchy of information

DocSearch works better on structured documentation. Result relevance uses the structural hierarchy of your content. The crawler reads the <h1> through <h6> headings or equivalent selectors to build hierarchy.lvl0 through hierarchy.lvl6.

Documentation usually introduces general concepts before covering details. Represent this structure with an ordered heading hierarchy. For example, content under an <h4> is more specific than content under an <h2> on the same page. Content that appears earlier on the page ranks higher.

DocSearch uses this structure to improve relevance. V5 also uses the populated hierarchy levels to render result breadcrumbs. Keep headings in order and avoid skipping levels where possible so each result retains its page context.

Choose a documentation depth that gives each result enough context. For large pages, use four levels, from lvl0 to lvl3. Use at least three levels.

You can use classes, such as ``, instead of <hX> elements.

Set a unique class to the element holding the content

DocSearch extracts content based on the HTML structure. We recommend that you add a custom class to the HTML element wrapping all your textual content. This will help narrow selectors to the relevant content.

A unique identifier makes your configuration more robust and limits indexing to relevant content. Use it to exclude unrelated headers, sidebars, and footers.

Add anchors to headings

Add a custom anchor to each heading. Define anchors with an id or name HTML attribute so browsers can scroll directly to the corresponding position. Links can target an anchor with # followed by its value.

DocSearch uses these anchors to send users to the location of the selected result.

Mark active pages in the navigation

If you use multi-level navigation, mark each active level with a custom CSS class. The crawler can use this class to determine where the current page fits in the website hierarchy.

For example, if your troubleshooting.html page is located under the "Installation" menu in your sidebar, we recommend that you add a custom CSS class to the "Installation" and "Troubleshooting" links in your sidebar.

Use any valid CSS class name that can be part of a CSS selector.

Consistency of your content

Use the same heading structure across documentation pages. Make each page topic and outline clear, and avoid selectors that create records without enough context, such as standalone introductions or asides.

Write selectors that match documentation pages but exclude landing pages, tables of contents, and other unrelated content. Add a dedicated class, such as .DocSearch-content, to the main documentation container.

Use consistent terms for the same concepts. You can also configure synonyms for terms your users search interchangeably.

Avoid duplicate content

Split broad topics into focused pages. Avoid catch-all pages that make it difficult to identify the relevant result.

Duplicate content adds noise and can mislead users. Don't repeat all documentation content on a landing or summary page. If you need duplicate records for separate datasets, such as different versions, use facets to distinguish them.

Index metadata for v5

Add each attribute used by the v5 facets option to attributesForFaceting. DocSearch supports up to five facet controls. For a result badge, index a short value such as version, include it in attributesToRetrieve, and pass its property path to resultBadgeKey. See the v5 JavaScript API reference.

Conciseness

Keep content focused on one task or concept, and use short headings and paragraphs.

For more guidance, read How to build a helpful search for technical documentation.


Packages Website Docs V5 Breaking Changes (`packages/website/docs/v5-breaking-changes.mdx`)


title: v5 breaking changes

This page lists the user-facing changes between the v4.6.0 package source and 5. Use it with the v4 migration guide.

JavaScript entry points

The root export is AI-capable

In v4, the root @docsearch/js export rendered the combined component and allowed Ask AI to be omitted. In v5, it renders DocSearchAI, and its DocSearchProps type requires askAi.

Use the root entry when you configure Agent Studio:

js title="app.js"
import docsearch from '@docsearch/js';

Keyword-only search moved to `/docsearch`

Use the new subpath when you don't need Ask AI:

js title="app.js"
import docsearch from '@docsearch/js/docsearch';

This entry excludes Ask AI code.

The UMD bundle is split

  • dist/umd/index.js includes keyword search and Ask AI.
  • dist/umd/docsearch.js includes keyword search only.
  • Both bundles expose window.docsearch.
  • Loading both bundles causes the later script to replace the same global.

An exports map restricts JavaScript imports

@docsearch/js now exports only . and ./docsearch. Replace imports of internal distribution files with one of these public entry points. Direct CDN URLs to the two documented UMD files remain supported by the package layout.

React components

`DocSearch` is keyword-only

V4's DocSearch accepted askAi and interceptAskAiEvent. V5's DocSearch contains keyword search only and no longer declares those props.

`DocSearchAI` owns the AI experience

Use DocSearchAI for keyword search and Ask AI:

jsx title="search.jsx"
import { DocSearchAI } from '@docsearch/react';

DocSearchAIProps extends DocSearchProps, requires askAi, and adds interceptAskAiEvent.

The package also adds @docsearch/react/docsearchAi and @docsearch/react/askaiModal subpaths.

The Ask AI modal is separate

DocSearchModal is keyword-only. DocSearchAskAiModal contains the combined keyword and AI modal. Composable integrations that rendered DocSearchModal with askAi must switch to DocSearchAskAiModal and its required provider callbacks. Review the Composable API instead of constructing these props without the provider.

@docsearch/modal exports the AI modal from its root and from @docsearch/modal/askai.

Ask AI and Agent Studio

The legacy transport is removed

V5 no longer requests a legacy Ask AI token or sends chat requests to the v4 Ask AI endpoint. All Ask AI conversations use the Agent Studio completions endpoint.

Create and configure an assistant in Agent Studio before upgrading.

`askAi.agentStudio` is removed

The backend switch is no longer needed because Agent Studio is the only backend. Remove both agentStudio: true and agentStudio: false.

Flat Ask AI search parameters are removed

DocSearchAskAi.searchParameters now always uses AgentStudioSearchParameters: an object keyed by index name.

js title="app.js"
searchParameters: {
  docs: {
    filters: 'language:en',
    attributesToRetrieve: ['title', 'content', 'url'],
    distinct: true,
  },
}

Each value supports filters, attributesToRetrieve, restrictSearchableAttributes, and distinct. The Agent Studio type omits facetFilters.

Agent Studio credentials are sent directly

Ask AI requests use the configured application ID and API key in x-algolia-application-id and x-algolia-api-key headers. Memory authentication adds x-algolia-secure-user-token. Check the permissions and domain restrictions of keys that were issued for the legacy transport.

Feedback uses Agent Studio

Feedback now posts to Agent Studio and supports negative-feedback reason tags and notes. Stored conversation messages can contain feedbackTags and feedbackNotes in addition to the like or dislike value.

Agent Studio configuration is nested under `askAi`

Dynamic indices, custom tools, memory, and keyword promptSuggestions belong inside the askAi object. interceptAskAiEvent remains a top-level integration callback.

Suggested questions have two sources

  • askAi.suggestedQuestions determines whether DocSearch loads published questions for the assistant from algolia_ask_ai_suggested_questions on the new-conversation screen.
  • askAi.promptSuggestions searches a configured index containing a prompt attribute and displays those prompts with keyword results.

These options aren't interchangeable.

Search configuration

The Docusaurus adapter configuration changed

The v5 adapter reads themeConfig.docsearch and rejects the former themeConfig.algolia key. It also requires indices and rejects indexName and root searchParameters.

Replace searchPagePath with searchPage. Move askAi.sidePanel to the root sidePanel option. Remove legacy Ask AI credentials and the askAi.agentStudio switch. Follow Migrate the Docusaurus adapter from v4 for before-and-after configurations.

Multiple indices share one result flow

V5 creates one source for each index response and combines hit totals across responses. Result order follows the normalized index order. Review code that assumes one index or source identifier.

New keyword search behavior

Facets add requests and filters

The new facets option fetches facet values with a zero-hit query for every configured index. DocSearch merges and sorts values, supports at most five keys after trimmed, lowercase duplicate checks, and displays only facets with values.

A selected value is appended to that index's existing facetFilters. Account for the additional facet-value request in analytics, rate estimates, and search-client mocks.

Result badges require retrieved attributes

The new resultBadgeKey reads a property path from each hit. The default attributesToRetrieve list doesn't include custom badge properties. Add them to each relevant index's searchParameters.attributesToRetrieve.

Result markup and grouping changed

V5 refreshes the modal and result markup, renders breadcrumbs, introduces source panels, and adds facet and badge elements. CSS selectors, DOM tests, snapshots, and custom overrides that target v4 internals can break.

Use public component props for behavior and review Styling for visual changes.

Styles and builds

Ask AI styles have a separate source bundle

The complete @docsearch/css stylesheet still imports button, modal, and Ask AI rules. React also exposes split style entries:

  • @docsearch/react/style/variables
  • @docsearch/react/style/button
  • @docsearch/react/style/modal
  • @docsearch/react/style/askai
  • @docsearch/react/style/sidepanel

If you assemble styles by component, add style/askai for DocSearchAI or DocSearchAskAiModal.

Generated React file names changed

The documented package subpaths remain stable, but their targets changed from names such as dist/esm/DocSearchModal.js to generated entry files such as dist/esm/modal.js. Imports that bypassed the package exports can break.

The React `main` field now points to ESM

@docsearch/react changes main from dist/umd/index.js to dist/esm/index.js. Consumers that resolve main instead of the package exports need an ESM-compatible build pipeline. The explicit unpkg and jsdelivr fields continue to point to dist/umd/index.js.

The browser target is ES2017

V5's tsdown builds target ES2017. Provide transpilation or polyfills if your browser support policy extends below that target.

Public controls

JavaScript instances don't expose Sidepanel state

DocSearchInstance exposes open, close, openAskAi, destroy, isReady, and isOpen. It doesn't expose openSidepanel, isSidepanelOpen, or isSidepanelSupported.

React refs include Sidepanel controls

DocSearchRef exposes the JavaScript-style modal controls plus openSidepanel, isSidepanelOpen, and isSidepanelSupported. openSidepanel does nothing until a Sidepanel view registers. On mobile, openAskAi and standard Ask AI actions fall back to the modal.

See hybrid mode for the supported integration.

Deprecated keyboard hook fields remain

UseDocSearchKeyboardEventsProps.onInput and searchButtonRef are accepted for compatibility but are deprecated and aren't used by the v5 React hook implementation.

Compatibility

React peer range

@docsearch/react, @docsearch/core, @docsearch/modal, and @docsearch/sidepanel declare these optional peers:

  • react: >=16.8.0 <20.0.0
  • react-dom: >=16.8.0 <20.0.0
  • @types/react: >=16.8.0 <20.0.0

@docsearch/react also accepts optional search-insights versions >=1 <3.

Package versions must match

The v5 packages depend on matching versions of the other DocSearch packages. Don't mix v4 and v5 packages in a Composable API or Sidepanel tree.

CSS remains a separate install for top-level integrations

Install @docsearch/css@^5, then import @docsearch/css. For a CDN integration, load @docsearch/css/dist/style.css.

Additive v5 APIs

These additions aren't breaking by themselves, but they replace common v4 custom implementations:

  • facets and DocSearchFacet for keyword filters.
  • resultBadgeKey for hit metadata.
  • DocSearchAI and DocSearchAskAiModal for AI-capable React views.
  • askAi.indices (string[]) for dynamic Agent Studio search indices.
  • askAi.searchParameters for per-index runtime search overrides.
  • ToolCalls and ToolDefinition for custom Agent Studio tools.
  • Memory for user-scoped Agent Studio memory.
  • PromptSuggestions for keyword-query prompt suggestions.
  • Ask AI feedback tags and notes.
  • Split JavaScript, React, and style entries for smaller keyword-only builds.

Packages Website Docs What Is Docsearch (`packages/website/docs/what-is-docsearch.md`)


title: What is DocSearch? sidebar_label: What is DocSearch?

Why?

We created DocSearch because developers spend a lot of time reading documentation, and finding relevant information in large documentation sites can be difficult. Building good search is a challenge.

Algolia has extensive experience building search interfaces. We use that experience to extract content from technical documentation and make it searchable from the first keystroke.

Overview

DocSearch has two independent parts: indexing and the frontend search experience.

Crawler configuration and record schema versions don't select the installed DocSearch frontend package version. You can update the frontend package without changing how the crawler is scheduled.

How to feature DocSearch?

DocSearch is free for eligible documentation sites. Read the eligibility requirements and apply. After approval and indexing, add a DocSearch v5 package or a supported framework integration to your website. Keep the "Search by Algolia" link displayed.

DocSearch is one of our ways to give back to the open source community for everything it did for us already.

You can now apply to the program


Packages Website Docs Who Can Apply (`packages/website/docs/who-can-apply.md`)


title: Who can apply?

Open to developer documentation and technical blogs.

We built DocSearch to improve search on large technical documentation sites. We offer the free DocSearch program to public technical documentation and technical blogs.

We usually turn down applications when they are not production ready or have non-technical content on the website.

Application process

To apply to the DocSearch program, follow the onboarding process in the Algolia dashboard. Submit your domain for validation against the program requirements. If your domain meets the criteria, you can create your DocSearch crawler.

Process duration

The application process includes automated validation. If we can't determine your eligibility automatically, we'll conduct a manual review that may take one to two business days.

Once approved, continue the onboarding process to create your DocSearch crawler. After the crawler indexes your data, choose the frontend package or framework integration separately. Updating the frontend doesn't change your crawler or index format.


Packages Website Docs Agent Studio Dynamic Indices (`packages/website/docs/agent-studio/dynamic-indices.mdx`)


title: Configure dynamic indices

Pass askAi.indices when Agent Studio should search a specific set of indices for this request. This lets each DocSearch instance choose which indices the agent can use.

This property isn't the same as the top-level indices property:

  • Top-level indices configures DocSearch keyword search. Entries are index names or objects with a name property.
  • askAi.indices configures Agent Studio search. Entries are index name strings.

Agent Studio completions accept index names only. Put index descriptions and tool defaults on the agent configuration in Agent Studio. Put per-index runtime overrides in askAi.searchParameters.

The agent's Algolia Search tool must use mode: "dynamic". If the tool's static index list is empty, also enable allowUnlistedIndices.

Select indices

tsx title="search.tsx"
<DocSearchAI
  appId="YOUR_APPLICATION_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['docs']}
  askAi={{
    agentId: 'YOUR_AGENT_ID',
    indices: ['docs_markdown', 'api_reference'],
    searchParameters: {
      docs_markdown: {
        filters: 'visibility:public',
        attributesToRetrieve: ['title', 'content', 'url'],
      },
      api_reference: {
        distinct: false,
      },
    },
  }}
/>

`indices`

type: string[] | optional

Index names available to the Agent Studio search tool for this request. When omitted, Agent Studio uses the indices configured on the agent tool.

Set request-wide search parameters

askAi.searchParameters is keyed by index name:

js title="docsearch.js"
askAi: {
  agentId: 'YOUR_AGENT_ID',
  indices: ['docs_markdown'],
  searchParameters: {
    docs_markdown: {
      filters: 'visibility:public',
      attributesToRetrieve: ['title', 'content', 'url'],
      distinct: false,
    },
  },
}

Supported override fields are filters, attributesToRetrieve, restrictSearchableAttributes, distinct, userToken, enablePersonalization, personalizationImpact, and optionalFilters.

Don't use the flat search-parameter shape from earlier DocSearch AI integrations.

Docusaurus validation

The v5 Docusaurus adapter requires at least one string when you set askAi.indices. Contextual search merges version/language filters into askAi.searchParameters[index].filters for each dynamic index name.

See the React package reference and Docusaurus adapter guide for the complete types.


Packages Website Docs Agent Studio Feedback (`packages/website/docs/agent-studio/feedback.mdx`)


title: Collect response feedback

DocSearch v5 includes feedback controls for completed Agent Studio answers. You don't need to add an askAi option to enable them.

Use an API key with the search ACL. Agent Studio accepts one vote per message. See Agent Studio feedback for service requirements and reporting details.

Understand the ratings

Thumbs up submits positive feedback immediately:

ts
{
  thumbs: 1;
}

Thumbs down opens a form before submission. A user can select zero or more reason tags and add an optional note:

ts
{
  thumbs: 0;
  tags?: AskAiFeedbackReason[];
  notes?: string;
}

Closing or canceling the form doesn't submit feedback. Submitting without a reason or note is valid. DocSearch trims notes, omits an empty note, and limits notes to 1,000 characters.

DocSearch supports these reason values:

Value Default label
incorrect Incorrect or incomplete
not_what_i_asked Not what I asked for
slow_or_buggy Slow or buggy
style_or_tone Style or tone
safety_or_legal Safety or legal concern
other Other

Reason tags and notes are collected only for negative feedback.

Understand submission behavior

DocSearch sends the Agent Studio agent ID, message ID, vote, and optional negative-feedback details to Agent Studio. After a successful request, it shows a thank-you state and records the rating with the locally stored conversation.

If submission fails, DocSearch keeps the negative-feedback form open and displays the error so the user can retry.

Change feedback labels

Override feedback text through translations.modal.askAiScreen:

tsx title="search.tsx"
<DocSearchAI
  appId="YOUR_APPLICATION_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['docs']}
  askAi={{ agentId: 'YOUR_AGENT_ID' }}
  translations={{
    modal: {
      askAiScreen: {
        likeButtonTitle: 'Helpful',
        dislikeButtonTitle: 'Not helpful',
        thanksForFeedbackText: 'Feedback received',
        feedbackPanelTitle: 'Tell us what went wrong',
        feedbackDetailsPlaceholder: 'Add details',
        feedbackSubmitButtonText: 'Send feedback',
        feedbackTagIncorrect: 'Incorrect or incomplete',
        feedbackTagNotWhatIAsked: 'Not what I asked for',
        feedbackTagSlowOrBuggy: 'Slow or buggy',
        feedbackTagStyleOrTone: 'Style or tone',
        feedbackTagSafetyOrLegal: 'Safety or legal concern',
        feedbackTagOther: 'Other',
      },
    },
  }}
/>

See the React package reference for all feedback translation keys and the exported feedback types.


Packages Website Docs Agent Studio Memory (`packages/website/docs/agent-studio/memory.mdx`)


title: Add user-scoped memory

Agent Studio memory lets an agent retain useful context for a user across conversations. Configure memory in Agent Studio first, then give DocSearch a secure user token so Agent Studio can isolate each user's data.

Read the Agent Studio memory overview before enabling memory in production.

Generate a secure user token

Generate the JWT on your backend after authenticating the user. Follow the Agent Studio user authentication guide for the required claims, signing algorithm, and key ID.

Protect the token flow:

  • Never generate the token in browser code.
  • Never expose the Algolia secret key used to sign it.
  • Use a stable, non-sensitive user identifier in the JWT sub claim.
  • Set an expiration and refresh expired tokens.
  • Serve the token only over HTTPS.
  • Don't put sensitive user data in JWT claims. JWT payloads aren't encrypted.

Pass the token to DocSearch

Fetch a token from your backend and pass it as memory.userToken:

js title="load-docsearch.js"
const response = await fetch('/api/agent-studio-token', {
  credentials: 'include',
});
const { userToken } = await response.json();

docsearch({
  container: '#docsearch',
  appId: 'YOUR_APPLICATION_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  indices: ['docs'],
  askAi: {
    agentId: 'YOUR_AGENT_ID',
    memory: {
      enabled: true,
      userToken,
    },
  },
});

Use the same askAi.memory object with React's DocSearchAI.

When userToken is present, DocSearch sends it in the X-Algolia-Secure-User-Token request header. When it's absent, DocSearch omits the header. Don't use unscoped memory for a multi-user application.

`memory.enabled`

type: boolean | optional

Controls whether DocSearch displays Agent Studio's built-in memory tool activity:

  • algolia_memorize displays that information was saved.
  • algolia_ponder and algolia_memory_search display that memory was used.
  • Memory tool errors aren't displayed.

The default is false.

This option doesn't enable memory in Agent Studio and doesn't create a user identity. Configure the feature on the agent and pass userToken for user isolation. DocSearch sends userToken when provided even if enabled is false.

A custom entry in askAi.tools with the same memory tool name replaces the built-in memory rendering.

See the JavaScript package reference or React package reference for the Memory configuration type.


Packages Website Docs Agent Studio Migrate To Agent Studio (`packages/website/docs/agent-studio/migrate-to-agent-studio.mdx`)


title: Migrate Ask AI to Agent Studio

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

Ask AI is now part of Agent Studio. Migrate your existing Ask AI assistant, publish the new agent, then point DocSearch at the agent ID.

DocSearch v5 uses Agent Studio as its only AI backend. There's no agentStudio flag.

If you're still on DocSearch v4, follow the v4 migration guide. To upgrade packages at the same time, see Migrate from DocSearch v4.

Migrate your assistant

1. Start the migration in the dashboard

  1. Sign in to the Algolia dashboard.
  2. Open Ask AI.
  3. Select your assistant and click Migrate to Agent Studio.

The wizard creates a draft Agent Studio agent from your assistant configuration, including the prompt, model, indices, and related settings. After migration, the assistant and agent are independent and don't stay in sync.

2. Review and publish the agent

  1. Open Agents in Agent Studio.
  2. Review the migrated agent.
  3. Publish the agent when you're ready to go live.

Copy the agent ID. DocSearch calls this value agentId in its public API.

3. Update your integration

Choose the path that matches how you embed Ask AI today:

Your existing Ask AI assistant keeps serving traffic until Ask AI is fully retired. Switch your client to the Agent Studio agent when you're ready.

Update DocSearch v5

Pass the Agent Studio agent ID as askAi.agentId, or as the askAi string shorthand. Rename any assistantId field to agentId.

Use DocSearchAI. Keyword-only DocSearch doesn't accept askAi.

tsx title="search.tsx"
import { DocSearchAI } from '@docsearch/react';
import '@docsearch/css';

export function Search() {
  return (
    <DocSearchAI
      appId="YOUR_APPLICATION_ID"
      apiKey="YOUR_SEARCH_API_KEY"
      indices={['YOUR_DOCSEARCH_INDEX']}
      askAi={{
        agentId: 'YOUR_AGENT_ID',
      }}
    />
  );
}

The string shorthand remains supported:

tsx title="search.tsx"
<DocSearchAI
  appId="YOUR_APPLICATION_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['YOUR_DOCSEARCH_INDEX']}
  askAi="YOUR_AGENT_ID"
/>

Keep the root @docsearch/js import. It renders the AI-capable component:

js title="load-docsearch.js"
import docsearch from '@docsearch/js';
import '@docsearch/css';

docsearch({
  container: '#docsearch',
  appId: 'YOUR_APPLICATION_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  indices: ['YOUR_DOCSEARCH_INDEX'],
  askAi: {
    agentId: 'YOUR_AGENT_ID',
  },
});

Update `searchParameters`

Agent Studio search parameters are keyed by index name. Move any flat Ask AI searchParameters under the index:

diff title="app.js"
askAi: {
-  assistantId: 'YOUR_ASSISTANT_ID',
+  agentId: 'YOUR_AGENT_ID',
   searchParameters: {
-    filters: 'language:en',
-    attributesToRetrieve: ['title', 'content', 'url'],
+    docs: {
+      filters: 'language:en',
+      attributesToRetrieve: ['title', 'content', 'url'],
+    },
   },
 }

Supported keys are filters, attributesToRetrieve, restrictSearchableAttributes, and distinct. Don't put facetFilters in this object. Put fixed facet conditions in filters. For per-request index selection, see dynamic indices.

Docusaurus adapter

The adapter requires themeConfig.docsearch.askAi as an object with agentId. It rejects the string shorthand and the removed agentStudio property. See the Docusaurus adapter guide.

Custom Ask AI API integrations

If you call the Ask AI HTTP API yourself instead of using DocSearch, configure your client for Agent Studio instead of https://askai.algolia.com.

Don't build new integrations against the Ask AI chat API. Use the Agent Studio APIs:

Authenticate with your application ID and a search-only API key. Prefer the DocSearch configuration above when you embed DocSearch—the SDK wires the Agent Studio transport for you.

Next steps

After the agent ID is live in DocSearch:


Packages Website Docs Agent Studio Prompt Suggestions (`packages/website/docs/agent-studio/prompt-suggestions.mdx`)


title: Configure prompt suggestions

DocSearch v5 can show questions in three places. Each source has a different purpose and configuration.

  • Suggested questions appear on the new-conversation screen. They come from published records for the agent in the fixed suggested-questions index. Configure them with suggestedQuestions: true.
  • Keyword prompt suggestions appear while the user types in keyword search. They come from your Algolia prompt-suggestions index. Configure them with promptSuggestions.
  • Streamed follow-ups appear below the latest completed answer. They come from data-suggestions streamed by Agent Studio. Configure suggestions on the agent.

Show suggested questions

Enable curated starting questions with suggestedQuestions:

js title="docsearch.js"
askAi: {
  agentId: 'YOUR_AGENT_ID',
  suggestedQuestions: true,
}

DocSearch queries the algolia_ask_ai_suggested_questions index for records where state is published and assistantId matches the configured agent. It requests up to three records.

A suggested-question record has this shape, plus its Algolia objectID:

ts
{
  appId: string;
  assistantId: string;
  question: string;
  locale?: string;
  state: 'published';
  source: string;
  order: number;
}

When a user selects one, DocSearch sends its objectID as suggestedQuestionId with the question.

Create an Algolia index whose records contain a prompt string, then configure its name:

js title="docsearch.js"
askAi: {
  agentId: 'YOUR_AGENT_ID',
  promptSuggestions: {
    indexName: 'docs_prompt_suggestions',
    hitsPerPage: 3,
  },
}

As the user types, DocSearch searches this index with the entered query and retrieves only the prompt attribute. It places matching prompts after the action that asks the entered text directly.

hitsPerPage defaults to 3. The Docusaurus adapter requires a positive value. If this search fails, DocSearch keeps the direct Ask AI action and omits the suggestions.

Selecting a prompt starts Agent Studio with that prompt. It doesn't send a suggestedQuestionId.

Show streamed follow-ups

Configure contextual suggestions in the Agent Studio agent editor. See write and configure agent prompts.

Agent Studio streams these follow-ups in a data-suggestions part. DocSearch renders its suggestions array below the latest answer only. Selecting one sends it as the next user message in the same conversation.

There's no DocSearch askAi option for streamed follow-ups. If Agent Studio doesn't stream data-suggestions, DocSearch doesn't show them.

See the JavaScript package reference and React package reference for the suggestion options and translation keys.


Packages Website Docs Agent Studio Tools (`packages/website/docs/agent-studio/tools.mdx`)


title: Add tools

Use tools to let your agent read live data or perform actions. Configure the tool and its input schema in Agent Studio, then add a matching entry to askAi.tools when DocSearch needs to run or render it.

See Agent Studio tools before exposing a tool to users.

Add a client-side tool

The key in tools must match the tool name configured in Agent Studio.

tsx title="search.tsx"
import { DocSearchAI, type ToolCalls } from '@docsearch/react';

const tools: ToolCalls = {
  getAccountPlan: {
    translations: {
      callingToolText: 'Checking your account',
    },
    render({ message: { input, output } }) {
      const result = output as { plan?: string } | undefined;
      return result?.plan ? `Account plan: ${result.plan}` : '';
    },
    async onToolCall({ input, addToolOutput }) {
      const response = await fetch('/api/account-plan', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify(input),
      });

      const output = await response.json();
      await addToolOutput({ output });
    },
  },
};

export function Search() {
  return (
    <DocSearchAI
      appId="YOUR_APPLICATION_ID"
      apiKey="YOUR_SEARCH_API_KEY"
      indices={['docs']}
      askAi={{
        agentId: 'YOUR_AGENT_ID',
        tools,
      }}
    />
  );
}

The JavaScript package accepts the same askAi.tools object.

Every tool definition requires render. DocSearch calls it after output is available and passes both input and output. Return a string to show a result, or an empty string to show nothing.

Add onToolCall for a tool that runs in the browser. It receives:

  • input: the arguments selected by the agent. Treat this value as untrusted and validate it.
  • toolCallId: the current call ID.
  • toolName: the configured tool name.
  • dynamic: whether the streamed call was marked as dynamic, when provided.
  • addToolOutput: the function that returns the result to the conversation.

Call addToolOutput({ output }) after your work finishes. DocSearch invokes onToolCall without waiting for its returned promise, so handle failures inside the callback.

Keep browser tools within the signed-in user's permissions. Don't place service credentials in the tool definition. Call your backend for privileged work. See client-side tool security.

For React, define tools outside the component or memoize it. Recreating the object doesn't change behavior, but a stable object avoids rebuilding dependent configuration.

Render server-side or MCP tools

If Agent Studio executes a tool, omit onToolCall and provide render under the streamed tool name. DocSearch uses the output returned by Agent Studio.

js title="tools.js"
const tools = {
  get_release_status: {
    render({ message: { output } }) {
      const status = output?.status;
      return status ? `Release status: ${status}` : '';
    },
  },
};

Understand Algolia MCP search tools

DocSearch recognizes these Agent Studio search tool names without a tools entry:

  • algolia_search_index
  • Any name beginning with algolia_search_index_

The recognized input includes query, index, optional number_of_results, and optional facet_filters. The output can include hits, nbHits, and queryId.

DocSearch shows search progress and the query used by the tool. It combines consecutive completed search calls into one search summary when more than one call has a nonempty query. A non-search message part ends the group.

You can add a matching tools entry to replace the built-in rendering for a search or memory tool. Your custom renderer takes precedence.

To connect other MCP servers to an agent, see MCP tools in Agent Studio. See the React package reference for ToolCalls and ToolDefinition.

Use tools with Docusaurus

Docusaurus removes functions while serializing theme configuration. The v5 adapter rejects askAi.tools and sidePanel.tools in docusaurus.config. Swizzle @theme/SearchBar and pass tools to the modal or Sidepanel from React instead.

See the Docusaurus adapter guide for the supported configuration.


Packages Website Docs Mcp Installation (`packages/website/docs/mcp/installation.mdx`)


title: Install DocSearch MCP sidebar_label: Installation

import MCPInstall from '@site/src/components/mcp/MCPInstall';
import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

DocSearch MCP is a remote MCP server. Point any MCP-compatible client at this endpoint — no authentication required:

text
https://mcp.algolia.com/1/docsearch/mcp

The fastest path to getting started is the DocSearch CLI — one command that configures your client for you. Prefer to set things up yourself? Install it as a plugin (ships the MCP server plus client guidance like rules, skills, and commands) or manually (just the MCP server config). Pick your client below.

Install a client plugin

Plugins include the MCP connection and instructions that teach the client when and how to use DocSearch.

Claude Code

Run these commands inside Claude Code:

text
/plugin marketplace add algolia/docsearch
/plugin install algolia-docsearch@algolia-docsearch-marketplace

The plugin adds the MCP server, a skill, and the /algolia-docsearch:docs command.

Cursor

The Cursor plugin package is in the DocSearch repository at:

text
mcp/plugins/docsearch/cursor/algolia-docsearch

It includes the MCP server configuration, a rule, and a skill.

Configure a supported agent manually

Manual configuration adds the server but doesn't install the rules and skills supplied by the CLI or plugins.

Add this entry to ~/.cursor/mcp.json for user-level configuration or .cursor/mcp.json for project configuration:

json title=".cursor/mcp.json"
{
  "mcpServers": {
    "algolia-docsearch": {
      "url": "https://mcp.algolia.com/1/docsearch/mcp"
    }
  }
}

Add the user-level remote server with the Claude Code CLI:

sh
claude mcp add --scope user --transport http algolia-docsearch https://mcp.algolia.com/1/docsearch/mcp

Add the remote server with the Codex CLI:

sh
codex mcp add algolia-docsearch --url https://mcp.algolia.com/1/docsearch/mcp

You can also add the URL under [mcp_servers.algolia-docsearch] in ~/.codex/config.toml.

Add this entry to opencode.json or opencode.jsonc:

json title="opencode.json"
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "algolia-docsearch": {
      "type": "remote",
      "url": "https://mcp.algolia.com/1/docsearch/mcp",
      "enabled": true
    }
  }
}

Add this entry to .gemini/settings.json for project configuration or ~/.gemini/settings.json for user-level configuration:

json title=".gemini/settings.json"
{
  "mcpServers": {
    "algolia-docsearch": {
      "httpUrl": "https://mcp.algolia.com/1/docsearch/mcp"
    }
  }
}

Connect another MCP client

You can also connect clients that support remote HTTP MCP servers. Use these connection methods:

  • Claude Desktop: Add a custom connector named Algolia DocSearch with the endpoint URL.
  • ChatGPT: Add a no-auth custom connector. Availability depends on the plan and workspace settings.
  • Pi: Install an MCP extension or adapter before adding the server.
  • VS Code: Add a remote server to the workspace or user MCP configuration. The tools are available in Copilot Chat agent mode.
  • Windsurf: Add the endpoint to the Cascade MCP configuration, then restart Windsurf.
  • Zed: Add the endpoint as a context server.
  • Conductor: Configure the server in the selected Claude Code, Codex, or Cursor host. Conductor doesn't use a separate MCP configuration for those sessions.
  • Antigravity: Add the endpoint through Manage MCP Servers > View raw config, then refresh the installed servers.

Configuration keys differ by client. Follow the client's MCP documentation and keep the server name algolia-docsearch and the endpoint URL unchanged.

Verify the installation

Ask your client to search public documentation:

text
Use DocSearch MCP to find the Next.js middleware matcher documentation.

Confirm that the client calls a tool whose name starts with algolia_docsearch_ and returns source links from the selected documentation.

If verification fails, see Troubleshooting.


Packages Website Docs Mcp Usage (`packages/website/docs/mcp/usage.mdx`)


title: Use DocSearch MCP sidebar_label: Usage

Ask focused questions about public documentation. Include the official product name, topic, and version when the version affects the answer.

text
How do I configure middleware matchers in Next.js?
text
Show me the Stripe webhook signature verification documentation.
text
What is the setup for Algolia InstantSearch React?

If your client doesn't select MCP tools on its own, name the server in your request:

text
Use DocSearch MCP to look up React Server Components data fetching.

Ask the client to include source URLs when you need to inspect the supporting documentation.

Use the Claude Code command

The Claude Code plugin provides this command:

text
/algolia-docsearch:docs <library-or-product> [topic]

For example:

text
/algolia-docsearch:docs Next.js middleware matcher
/algolia-docsearch:docs Stripe webhook signature verification
/algolia-docsearch:docs Algolia InstantSearch React configure search client

Search from the terminal

@docsearch/cli can call the hosted MCP tools without a separate MCP client. Use docs for most questions:

sh
docsearch docs Next.js "how do middleware matchers work"

Limit the number of results or documentation sets when needed:

sh
docsearch docs Next.js "cache revalidation" --max-results 3 --max-docsets 2

For explicit documentation-set selection, resolve a product and then query its returned ID:

sh
docsearch resolve "Algolia InstantSearch React"
docsearch query repo/algolia/instantsearch "configure the React search client"

Limit resolver candidates with --top-n:

sh
docsearch resolve Next.js --top-n 3

Add --json to print the raw MCP result as JSON:

sh
docsearch docs Next.js "cache revalidation" --json

Machine-readable results go to standard output. Progress and errors go to standard error.

Choose a tool workflow

DocSearch MCP provides a one-shot search and a two-step search. Use natural-language questions rather than lists of keywords.

Search in one call

Use algolia_docsearch_search_docs for most questions. Keep the product name in library and the question in query:

json
{
  "library": "Next.js",
  "query": "how do middleware matchers work"
}

The tool resolves the best documentation set and returns ranked content. If library doesn't identify a clear match, it returns candidate sets instead of searching the wrong one.

Resolve and query documentation sets

Use the two-step workflow when the product is ambiguous, you want to inspect the candidates, or the question covers multiple products.

  1. Call algolia_docsearch_resolve_docset with the product or platform name:

    json
    {
      "query": "Next.js app router"
    }
  2. Select the best docset_id from the response.

  3. Call algolia_docsearch_query_docs with the selected ID and a focused question:

    json
    {
      "query": "middleware matcher configuration",
      "docsetIds": ["nextjs"]
    }

Pass more than one docsetIds value when the question covers multiple products. Don't guess IDs. Use only IDs returned by algolia_docsearch_resolve_docset or algolia_docsearch_search_docs.

Troubleshooting

The client doesn't call DocSearch MCP

Confirm that the server is enabled and named algolia-docsearch. If you installed a plugin, confirm that the plugin is enabled. Then ask the client to use DocSearch MCP explicitly.

The client can't connect

Confirm that the client supports remote HTTP MCP servers and uses this exact HTTPS URL:

text
https://mcp.algolia.com/1/docsearch/mcp

The public endpoint doesn't require authentication. Remove application IDs, API keys, headers, or authentication settings that the client doesn't require.

CLI setup doesn't detect an agent

Pass the agent flag directly, or use --all with the setup command from the installation guide.

sh
docsearch setup --project --cursor --yes
docsearch setup --global --all --yes

Supported flags are --cursor, --claude, --codex, --opencode, and --gemini.

CLI setup reports an invalid configuration

Fix the reported JSON, JSONC, or TOML error before running setup again. The CLI stops instead of replacing an invalid configuration. It also rejects duplicate [mcp_servers.algolia-docsearch] sections in Codex configuration.

The result covers the wrong product

Use the official product or vendor name. For example, use Algolia InstantSearch instead of search. If the name remains ambiguous, resolve the documentation set first and query the selected ID.

The result is too broad or empty

Add the product version and narrow the question to one task. Run separate searches for unrelated topics. If a narrower search still returns no useful content, the requested documentation might not be in the public DocSearch corpus.

Private documentation isn't returned

DocSearch MCP searches public developer documentation only. It doesn't search private company docs, internal repositories, or unpublished APIs.


Packages Website Docs Packages Core Api (`packages/website/docs/packages/core/api.mdx`)


title: Core API reference toc_max_heading_level: 2

`DocSearch`

DocSearch is a ref-forwarding React provider.

`appId`

type: string | optional

Optional parent level application ID. If this is set, appId won't need to be set on the child Modal/Sidepanel.

`apiKey`

type: string | optional

Optional parent level search API key. If this is set, apiKey won't need to be set on the child Modal/Sidepanel.

`children`

type: React.ReactNode | required

Views and controls that consume DocSearch state.

`theme`

type: 'dark' | 'light' | optional

Sets document.documentElement.dataset.theme while mounted.

`initialQuery`

type: string | optional

Initial modal query and reset value after close. Defaults to ''.

`keyboardShortcuts`

type: KeyboardShortcuts | optional

Overrides individual shortcut defaults. All shortcuts are enabled by default.

`onReady`

type: () => void | optional

Runs after the provider mounts.

`onOpen`

type: () => void | optional

Runs when a modal opens.

`onClose`

type: () => void | optional

Runs when a modal closes to the ready state.

`onSidepanelOpen`

type: () => void | optional

Runs when the Sidepanel opens.

`onSidepanelClose`

type: () => void | optional

Runs when the Sidepanel closes.

`KeyboardShortcuts`

ts
interface KeyboardShortcuts {
  'Ctrl/Cmd+K'?: boolean;
  '/'?: boolean;
  'Ctrl/Cmd+I'?: boolean;
}

DEFAULT_KEYBOARD_SHORTCUTS sets all three fields to true.

`DocSearchRef`

Attach this ref to DocSearch.

`open`

type: () => void

Opens the search modal.

`close`

type: () => void

Returns to the ready state and focuses the registered search button.

`openAskAi`

type: (message?: InitialAskAiMessage) => void

Opens Ask AI in a registered view. See Hybrid Mode.

`openSidepanel`

type: (message?: InitialAskAiMessage) => void

Opens the Sidepanel; it does nothing until that view registers.

`isReady`

type: readonly boolean

Whether the provider is mounted.

`isOpen`

type: readonly boolean

Whether a modal is open.

`isSidepanelOpen`

type: readonly boolean

Whether the Sidepanel is open.

`isSidepanelSupported`

type: readonly boolean

Whether Sidepanel support is registered. See Hybrid Mode.

ts
type InitialAskAiMessage = {
  query: string;
  messageId?: string;
  suggestedQuestionId?: string;
};

`useDocSearch`

ts
function useDocSearch(): DocSearchContext;

The hook returns the nearest provider value.

DocSearchState is 'modal-askai' | 'modal-search' | 'ready' | 'sidepanel'.

View is 'modal' | 'sidepanel' | (Record<string, unknown> & string), so integrations can register another string view.

`docsearchState`

type: DocSearchState

Active state.

`setDocsearchState`

type: (state: DocSearchState) => void

Sets active state directly.

`searchButtonRef`

type: React.RefObject<HTMLButtonElement | null>

Ref used to restore focus after close.

`initialQuery`

type: string

Query for a modal opening.

`keyboardShortcuts`

type: Required<KeyboardShortcuts>

User options merged with defaults.

`openModal`

type: () => void

Opens keyword search.

`closeModal`

type: () => void

Closes the modal and resets its query.

`isAskAiActive`

type: boolean

Whether the modal is in Ask AI state.

`isModalActive`

type: boolean

Whether either modal state is active.

`onAskAiToggle`

type: OnAskAiToggle

Changes the active Ask AI state. See Hybrid Mode.

`initialAskAiMessage`

type: InitialAskAiMessage | undefined | optional

Initial Sidepanel message.

`registerView`

type: (view: View) => void

Registers an available view.

`isHybridModeSupported`

type: boolean

Whether cross-view support is available. See Hybrid Mode.

`useKeyboardShortcuts`

ts
function useKeyboardShortcuts(
  userShortcuts?: KeyboardShortcuts
): Required<KeyboardShortcuts>;

Returns the defaults merged with the supplied fields.

`useTheme`

ts
function useTheme(props: { theme?: 'dark' | 'light' }): void;

When theme differs from the document's existing data-theme, the hook sets it and restores the previous value on cleanup. It makes no change when theme is omitted.

`useDocSearchKeyboardEvents`

ts
interface UseDocSearchKeyboardEventsProps {
  isOpen: boolean;
  onOpen: () => void;
  onClose: () => void;
  isAskAiActive: boolean;
  onAskAiToggle: (active: boolean) => void;
  keyboardShortcuts?: KeyboardShortcuts;
  onInput?: (event: KeyboardEvent) => void;
  searchButtonRef?: React.RefObject<HTMLButtonElement | null>;
}

The hook registers a window keydown listener. Escape leaves Ask AI first, then closes an open modal. Control/Command+K toggles the modal. / opens it when the user isn't editing content.

onInput and searchButtonRef remain in the type for compatibility but are deprecated and aren't used by the hook.

Exports

The root @docsearch/core entry exports:

Kind Exports
Components and hooks DocSearch, useDocSearch, useDocSearchKeyboardEvents, useKeyboardShortcuts, useTheme
Constants DEFAULT_KEYBOARD_SHORTCUTS
Types DocSearchState, View, InitialAskAiMessage, OnAskAiToggle, DocSearchRef, DocSearchContext, DocSearchCallbacks, DocSearchProps, DocSearchTheme, UseThemeProps, UseDocSearchKeyboardEventsProps, DocSearchModalShortcuts, SidepanelShortcuts, KeyboardShortcuts

The package also exposes these subpaths:

Import path Exports
@docsearch/core/useDocSearchKeyboardEvents useDocSearchKeyboardEvents, UseDocSearchKeyboardEventsProps
@docsearch/core/useKeyboardShortcuts useKeyboardShortcuts, DEFAULT_KEYBOARD_SHORTCUTS, shortcut types
@docsearch/core/useTheme useTheme, DocSearchTheme, UseThemeProps

useIsMobile is internal and isn't a package export.


Packages Website Docs Packages Css Bundle Exports (`packages/website/docs/packages/css/bundle-exports.mdx`)


title: CSS bundles and exports

@docsearch/css publishes compiled CSS and SCSS-named assets in dist. The package doesn't define an exports map, so import the root entry or a listed dist file.

Root entry

The package fields main, unpkg, and jsdelivr all point to dist/style.css.

These imports load the same full search-and-modal bundle:

js title="app.js"
import '@docsearch/css';
import '@docsearch/css/dist/style.css';

Use only one of them.

Choose imports by surface

Each surface needs a different set of assets. See Published assets for the full file list.

Search button only

js title="app.js"
import '@docsearch/css/dist/button.css';

Keyword-search modal

js title="app.js"
import '@docsearch/css/dist/button.css';
import '@docsearch/css/dist/modal.css';

Use the root bundle instead if your modal can show Agent Studio responses.

Agent Studio modal

js title="app.js"
import '@docsearch/css';

Sidepanel

js title="app.js"
import '@docsearch/css';
import '@docsearch/css/dist/sidepanel.css';

The Sidepanel reuses Agent Studio response and Markdown classes from the root bundle, so sidepanel.css isn't the complete Sidepanel presentation by itself.

Load from a CDN

html title="index.html"
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@docsearch/css@^5/dist/style.css"
/>

Add the Sidepanel asset when needed:

html title="index.html"
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@docsearch/css@^5/dist/sidepanel.css"
/>

Use the caret beta range so compatible beta updates remain available.

Published assets

Path Contents
@docsearch/css/dist/style.css Variables, search button, modal, and Agent Studio response styles.
@docsearch/css/dist/_variables.css Shared light and dark custom properties.
@docsearch/css/dist/button.css Variables and search-button styles.
@docsearch/css/dist/modal.css Variables and keyword-search modal styles.
@docsearch/css/dist/_askai.css Agent Studio modal response and Markdown styles.
@docsearch/css/dist/sidepanel.css Variables, Sidepanel button, panel layout, and Sidepanel-specific overrides.

Each asset also has an equivalent .scss file: style.scss, _variables.scss, button.scss, modal.scss, _askai.scss, and sidepanel.scss. The build writes the compiled bundle to both extensions; these aren't Sass source partials.

React style bridge exports

@docsearch/react v5 beta also exposes JavaScript style bridge entry points. They re-export files from @docsearch/css:

Import path CSS target
@docsearch/react/style @docsearch/css
@docsearch/react/style/variables @docsearch/css/dist/_variables.css
@docsearch/react/style/button @docsearch/css/dist/button.css
@docsearch/react/style/modal @docsearch/css/dist/modal.css
@docsearch/react/style/askai @docsearch/css/dist/_askai.css
@docsearch/react/style/sidepanel @docsearch/css/dist/sidepanel.css

Prefer direct @docsearch/css imports when your bundler supports CSS package imports. They show which assets enter your bundle and work across the DocSearch React packages.


Packages Website Docs Packages Css Styling (`packages/website/docs/packages/css/styling.mdx`)


title: Style DocSearch

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

@docsearch/css contains the styles for the search button, modal, and Sidepanel.

Install and import

bash
npm install @docsearch/css@^5
bash
yarn add @docsearch/css@^5
bash
pnpm add @docsearch/css@^5
bash
bun add @docsearch/css@^5

For the search button and modal, import the package root:

js title="app.js"
import '@docsearch/css';

The root stylesheet includes variables, button styles, modal styles, and Agent Studio response styles. It doesn't include Sidepanel layout styles.

For a Sidepanel, add its stylesheet after the root stylesheet:

js title="app.js"
import '@docsearch/css';
import '@docsearch/css/dist/sidepanel.css';

Override variables

Load your overrides after DocSearch CSS.

css title="custom.css"
:root {
  --docsearch-primary-color: #2457d6;
  --docsearch-primary-dark-color: #173b99;
  --docsearch-focus-color: #0b57d0;
  --docsearch-modal-width: 48rem;
  --docsearch-modal-radius: 0.75rem;
  --docsearch-hit-height: 3.75rem;
  --docsearch-border-radius: 0.375rem;
}

Prefer variables over selector overrides. Variables preserve focus, responsive, and state styles across package updates.

Frequently used variables include:

  • Brand and state: --docsearch-primary-color, --docsearch-primary-dark-color, --docsearch-highlight-color, --docsearch-focus-color, --docsearch-error-color, --docsearch-success-color
  • Text and surfaces: --docsearch-text-color, --docsearch-secondary-text-color, --docsearch-background-color, --docsearch-modal-background, --docsearch-subtle-color, --docsearch-muted-color
  • Modal: --docsearch-modal-width, --docsearch-modal-height, --docsearch-modal-variable-height, --docsearch-modal-radius, --docsearch-modal-shadow
  • Search box and hits: --docsearch-searchbox-height, --docsearch-searchbox-background, --docsearch-hit-height, --docsearch-hit-background, --docsearch-hit-focus-background
  • Button: --docsearch-search-button-background, --docsearch-search-button-text-color
  • Sidepanel: --docsearch-sidepanel-background, --docsearch-sidepanel-primary, --docsearch-sidepanel-border, --docsearch-sidepanel-text-base, --docsearch-sidepanel-text-muted

Set dark theme values

DocSearch applies dark variables under html[data-theme='dark']. The theme="dark" prop on a DocSearch component sets this attribute.

Override dark values with the same selector:

css title="custom.css"
html[data-theme='dark'] {
  --docsearch-modal-background: #111827;
  --docsearch-background-color: #1f2937;
  --docsearch-text-color: #f3f4f6;
  --docsearch-secondary-text-color: #d1d5db;
  --docsearch-hit-background: #111827;
  --docsearch-hit-focus-background: #263244;
}

Add targeted overrides

All component classes use the DocSearch- prefix. Scope selector overrides to a component and preserve visible focus states.

css title="custom.css"
.DocSearch-Button {
  min-width: 15rem;
}

.DocSearch-Sidepanel-Container.floating {
  box-shadow: 0 1rem 3rem rgb(0 0 0 / 20%);
}

.DocSearch-Action:focus-visible,
.DocSearch-Button:focus-visible {
  outline: 2px solid var(--docsearch-focus-color);
  outline-offset: 2px;
}

Don't remove the visually hidden helpers or reduced-motion rules. They support accessible labels, keyboard use, and user motion preferences.

See the CSS bundle and export guide when you need component-specific assets.


Packages Website Docs Packages Docusaurus Adapter Configuration Reference (`packages/website/docs/packages/docusaurus-adapter/configuration-reference.mdx`)


title: Docusaurus adapter configuration toc_max_heading_level: 2

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Add supported options under themeConfig.docsearch. The adapter doesn't read themeConfig.algolia.

js title="docusaurus.config.mjs"
export default {
  plugins: ['@docsearch/docusaurus-adapter'],
  themeConfig: {
    docsearch: {
      appId: 'YOUR_APPLICATION_ID',
      apiKey: 'YOUR_SEARCH_API_KEY',
      indices: ['YOUR_INDEX_NAME'],
    },
  },
};

Compatibility

Dependency Supported version
Node.js 20 or later
Docusaurus 3.10.2 or later in the 3.x release line
React and React DOM 18 or 19

Keep the adapter, Docusaurus, React, and React DOM within these ranges. Don't run the adapter beside @docusaurus/theme-search-algolia.

Root options

The validator rejects unknown root options. Pass runtime functions such as custom Agent Studio tools through a swizzled SearchBar instead of themeConfig.

`appId`

type: string | required

Algolia application ID.

`apiKey`

type: string | required

Public API key with search permission.

`indices`

type: Array<string | DocSearchIndex> | required

Nonempty list of keyword indices, in query order. See Indices and search parameters.

`contextualSearch`

type: boolean | optional

Whether to add the current Docusaurus locale, default tag, and docs-version tags to search. Defaults to true. See Contextual search.

`externalUrlRegex`

type: string | optional

Regular expression that identifies result URLs that require full-page navigation. See URL processing.

`replaceSearchResultPathname`

type: { from: string | RegExp, to: string } | optional

Replace a result pathname before adding the Docusaurus base URL. See URL processing.

`facets`

type: Array<{ key: string, label?: string }> | optional

Facet controls in the search modal. Defaults to []. See Modal facets.

`initialQuery`

type: string | optional

Query placed in the modal when it opens. Defaults to ''.

`insights`

type: boolean | object | optional

Whether to enable Algolia Insights, or an object that configures it. Defaults to false.

`placeholder`

type: string | optional

Search input placeholder. Defaults to the built-in translation.

`translations`

type: DocSearchTranslations | optional

Search button and modal text overrides. Defaults to the Docusaurus translations.

`maxResultsPerGroup`

type: number | optional

Maximum results shown in each modal result group.

`disableUserPersonalization`

type: boolean | optional

Whether to disable recent searches, favorites, and stored AI conversations. Defaults to false.

`getMissingResultsUrl`

type: ({ query }) => string | optional

Build the no-results report URL.

`keyboardShortcuts`

type: object | optional

Enable or disable Ctrl/Cmd+K, /, and Ctrl/Cmd+I. All shortcuts are enabled by default.

`recentSearchesLimit`

type: number | optional

Maximum recent searches when no favorites exist. Defaults to 7.

`recentSearchesWithFavoritesLimit`

type: number | optional

Maximum recent searches when favorites exist. Defaults to 4.

`resultBadgeKey`

type: string | optional

Hit property rendered as a badge in modal results. See Result badges.

`searchPage`

type: false | SearchPageConfig | optional

Configure or disable the search results page. Defaults to { path: 'search' }. See Search page.

`askAi`

type: AskAiConfig | optional

Configure Agent Studio for the modal and Sidepanel. See Ask AI.

`sidePanel`

type: boolean | SidePanelConfig | optional

Whether to enable the Ask AI Sidepanel, or an object that configures it. Defaults to false. See Sidepanel.

Indices and search parameters

Define at least one keyword index. Use a string for its default settings or an object for per-index settings:

js title="docusaurus.config.mjs"
indices: [
  'docs_en',
  {
    name: 'api_reference',
    searchParameters: {
      facetFilters: ['version:v5'],
      filters: 'visibility:public',
      attributesToRetrieve: [
        'content',
        'hierarchy',
        'type',
        'url',
        'version',
      ],
      restrictSearchableAttributes: ['hierarchy', 'content'],
      distinct: true,
    },
  },
],

searchParameters accepts Algolia search parameters. The validator explicitly accepts facetFilters, filters, attributesToRetrieve, restrictSearchableAttributes, and distinct, and preserves other Algolia parameters.

The modal queries every index in array order. The search page queries only the first index.

Keep contextualSearch: true to limit results to the current locale and Docusaurus docs versions. The adapter merges these conditions into each index's facetFilters instead of replacing your filters.

Contextual search also applies to Ask AI when you set askAi.indices. The adapter merges version and language filters into askAi.searchParameters[index].filters for each dynamic index name.

Set contextualSearch: false when your records don't contain Docusaurus language and docusaurus_tag attributes:

js title="docusaurus.config.mjs"
docsearch: {
  // ...
  contextualSearch: false,
},

Use root facets to add filter controls to the modal:

js title="docusaurus.config.mjs"
docsearch: {
  // ...
  facets: [
    { key: 'language', label: 'Language' },
    { key: 'version', label: 'Version' },
  ],
},

Configure each attribute as an Algolia facet. The modal supports up to five unique, nonempty facet keys. It merges facet values from every keyword index and hides facets with no values.

Users can select multiple values per facet. The modal combines values of the same facet with OR and different facets with AND. When contextualSearch is on, the modal uses the contextual filters as initial selections. Expose language to let users change the current locale filter, or docusaurus_tag to let users change the default and docs version tags.

These controls don't configure the search page sidebar. Use searchPage.facets for that page.

Result badges

Set resultBadgeKey to a property path returned by each keyword index:

js title="docusaurus.config.mjs"
docsearch: {
  // ...
  indices: [
    {
      name: 'docs',
      searchParameters: {
        attributesToRetrieve: [
          'content',
          'hierarchy',
          'type',
          'url',
          'version',
        ],
      },
    },
  ],
  resultBadgeKey: 'version',
},

Dot paths and array indices work, including hierarchy.lvl1, tags[2], and tags.2. The adapter displays the badge in modal results. The built-in search page doesn't render result badges.

Search page

The adapter creates /search by default. Change the path and sidebar facets with an object:

js title="docusaurus.config.mjs"
searchPage: {
  path: 'find',
  facets: [
    { attribute: 'hierarchy.lvl0', label: 'Section' },
    { attribute: 'version', label: 'Version' },
  ],
},

Each facet requires attribute; label defaults to the attribute name. If facets is missing or empty, the page shows hierarchy.lvl0 with the label Section.

The page uses the first indices item and its searchParameters. It shows 15 results per request, stores refinements in the URL, and adds docs-version controls when contextual search and Docusaurus versioning are active. Configure every sidebar attribute as an Algolia facet.

Disable the route, modal footer link, and OpenSearch metadata with:

js title="docusaurus.config.mjs"
searchPage: false,

Ask AI

Create an assistant by following Get started with Agent Studio. Set askAi to an object:

js title="docusaurus.config.mjs"
askAi: {
  assistantId: 'YOUR_ASSISTANT_ID',
  suggestedQuestions: true,
  searchParameters: {
    docs: {
      filters: 'visibility:public',
      attributesToRetrieve: ['title', 'content', 'url'],
      distinct: true,
    },
  },
  memory: {
    enabled: true,
    userToken: 'SERVER_GENERATED_JWT',
  },
  promptSuggestions: {
    indexName: 'docs_prompt_suggestions',
    hitsPerPage: 3,
  },
},

`assistantId`

type: string | required

Agent Studio assistant ID.

`suggestedQuestions`

type: boolean | optional

Whether to show published assistant questions on the new-conversation screen. Defaults to false.

`searchParameters`

type: Record<string, AgentStudioSearchParameters> | optional

Search parameters keyed by index name. Root askAi.searchParameters supports filters, attributesToRetrieve, restrictSearchableAttributes, and distinct. Don't add facetFilters at this level.

`indices`

type: string[] | optional

Index names available to Agent Studio search tools. See dynamic indices.

js title="docusaurus.config.mjs"
askAi: {
  agentId: 'YOUR_ASSISTANT_ID',
  indices: ['docs_markdown'],
  searchParameters: {
    docs_markdown: {
      filters: 'language:en',
    },
  },
},

`memory`

type: { enabled?: boolean, userToken?: string } | optional

Show memory tool calls and send a user JWT. Memory is disabled by default. See user-scoped memory.

`promptSuggestions`

type: { indexName: string, hitsPerPage?: number } | optional

Show prompt suggestions with keyword results. hitsPerPage defaults to 3. See Configure prompt suggestions.

Sidepanel

Set sidePanel: true for the default panel. askAi is required whenever the Sidepanel is enabled.

js title="docusaurus.config.mjs"
sidePanel: {
  variant: 'inline',
  side: 'right',
  width: 420,
  expandedWidth: '60vw',
  pushSelector: '#__docusaurus',
  suggestedQuestions: true,
  hideButton: false,
  keyboardShortcuts: {
    'Ctrl/Cmd+I': true,
  },
},

Review hybrid mode before changing panel behavior.

`variant`

type: 'floating' | 'inline' | optional

Float above content or push selected content. Defaults to 'inline'.

`side`

type: 'left' | 'right' | optional

Side where the panel opens. Defaults to 'right'.

`width`

type: number | string | optional

Collapsed panel width. Numbers represent pixels. Defaults to 360px.

`expandedWidth`

type: number | string | optional

Expanded panel width. Numbers represent pixels. Defaults to 580px.

`pushSelector`

type: string | optional

Element pushed by the inline panel. Defaults to #__docusaurus.

`suggestedQuestions`

type: boolean | optional

Whether to show suggested questions in the panel. Defaults to askAi.suggestedQuestions.

`translations`

type: SidepanelTranslations | optional

Panel text overrides. Defaults to the built-in strings.

`hideButton`

type: boolean | optional

Whether to hide the Sidepanel button while keeping the panel registered. Defaults to false.

`portalContainer`

type: DocumentFragment | Element | null | optional

Element that receives the panel portal. Defaults to document.body. Pass this option through a swizzled SearchBar because a DOM element isn't available while Docusaurus evaluates its server configuration.

`keyboardShortcuts`

type: { 'Ctrl/Cmd+I'?: boolean } | optional

Enable or disable the panel shortcut. The shortcut is enabled by default.

`indices`

type: string[] | optional

Override Agent Studio indices for the panel. Defaults to askAi.indices. See dynamic indices.

`memory`

type: { enabled?: boolean, userToken?: string } | optional

Override memory for the panel. Defaults to askAi.memory. See user-scoped memory.

Custom tools

Docusaurus can't serialize tool functions in themeConfig. The adapter rejects both askAi.tools and sidePanel.tools there.

Swizzle SearchBar from @docsearch/docusaurus-adapter, then pass tools as component props:

bash
npm run swizzle -- @docsearch/docusaurus-adapter SearchBar --eject

Replace the generated component with one of these examples:

tsx title="src/theme/searchbar/index.tsx"
import type { DocusaurusSearchBarProps } from '@docsearch/docusaurus-adapter';
import type { ToolCalls } from '@docsearch/react';
import OriginalSearchBar from '@theme-original/SearchBar';

const tools: ToolCalls = {
  getReleaseStatus: {
    render: ({ message }) => JSON.stringify(message.output),
  },
};

export default function SearchBar(props: DocusaurusSearchBarProps) {
  return (
    <OriginalSearchBar
      {...props}
      askAi={{
        assistantId: 'YOUR_ASSISTANT_ID',
        tools,
      }}
      sidePanel={{ tools }}
    />
  );
}
jsx title="src/theme/searchbar/index.js"
import OriginalSearchBar from '@theme-original/SearchBar';

const tools = {
  getReleaseStatus: {
    render: ({ message }) => JSON.stringify(message.output),
  },
};

export default function SearchBar(props) {
  return (
    <OriginalSearchBar
      {...props}
      askAi={{
        assistantId: 'YOUR_ASSISTANT_ID',
        tools,
      }}
      sidePanel={{ tools }}
    />
  );
}

Passing askAi or sidePanel as a prop replaces that nested theme-config value. Include every nested option that you want to keep in the prop object. See Agent Studio tools for tool renderers and client-side handlers.

Translations

Override only the modal strings you need:

js title="docusaurus.config.mjs"
translations: {
  button: {
    buttonText: 'Search API docs',
    buttonAriaLabel: 'Search API docs',
  },
  modal: {
    searchBox: {
      placeholderText: 'Search API docs',
    },
    facets: {
      clearAllLabel: 'Reset filters',
    },
    resultsScreen: {
      resultBadgeLabelText: 'Version',
    },
  },
},

The adapter uses Docusaurus translation IDs for its default search button, modal, and search page strings. Run the Docusaurus write-translations command to localize built-in strings. Put Sidepanel overrides under sidePanel.translations.

URL processing

The adapter parses each result URL. It leaves URLs matching externalUrlRegex unchanged and uses full-page navigation for them. For other URLs, it keeps the pathname, query, and hash, applies replaceSearchResultPathname, and adds the Docusaurus base URL.

js title="docusaurus.config.mjs"
docsearch: {
  // ...
  externalUrlRegex: '^https://external\\.example\\.com/',
  replaceSearchResultPathname: {
    from: '/legacy-docs/',
    to: '/docs/',
  },
},

A string from value is treated literally. A RegExp is converted to its source during validation.

Validation errors

The adapter reports dedicated errors for removed or unsupported v4 options. Use the replacement named in each message:

text
`themeConfig.algolia` is no longer supported by @docsearch/docusaurus-adapter v5. Move the configuration to `themeConfig.docsearch`.

`themeConfig.docsearch.indexName` was removed. Use `themeConfig.docsearch.indices` instead.

`themeConfig.docsearch.searchParameters` was removed. Configure `searchParameters` on each `themeConfig.docsearch.indices` entry instead.

`themeConfig.docsearch.searchPagePath` was removed. Use `themeConfig.docsearch.searchPage` instead.

`themeConfig.docsearch.askAi` must be an object with `assistantId`.

`themeConfig.docsearch.askAi.agentStudio` was removed. The adapter now only supports Agent Studio.

`themeConfig.docsearch.askAi.indexName`, `apiKey`, and `appId` were removed. Use the top-level DocSearch credentials instead.

`themeConfig.docsearch.askAi.sidePanel` was removed. Use `themeConfig.docsearch.sidePanel` instead.

`themeConfig.docsearch.sidePanel` requires `themeConfig.docsearch.askAi`.

Tool definitions report these errors:

text
`themeConfig.docsearch.askAi.tools` is not supported because Docusaurus removes function values when serializing theme config. Pass custom tools through a swizzled `@theme/SearchBar` component instead: use `askAi` for the modal and `sidePanel` for the side panel.

`themeConfig.docsearch.sidePanel.tools` is not supported because Docusaurus removes function values when serializing theme config. Pass custom tools through a swizzled `@theme/SearchBar` component instead: use `askAi` for the modal and `sidePanel` for the side panel.

The schema also reports these messages for missing or invalid required configuration:

text
"themeConfig.docsearch" is required
"docsearch.appId" is required. If you haven't migrated to the new DocSearch infra, please refer to the blog post for instructions: https://docusaurus.io/blog/2021/11/21/algolia-docsearch-migration
"docsearch.apiKey" is required
"docsearch.indices" is required
"docsearch.indices" must contain at least 1 items
"docsearch.unknownKey" is not allowed
"docsearch.askAi.indices" must contain at least 1 items
"docsearch.askAi.indices[0]" must be a string
"docsearch.sidePanel.indices" must contain at least 1 items
"docsearch.sidePanel.indices[0]" must be a string

Replace unknownKey with the rejected option name. Other invalid nested values use the same Joi path format.


Packages Website Docs Packages Docusaurus Adapter Migrating From V4 (`packages/website/docs/packages/docusaurus-adapter/migrating-from-v4.mdx`)


title: Migrate the Docusaurus adapter from v4

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

DocSearch v5 requires themeConfig.docsearch, a nonempty indices array, and Agent Studio for Ask AI. Update the adapter and configuration together.

Review the broader DocSearch v4 migration guide for changes outside the Docusaurus adapter.

1. Check compatibility

Upgrade the site to Node.js 20 or later and Docusaurus 3.10.2 or later in the Docusaurus 3 release line. Use React and React DOM 18 or 19.

2. Install the v5 adapter

Install @docsearch/docusaurus-adapter@^5:

bash
npm install @docsearch/docusaurus-adapter@^5
bash
yarn add @docsearch/docusaurus-adapter@^5
bash
pnpm add @docsearch/docusaurus-adapter@^5
bash
bun add @docsearch/docusaurus-adapter@^5

Keep the adapter in plugins and don't add @docusaurus/theme-search-algolia as another search integration.

3. Move to `themeConfig.docsearch`

V4 accepted themeConfig.algolia as an alias. V5 rejects it.

js title="docusaurus.config.mjs"
export default {
  plugins: ['@docsearch/docusaurus-adapter'],
  themeConfig: {
    algolia: {
      appId: 'YOUR_APPLICATION_ID',
      apiKey: 'YOUR_SEARCH_API_KEY',
      indexName: 'docs',
    },
  },
};
js title="docusaurus.config.mjs"
export default {
  plugins: ['@docsearch/docusaurus-adapter'],
  themeConfig: {
    docsearch: {
      appId: 'YOUR_APPLICATION_ID',
      apiKey: 'YOUR_SEARCH_API_KEY',
      indices: [{ name: 'docs' }],
    },
  },
};

Don't define both keys during the migration. V5 accepts only themeConfig.docsearch.

4. Replace `indexName` and root search parameters

Move every keyword index into indices. Move root searchParameters onto the matching index:

js title="docusaurus.config.mjs"
docsearch: {
  appId: 'YOUR_APPLICATION_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  indexName: 'docs',
  searchParameters: {
    facetFilters: ['language:en'],
    attributesToRetrieve: ['content', 'hierarchy', 'type', 'url'],
  },
},
js title="docusaurus.config.mjs"
docsearch: {
  appId: 'YOUR_APPLICATION_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  indices: [
    {
      name: 'docs',
      searchParameters: {
        facetFilters: ['language:en'],
        attributesToRetrieve: ['content', 'hierarchy', 'type', 'url'],
      },
    },
  ],
},

indices is required and must contain at least one item. The modal queries all items in order. The search page uses the first item.

5. Replace `searchPagePath`

V5 replaces the path value with an object that can also configure facets:

js title="docusaurus.config.mjs"
searchPagePath: 'find',
js title="docusaurus.config.mjs"
searchPage: {
  path: 'find',
  facets: [
    { attribute: 'hierarchy.lvl0', label: 'Section' },
    { attribute: 'version', label: 'Version' },
  ],
},

Use searchPage: false to disable the route. An empty object uses the default search path and the default hierarchy.lvl0 section facet.

6. Move Ask AI to Agent Studio

Create an assistant by following Get started with Agent Studio. V5 accepts only an askAi object and always uses Agent Studio.

js title="docusaurus.config.mjs"
askAi: {
  assistantId: 'YOUR_ASSISTANT_ID',
  appId: 'ASK_AI_APPLICATION_ID',
  apiKey: 'ASK_AI_SEARCH_API_KEY',
  indexName: 'docs_markdown',
  agentStudio: true,
},

V4 also accepted this shorthand:

js title="docusaurus.config.mjs"
askAi: 'YOUR_ASSISTANT_ID',
js title="docusaurus.config.mjs"
askAi: {
  agentId: 'YOUR_ASSISTANT_ID',
  indices: ['docs_markdown'],
},

Remove agentStudio, appId, apiKey, and indexName from askAi. The adapter reuses the root credentials. Without askAi.indices, it uses the first keyword index as the Ask AI index.

V4 supported flat search parameters for the legacy Ask AI backend. V5 requires Agent Studio search parameters keyed by index name:

js title="docusaurus.config.mjs"
askAi: {
  assistantId: 'YOUR_ASSISTANT_ID',
  searchParameters: {
    filters: 'language:en',
    attributesToRetrieve: ['title', 'content', 'url'],
  },
},
js title="docusaurus.config.mjs"
askAi: {
  assistantId: 'YOUR_ASSISTANT_ID',
  searchParameters: {
    docs: {
      filters: 'language:en',
      attributesToRetrieve: ['title', 'content', 'url'],
    },
  },
},

Root askAi.searchParameters supports filters, attributesToRetrieve, restrictSearchableAttributes, and distinct.

7. Move the Sidepanel to the root

Move sidePanel out of askAi:

js title="docusaurus.config.mjs"
askAi: {
  assistantId: 'YOUR_ASSISTANT_ID',
  sidePanel: {
    variant: 'inline',
    side: 'right',
  },
},
js title="docusaurus.config.mjs"
askAi: {
  assistantId: 'YOUR_ASSISTANT_ID',
},
sidePanel: {
  variant: 'inline',
  side: 'right',
},

The root sidePanel requires askAi. It can override Agent Studio indices, memory, suggestedQuestions, and translations for the panel. Review hybrid mode for modal and panel behavior.

V5 rejects askAi.tools and sidePanel.tools in docusaurus.config because Docusaurus removes functions while serializing theme config. Swizzle @theme/SearchBar and pass tools as component props.

bash
npm run swizzle -- @docsearch/docusaurus-adapter SearchBar --eject
tsx title="src/theme/searchbar/index.tsx"
import type { DocusaurusSearchBarProps } from '@docsearch/docusaurus-adapter';
import type { ToolCalls } from '@docsearch/react';
import OriginalSearchBar from '@theme-original/SearchBar';

const tools: ToolCalls = {
  getReleaseStatus: {
    render: ({ message }) => JSON.stringify(message.output),
  },
};

export default function SearchBar(props: DocusaurusSearchBarProps) {
  return (
    <OriginalSearchBar
      {...props}
      askAi={{ assistantId: 'YOUR_ASSISTANT_ID', tools }}
      sidePanel={{ tools }}
    />
  );
}
jsx title="src/theme/searchbar/index.js"
import OriginalSearchBar from '@theme-original/SearchBar';

const tools = {
  getReleaseStatus: {
    render: ({ message }) => JSON.stringify(message.output),
  },
};

export default function SearchBar(props) {
  return (
    <OriginalSearchBar
      {...props}
      askAi={{ assistantId: 'YOUR_ASSISTANT_ID', tools }}
      sidePanel={{ tools }}
    />
  );
}

Include every nested askAi and sidePanel option that you want to keep because component props replace those nested theme-config values. See Agent Studio tools for complete tool definitions.

9. Add v5 search features

Configure modal facets at the docsearch root:

js title="docusaurus.config.mjs"
facets: [
  { key: 'language', label: 'Language' },
  { key: 'version', label: 'Version' },
],

Configure search-page facets separately under searchPage.facets. Configure every facet attribute in your Algolia index.

Show a custom hit property in modal results with resultBadgeKey. Add that property to each index's attributesToRetrieve:

js title="docusaurus.config.mjs"
indices: [
  {
    name: 'docs',
    searchParameters: {
      attributesToRetrieve: [
        'content',
        'hierarchy',
        'type',
        'url',
        'version',
      ],
    },
  },
],
resultBadgeKey: 'version',

10. Verify the migration

Run the production Docusaurus build, then verify these paths:

  • Open keyword search with the button, Ctrl/Cmd+K, and /.
  • Search every configured index and apply each modal facet.
  • Open the search page, apply its facets, and check docs-version filtering.
  • Open Ask AI and submit a follow-up question.
  • Open the Sidepanel with its button and Ctrl/Cmd+I.
  • Check contextual results in every locale and docs version.
  • Follow internal, replaced, and external result URLs.
  • Check translated strings and result badges.
  • Test mobile behavior. Hybrid mode uses the modal instead of the Sidepanel on mobile.

Use the configuration reference to resolve validation messages and review every v5 option.


Packages Website Docs Packages Js Api Reference (`packages/website/docs/packages/js/api-reference.mdx`)


title: JS package API reference toc_max_heading_level: 2

`docsearch(options)`

Renders DocSearch in options.container and returns a DocSearchInstance.

ts title="load-docsearch.ts"
import docsearch from '@docsearch/js';

const instance = docsearch(options);

The default export from @docsearch/js is AI-capable and uses DocSearchAI. The default export from @docsearch/js/docsearch is keyword-only and uses DocSearch.

JavaScript options

`container`

type: HTMLElement | string | required

Container element or CSS selector for the search button. A selector resolves against environment.document and must match an element.

`environment`

type: typeof window | optional

Browser-like environment used to resolve a string container. Defaults to window.

`onReady`

type: () => void | optional

Callback after DocSearch mounts.

`onOpen`

type: () => void | optional

Callback when the modal opens.

`onClose`

type: () => void | optional

Callback when the modal closes.

`interceptAskAiEvent`

type: (initialMessage: InitialAskAiMessage) => boolean | void | optional

Callback before DocSearch starts an Ask AI request. Return true to prevent the modal from toggling or sending the message. Use this option to route the request to another view, such as the Sidepanel.

InitialAskAiMessage contains query and can contain messageId or suggestedQuestionId.

Search options

These options apply to both package entries.

`appId`

type: string | required

Algolia application ID.

`apiKey`

type: string | required

Public API key with search permission.

`indices`

type: Array<string | DocSearchIndex> | optional

Indices used for keyword search, in display order. There's no default, and at least indices or indexName is required.

Use a string for default search parameters or a DocSearchIndex for per-index parameters:

ts
interface DocSearchIndex {
  name: string;
  searchParameters?: SearchParamsObject;
}
js title="docsearch-options.js"
indices: [
  {
    name: 'docs_en',
    searchParameters: {
      facetFilters: ['version:v5'],
      attributesToRetrieve: [
        'hierarchy.lvl0',
        'hierarchy.lvl1',
        'hierarchy.lvl2',
        'hierarchy.lvl3',
        'hierarchy.lvl4',
        'hierarchy.lvl5',
        'hierarchy.lvl6',
        'content',
        'type',
        'url',
        'version',
      ],
    },
  },
  'docs_fr',
];

If you pass both indexName and indices, DocSearch queries indexName first, then each indices item. indexName and the root searchParameters remain available for v4 compatibility but are deprecated.

`indexName`

type: string | optional

Deprecated index name. There's no default. Use indices.

`facets`

type: DocSearchFacet[] | optional

Facet controls populated from the configured indices. Defaults to [].

ts
interface DocSearchFacet {
  key: string;
  label?: string;
}

DocSearch supports up to five facets. It compares trimmed, lowercase keys to ignore duplicates and empty keys, fetches values from all configured indices, and displays only facets that have values.

Users can select multiple values per facet. DocSearch combines values of the same facet with OR and different facets with AND when it builds facetFilters for each index. A selection replaces the index's configured facetFilters entries for that facet key and keeps entries for other keys. DocSearch also replaces a configured OR group when the user has a selection for every key in the group.

js title="docsearch-options.js"
facets: [
  { key: 'language', label: 'Language' },
  { key: 'version', label: 'Version' },
];

Configure each attribute for faceting in the Algolia index before exposing it here.

`theme`

type: 'light' | 'dark' | optional

Theme written to document.documentElement.dataset.theme. By default, DocSearch leaves the current theme unchanged.

`placeholder`

type: string | optional

Search input placeholder. The default is experience-specific.

`searchParameters`

type: SearchParamsObject | optional

Deprecated search parameters for indexName. There's no default. Put them on an indices item.

`maxResultsPerGroup`

type: number | optional

Maximum results in each result group. There's no default.

`transformItems`

type: (items: DocSearchHit[]) => DocSearchHit[] | optional

Function that transforms hits before grouping and rendering. Defaults to the identity function.

`hitComponent`

type: ({ hit, children }, { html }) => JSX.Element | optional

Template for a result link. Defaults to the built-in hit template. See Templates.

`resultsFooterComponent`

type: ({ state }, { html }) => JSX.Element | null | optional

Template below the result collections. There's no default. See Templates.

`footerAction`

type: (_, { html }) => JSX.Element | null | optional

Optional function to render a custom action in the Modal's footer. It will be rendered in line with the Algolia "powered by" logo. See Templates.

`transformSearchClient`

type: (client) => client | optional

Function that wraps or replaces the Algolia search client. Defaults to the identity function.

`disableUserPersonalization`

type: boolean | optional

Whether to disable recent searches, favorites, and stored AI conversations. Defaults to false.

`initialQuery`

type: string | optional

Query placed in the input when the modal opens. Defaults to ''.

type: AutocompleteOptions['navigator'] | optional

Autocomplete navigation implementation. Defaults to the default navigator.

`translations`

type: DocSearchTranslations | optional

Button and modal text overrides. Defaults to the English strings.

`getMissingResultsUrl`

type: ({ query }) => string | optional

Function that builds the no-results report URL. There's no default.

`insights`

type: AutocompleteOptions['insights'] | optional

Algolia Insights integration options. Defaults to false.

`portalContainer`

type: DocumentFragment | Element | optional

Element that receives the modal portal. Defaults to document.body.

`recentSearchesLimit`

type: number | optional

Maximum recent searches without favorites. Defaults to 7.

`recentSearchesWithFavoritesLimit`

type: number | optional

Maximum recent searches when favorites exist. Defaults to 4.

`keyboardShortcuts`

type: DocSearchModalShortcuts | optional

Whether Ctrl/Cmd+K and / open the modal. Both shortcuts are enabled by default. Escape always closes it.

`resultBadgeKey`

type: string | optional

Hit property rendered as a result badge. There's no default.

The key supports property paths such as version, hierarchy.lvl1, tags[2], and tags.2. Primitive values render as text. Arrays of primitive values render as a comma-separated list.

Add custom badge data to attributesToRetrieve. Otherwise the property isn't present in the hit:

js title="docsearch-options.js"
indices: [
  {
    name: 'docs',
    searchParameters: {
      attributesToRetrieve: [
        'hierarchy.lvl0',
        'hierarchy.lvl1',
        'hierarchy.lvl2',
        'hierarchy.lvl3',
        'hierarchy.lvl4',
        'hierarchy.lvl5',
        'hierarchy.lvl6',
        'content',
        'type',
        'url',
        'version',
      ],
    },
  },
],
resultBadgeKey: 'version',

Set translations.modal.resultsScreen.resultBadgeLabelText to describe the badge to screen-reader users. Its default is Category.

Templates

  • hitComponent receives { hit, children }.
  • resultsFooterComponent receives { state }.
  • footerAction currently does not receive any extra props.

JavaScript templates can return a Preact element, a string, or a component function. The optional second argument provides an html tagged-template helper.

js title="docsearch-options.js"
docsearch({
  hitComponent({ hit, children }, { html }) {
    return html`<a href=${hit.url} data-result-type=${hit.type}>${children}</a>`;
  },
  resultsFooterComponent({ state }, { html }) {
    return html`<p>No results found for query: ${state.query}</p>`;
  },
  footerAction(_, { html }) {
    return html`<a href="https://algolia.com">Our other project</a>`;
  },
});

Ask AI options

Ask AI is available from the default @docsearch/js entry. Its askAi option is required by that entry's DocSearchProps type.

`askAi`

type: string | DocSearchAskAi | required

Assistant ID or Agent Studio configuration. The default entry requires it.

js title="docsearch-options.js"
askAi: 'YOUR_ASSISTANT_ID';

Use an object for additional controls.

Follow Get started with Agent Studio to create the assistant and hybrid mode to route AI requests to a Sidepanel.

`assistantId`

type: string | required

Agent Studio assistant ID.

`appId`

type: string | optional

Application ID used by Ask AI. Defaults to the root appId.

`apiKey`

type: string | optional

API key used by Ask AI. Defaults to the root apiKey.

`indexName`

type: string | optional

Index used by Ask AI. Defaults to the first normalized keyword index.

`suggestedQuestions`

type: boolean | optional

Whether to show published assistant questions on the new-conversation screen. Defaults to false.

`searchParameters`

type: AgentStudioSearchParameters | optional

Search parameters keyed by index name. There's no default.

Each value supports filters, attributesToRetrieve, restrictSearchableAttributes, and distinct. This Agent Studio shape doesn't accept facetFilters.

js title="docsearch-options.js"
askAi: {
  assistantId: 'YOUR_ASSISTANT_ID',
  searchParameters: {
    docs: {
      filters: 'language:en',
      attributesToRetrieve: ['title', 'content', 'url'],
      distinct: true,
    },
  },
}

`indices`

type: string[] | optional

Index names for the Agent Studio search tool on this request. There's no default.

Put descriptions and tool defaults on the agent configuration. Put per-index runtime overrides in searchParameters.

js title="docsearch-options.js"
askAi: {
  agentId: 'YOUR_ASSISTANT_ID',
  indices: ['api_reference', 'docs_markdown'],
  searchParameters: {
    api_reference: {
      filters: 'version:latest',
    },
  },
}

`tools`

type: ToolCalls | optional

Custom Agent Studio tool renderers and handlers. Defaults to {}.

ToolCalls maps Agent Studio tool names to ToolDefinition objects. render converts the tool input and output to displayed text. onToolCall handles a client-side tool and must call addToolOutput when it produces a result. translations.callingToolText changes the pending label.

`memory`

type: Memory | optional

Agent Studio memory display and user token. Memory is disabled by default.

js title="docsearch-options.js"
memory: {
  enabled: true,
  userToken: 'SERVER_GENERATED_JWT_TOKEN',
}

enabled controls whether memory tool calls appear. userToken is the JWT sent in the x-algolia-secure-user-token header.

`promptSuggestions`

type: PromptSuggestions | optional

Prompt suggestions displayed with keyword results. There's no default.

js title="docsearch-options.js"
promptSuggestions: {
  indexName: 'docsearch_prompt_suggestions',
  hitsPerPage: 3,
}

The index records must contain a prompt attribute. hitsPerPage defaults to 3.

`DocSearchInstance`

`isReady`

type: readonly boolean

Whether the instance is mounted.

`isOpen`

type: readonly boolean

Whether the modal is open.

`open`

type: () => void

Opens keyword search.

`close`

type: () => void

Closes the modal.

`openAskAi`

type: (initialMessage?: InitialAskAiMessage) => void

Opens Ask AI with an optional query. Use with the AI-capable entry.

`destroy`

type: () => void

Unmounts DocSearch and marks the instance not ready.

Compatibility and deprecations

  • The bundles target ES2017 browsers.
  • indexName and root searchParameters remain supported but are deprecated. Move to indices.
  • The default entry uses Agent Studio. The v4 Ask AI transport and askAi.agentStudio switch aren't available.
  • The keyword-only /docsearch export is the smaller choice when you don't configure Ask AI.

Packages Website Docs Packages Modal Api (`packages/website/docs/packages/modal/api.mdx`)


title: Modal API reference

`DocSearchButton`

type: React.ComponentType<DocSearchButtonProps>

Renders the search trigger. It runs your onClick handler, then opens the modal through the nearest DocSearch provider.

DocSearchButtonProps accepts standard React button props and the following prop. Configure theme and keyboardShortcuts on DocSearch, not on this component.

`translations`

type: { buttonText?: string; buttonAriaLabel?: string } | optional

Sets the visible and accessible button text. Both values default to English labels.

`DocSearchModal`

type: React.ComponentType<DocSearchModalProps>

Renders a keyword-search modal when its provider is active. It renders in document.body unless you set portalContainer.

Required props

`appId`

type: string | required

Algolia application ID.

`apiKey`

type: string | required

Public API key with search permission.

`indices`

type: Array<string | DocSearchIndex> | required

The list of indices and their optional configuration used for search.

Search props

`facets`

type: Array<{ key: string; label?: string }> | optional

Adds filter controls that use facet values from the configured indices. Defaults to [].

`placeholder`

type: string | optional

Sets the search input placeholder. Defaults to Search docs. A translation can override this value.

`maxResultsPerGroup`

type: number | optional

Limits the displayed hits in each result group.

`transformItems`

type: (items: DocSearchHit[]) => DocSearchHit[] | optional

Changes hits before rendering. Defaults to the identity function.

`transformSearchClient`

type: (client: DocSearchTransformClient) => DocSearchTransformClient | optional

Wraps or changes the search client. Defaults to the identity function.

type: AutocompleteOptions['navigator'] | optional

Controls link navigation.

`insights`

type: AutocompleteOptions['insights'] | optional

Configures Algolia Insights. Defaults to false.

`resultBadgeKey`

type: string | optional

Reads a hit property and displays it as a result badge. Include the property in attributesToRetrieve.

Rendering and behavior props

`initialQuery`

type: string | optional

Prefills the search input. This value takes precedence over the provider value and defaults to '' if neither value is set.

`portalContainer`

type: DocumentFragment | Element | optional

Receives the modal portal. Defaults to document.body.

`hitComponent`

type: (props) => JSX.Element | optional

Renders an individual result. Defaults to the built-in hit component.

`resultsFooterComponent`

type: (props) => JSX.Element | null | optional

Renders content below the results. Defaults to null.

`footerAction`

type: React.ReactNode | optional

Renders a custom element in the modal footer, before the "Powered by Algolia" logo. Passing null renders nothing.

`disableUserPersonalization`

type: boolean | optional

Disables storing and using recent and favorite searches. Defaults to false.

`recentSearchesLimit`

type: number | optional

Limits saved and displayed recent searches. Defaults to 7.

`recentSearchesWithFavoritesLimit`

type: number | optional

Limits recent searches when favorites exist. Defaults to 4.

`getMissingResultsUrl`

type: ({ query }: { query: string }) => string | optional

Builds the missing-results report URL.

`translations`

type: ModalTranslations | optional

Supplies partial strings for searchBox, footer, facets, errorScreen, startScreen, noResultsScreen, and resultsScreen. Defaults to {}.

DocSearchModal receives theme, keyboardShortcuts, and close behavior from the provider. It doesn't accept these props directly.

`DocSearchIndex`

`name`

type: string | required

Index to search.

`searchParameters`

type: SearchParamsObject | optional

Sets search parameters for this index.

`DocSearchAskAiModal`

type: React.ComponentType<DocSearchAskAiModalProps>

Renders the Agent Studio-enabled modal. It accepts every DocSearchModal prop, requires askAi, and adds Agent Studio translations.

`askAi`

type: string | DocSearchAskAi | required

Sets the Agent Studio agent ID or the complete Agent Studio configuration.

`interceptAskAiEvent`

type: (message: InitialAskAiMessage) => boolean | void | optional

Runs before the default Ask AI action. Return true to prevent the action.

`translations`

type: DocSearchAskAiModalTranslations | optional

Adds askAiScreen, newConversation, and Agent Studio search-box strings to the search translations. Defaults to {}.

The component receives its active state and close behavior from DocSearch. It doesn't accept isAskAiActive, isHybridModeSupported, onAskAiToggle, onClose, theme, or keyboardShortcuts. See Hybrid Mode for cross-view behavior.

`DocSearchAskAi`

The object form of askAi. It accepts the following fields.

`agentId`

type: string | required

Agent Studio agent ID.

`appId`

type: string | optional

Overrides the root appId for Agent Studio.

`apiKey`

type: string | optional

Overrides the root apiKey for Agent Studio.

`suggestedQuestions`

type: boolean | optional

Shows configured suggested questions on the new-conversation screen. Defaults to false.

`searchParameters`

type: Record<string, AgentStudioIndexSearchParameters> | optional

Sends search parameters keyed by index name. AgentStudioIndexSearchParameters supports filters, attributesToRetrieve, restrictSearchableAttributes, and distinct. It doesn't support facetFilters.

`indices`

type: string[] | optional

Index names available to Agent Studio search tools. Put descriptions and tool defaults on the agent configuration. Put per-index runtime overrides in searchParameters.

`tools`

type: Record<string, ToolDefinition> | optional

Handles and renders custom Agent Studio tools. Defaults to {}.

`memory`

type: { enabled?: boolean; userToken?: string } | optional

Displays memory tool activity and sends a secure user token.

`promptSuggestions`

type: { indexName: string; hitsPerPage?: number } | optional

Configures prompt suggestions in keyword search. hitsPerPage defaults to 3.

Custom tools

Each ToolDefinition accepts the following fields:

`render`

type: (params: { message: { input: unknown; output: unknown } }) => string | required

Renders the tool input and output.

`onToolCall`

type: (params: ToolCallParameters) => Promise<void> | void | optional

Handles a client-side tool call. ToolCallParameters includes input, addToolOutput, toolCallId, toolName, and the optional dynamic flag.

`translations`

type: { callingToolText?: string } | optional

Overrides the text shown while the tool runs.

When onToolCall handles a client-side tool, call addToolOutput with the result. Define the tools object outside your component or memoize it to keep its identity stable.

Memory

Set memory.enabled to render Agent Studio memory tool calls. Set memory.userToken to send the JSON Web Token (JWT) as the x-algolia-secure-user-token request header.

Generate the JWT on your server. Don't put signing secrets in browser code.

Exports

Import path Value exports Type exports
@docsearch/modal DocSearchButton, DocSearchModal, DocSearchAskAiModal DocSearchButtonProps, DocSearchModalProps, DocSearchAskAiModalProps
@docsearch/modal/button DocSearchButton DocSearchButtonProps
@docsearch/modal/modal DocSearchModal DocSearchModalProps
@docsearch/modal/askai DocSearchAskAiModal DocSearchAskAiModalProps

Packages Website Docs Packages React Api Reference (`packages/website/docs/packages/react/api-reference.mdx`)


title: React API reference

Components

`DocSearch`

type: React.ForwardRefExoticComponent<DocSearchProps>

Renders keyword search. It accepts the common props and forwards a DocSearchRef.

tsx title="search.tsx"
import { DocSearch } from '@docsearch/react';

`DocSearchAI`

type: React.ForwardRefExoticComponent<DocSearchAIProps>

Renders keyword search and Ask AI. It accepts the common props, requires askAi, and forwards a DocSearchRef.

tsx title="search.tsx"
import { DocSearchAI } from '@docsearch/react';

Common props

`appId`

type: string | required

Algolia application ID.

`apiKey`

type: string | required

Public API key with search permission.

`indices`

type: Array<string | DocSearchIndex> | optional

Indices to search in display order.

tsx title="search.tsx"
<DocSearch
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={[
    {
      name: 'docs_en',
      searchParameters: {
        facetFilters: ['version:v5'],
      },
    },
    'docs_fr',
  ]}
/>

`facets`

type: DocSearchFacet[] | optional

Facet controls populated from the configured indices. Defaults to [].

DocSearch supports up to five facets. It ignores empty and duplicate keys, merges sorted values from all configured indices, and hides facets with no values. Configure each attribute for faceting in the Algolia index.

Users can select multiple values per facet. DocSearch combines values of the same facet with OR and different facets with AND when it builds facetFilters for each index. A selection replaces the index's configured facetFilters entries for that facet key and keeps entries for other keys. DocSearch also replaces a configured OR group, such as ['docusaurus_tag:default', 'docusaurus_tag:docs-default-current'], when the user has a selection for every key in the group.

`theme`

type: 'light' | 'dark' | optional

Theme written to document.documentElement.dataset.theme. By default, DocSearch doesn't change the current theme.

`placeholder`

type: string | optional

Search input placeholder. The active experience supplies the default.

`maxResultsPerGroup`

type: number | optional

Maximum results to show in each result group.

`transformItems`

type: (items: DocSearchHit[]) => DocSearchHit[] | optional

Transforms hits before DocSearch groups and renders them. Defaults to the identity function.

`hitComponent`

type: ({ hit, children }: HitComponentProps) => JSX.Element | optional

Renders one result link. The default component renders the standard result content.

tsx title="hit.tsx"
function Hit({ hit, children }: HitComponentProps): JSX.Element {
  return (
    <a href={hit.url} data-result-type={hit.type}>
      {children}
    </a>
  );
}

Preserve children to retain the default hit content. hit is an InternalDocSearchHit | StoredDocSearchHit.

`resultsFooterComponent`

type: ({ state }: ResultsFooterComponentProps) => JSX.Element | null | optional

Renders below result collections. It receives the current Autocomplete state. By default, DocSearch doesn't render a footer.

`footerAction`

type: React.ReactNode | optional

Renders a custom element in the modal footer, before the "Powered by Algolia" logo. Passing null renders nothing.

tsx title="search.tsx"
function FooterAction(): JSX.Element {
  return (
    <a href="https://algolia.com">
      Our other project
    </a>
  );
}

function Search() {
  return (
    <DocSearch
      // ...
      footerAction={<FooterAction />}
    />
  );
}

`transformSearchClient`

type: (client: SearchClient) => SearchClient | optional

Wraps or replaces the Algolia search client. Defaults to the identity function.

`disableUserPersonalization`

type: boolean | optional

Disables recent searches, favorites, and stored AI conversations. Defaults to false.

`initialQuery`

type: string | optional

Query to place in the input when the modal opens. Defaults to an empty string.

type: AutocompleteOptions['navigator'] | optional

Autocomplete navigation implementation. Defaults to the Autocomplete navigator.

`translations`

type: DocSearchTranslations | optional

Overrides button and modal text. Defaults to English strings.

DocSearchTranslations groups overrides under button and modal. Modal groups include searchBox, footer, facets, errorScreen, startScreen, noResultsScreen, and resultsScreen. DocSearchAI also supports askAiScreen and newConversation.

tsx title="search.tsx"
<DocSearch
  translations={{
    button: {
      buttonText: 'Search API docs',
      buttonAriaLabel: 'Search API docs',
    },
    modal: {
      searchBox: {
        placeholderText: 'Search API docs',
      },
      facets: {
        clearAllLabel: 'Reset filters',
      },
    },
  }}
/>

`getMissingResultsUrl`

type: ({ query }: { query: string }) => string | optional

Builds the no-results report URL.

`insights`

type: AutocompleteOptions['insights'] | optional

Configures Algolia Insights. Defaults to false.

`portalContainer`

type: DocumentFragment | Element | optional

Element that receives the modal portal. Defaults to document.body.

`recentSearchesLimit`

type: number | optional

Maximum recent searches when the user has no favorites. Defaults to 7.

`recentSearchesWithFavoritesLimit`

type: number | optional

Maximum recent searches when the user has favorites. Defaults to 4.

`keyboardShortcuts`

type: DocSearchModalShortcuts | optional

Enables Ctrl/Cmd+K and / to open the modal. Both shortcuts are enabled by default. Escape always closes the modal.

`resultBadgeKey`

type: string | optional

Property path for a value on each hit. Paths support dot and array-index notation, such as hierarchy.lvl1, tags[2], and tags.2.

Add custom properties to attributesToRetrieve:

tsx title="search.tsx"
<DocSearch
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={[
    {
      name: 'docs',
      searchParameters: {
        attributesToRetrieve: ['hierarchy.lvl0', 'content', 'url', 'version'],
      },
    },
  ]}
  resultBadgeKey="version"
/>

Primitive values render as text and arrays of primitives render as a comma-separated list. Set translations.modal.resultsScreen.resultBadgeLabelText to replace the default screen-reader label, Category.

Ask AI props

`askAi`

type: string | DocSearchAskAi | required

Agent Studio assistant ID or configuration. This prop is required by DocSearchAI.

`agentId`

type: string | required

Agent Studio agent ID.

`appId`

type: string | optional

Application ID for Agent Studio. Defaults to the root appId.

`apiKey`

type: string | optional

API key for Agent Studio. Defaults to the root apiKey.

`suggestedQuestions`

type: boolean | optional

Shows published assistant questions on the new-conversation screen. Defaults to false.

`searchParameters`

type: AgentStudioSearchParameters | optional

Search parameters keyed by index name. Each value supports filters, attributesToRetrieve, restrictSearchableAttributes, and distinct.

tsx title="search.tsx"
<DocSearchAI
  askAi={{
    agentId: 'YOUR_AGENT_ID',
    searchParameters: {
      docs: {
        filters: 'language:en',
        attributesToRetrieve: ['title', 'content', 'url'],
        distinct: true,
      },
    },
  }}
/>

`indices`

type: string[] | optional

Index names for the Agent Studio search tool on this request. Put descriptions and tool defaults on the agent configuration. Put per-index runtime overrides in searchParameters.

`tools`

type: ToolCalls | optional

Custom Agent Studio tool renderers and handlers. Defaults to {}. Each ToolDefinition requires render({ message }); onToolCall can handle client-side work and call addToolOutput({ output }).

`memory`

type: Memory | optional

Agent Studio memory display and user token. Memory is disabled by default. Memory.userToken is the user JWT sent to Agent Studio.

`promptSuggestions`

type: PromptSuggestions | optional

Prompt suggestions displayed with keyword results. indexName selects an index whose records contain a prompt attribute. hitsPerPage defaults to 3.

`interceptAskAiEvent`

type: (initialMessage: InitialAskAiMessage) => boolean | void | optional

Runs before DocSearch starts an Ask AI request. Return true to prevent the modal from toggling or sending the message. Use it to route Ask AI to another view.

`DocSearchRef`

Ref interface for DocSearch and DocSearchAI.

`isReady`

type: readonly boolean

Whether the provider is mounted.

`isOpen`

type: readonly boolean

Whether the modal is open.

`isSidepanelOpen`

type: readonly boolean

Whether the registered Sidepanel is open.

`isSidepanelSupported`

type: readonly boolean

Whether a Sidepanel is registered and the viewport isn't mobile.

`open`

type: () => void

Opens keyword search.

`close`

type: () => void

Closes the modal.

`openAskAi`

type: (initialMessage?: InitialAskAiMessage) => void

Opens Ask AI in the Sidepanel when hybrid mode is available, or in the modal otherwise.

`openSidepanel`

type: (initialMessage?: InitialAskAiMessage) => void

Opens a registered Sidepanel. Does nothing when no Sidepanel is registered.

InitialAskAiMessage requires query and can include messageId or suggestedQuestionId.

Compatibility and deprecations

  • react, react-dom, and @types/react support versions >=16.8.0 <20.0.0.
  • search-insights supports versions >=1 <3 and is optional.
  • The browser build targets ES2017.
  • UseDocSearchKeyboardEventsProps.onInput and searchButtonRef remain accepted for compatibility but are deprecated.
  • DocSearch is keyword-only in v5. Use DocSearchAI for Ask AI.

Package exports

The root package exports DocSearch, DocSearchAI, DocSearchAskAiModal, DocSearchButton, DocSearchModal, useDocSearchKeyboardEvents, version, and public types.

Import Export
@docsearch/react/askaiModal DocSearchAskAiModal
@docsearch/react/button DocSearchButton
@docsearch/react/docsearch DocSearch - Search only
@docsearch/react/docsearchAi DocSearchAI and AI types
@docsearch/react/modal DocSearchModal
@docsearch/react/sidepanel DocSearchSidepanel and Sidepanel components
@docsearch/react/sidepanelButton SidepanelButton, SidepanelButtonProps, SidepanelButtonTranslations, and ButtonVariant
@docsearch/react/sidepanelPanel Sidepanel, SidepanelProps, SidepanelRef, and SidepanelTranslations - panel only, without the button
@docsearch/react/useDocSearchKeyboardEvents useDocSearchKeyboardEvents
@docsearch/react/useTheme useTheme
@docsearch/react/version version

For provider and modal composition, see Composable API. For modal and Sidepanel composition, see hybrid mode.

Style exports

Import @docsearch/css for the complete modal stylesheet. The React package also exports @docsearch/react/style and split style/variables, style/button, style/modal, style/askai, and style/sidepanel entries for component-level builds. See Styling.


Packages Website Docs Packages React Examples (`packages/website/docs/packages/react/examples.mdx`)


title: React examples

These examples build on the React getting started guide. Replace all placeholder credentials before using them.

Search multiple indices

Pass strings or per-index objects. Results follow the array order.

jsx title="multiindexsearch.jsx"
<DocSearch
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={[
    {
      name: 'product_docs',
      searchParameters: {
        facetFilters: ['language:en'],
      },
    },
    'api_reference',
  ]}
/>

Add facet filters

Configure the attributes for faceting in Algolia, then expose up to five controls:

jsx title="facetedsearch.jsx"
<DocSearch
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['product_docs']}
  facets={[
    { key: 'language', label: 'Language' },
    { key: 'version', label: 'Version' },
  ]}
/>

DocSearch loads available values from all configured indices. When a user selects values, DocSearch replaces each index's configured facetFilters entries for that facet key with the selection and keeps entries for other keys. Users can select multiple values per facet. DocSearch combines them with OR, for example [['language:en', 'language:fr'], 'version:v2'].

Show a result badge

Retrieve the property and pass its path to resultBadgeKey:

jsx title="resultbadgesearch.jsx"
<DocSearch
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={[
    {
      name: 'product_docs',
      searchParameters: {
        attributesToRetrieve: [
          'hierarchy.lvl0',
          'hierarchy.lvl1',
          'hierarchy.lvl2',
          'hierarchy.lvl3',
          'hierarchy.lvl4',
          'hierarchy.lvl5',
          'hierarchy.lvl6',
          'content',
          'type',
          'url',
          'version',
        ],
      },
    },
  ]}
  resultBadgeKey="version"
  translations={{
    modal: {
      resultsScreen: {
        resultBadgeLabelText: 'Version',
      },
    },
  }}
/>

Nested paths such as hierarchy.lvl1 and tags[2] also work.

Use hitComponent to change the link while preserving DocSearch's result content:

jsx title="searchhit.jsx"
function SearchHit({ hit, children }) {
  return (
    <a
      href={hit.url}
      data-index={hit.__autocomplete_indexName}
      onClick={() => console.info('Opened result', hit.objectID)}
    >
      {children}
    </a>
  );
}

<DocSearch
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['product_docs']}
  hitComponent={SearchHit}
/>;

Use the Autocomplete state to show query-level information:

jsx title="resultsfooter.jsx"
function ResultsFooter({ state }) {
  const count = state.context.nbHits ?? 0;

  return <p>{count} matching records</p>;
}

<DocSearch
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['product_docs']}
  resultsFooterComponent={ResultsFooter}
/>;

Transform results

Return the hits in the order you want DocSearch to group and render them:

jsx title="transformedsearch.jsx"
<DocSearch
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['product_docs']}
  transformItems={(items) =>
    items.filter((item) => item.hierarchy.lvl0 !== 'Archived')
  }
/>

Open search from another control

tsx title="searchtrigger.tsx"
import { useRef } from 'react';
import { DocSearch, type DocSearchRef } from '@docsearch/react';

function Search() {
  const searchRef = useRef<DocSearchRef>(null);

  return (
    <>
      <button type="button" onClick={() => searchRef.current?.open()}>
        Search documentation
      </button>
      <DocSearch
        ref={searchRef}
        appId="YOUR_APP_ID"
        apiKey="YOUR_SEARCH_API_KEY"
        indices={['product_docs']}
      />
    </>
  );
}

Add Agent Studio search parameters

Use DocSearchAI. Key Ask AI search parameters by index name:

jsx title="askaisearch.jsx"
<DocSearchAI
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['product_docs']}
  askAi={{
    assistantId: 'YOUR_ASSISTANT_ID',
    searchParameters: {
      product_docs: {
        filters: 'language:en AND version:v5',
        attributesToRetrieve: ['title', 'content', 'url'],
        restrictSearchableAttributes: ['title', 'content'],
        distinct: true,
      },
    },
  }}
/>

See Get started with Agent Studio before configuring the component.

Add dynamic Agent Studio indices

Pass the index names Agent Studio should search for this request:

jsx title="dynamicindicessearch.jsx"
const askAi = {
  agentId: 'YOUR_ASSISTANT_ID',
  indices: ['product_docs', 'api_reference'],
  searchParameters: {
    product_docs: {
      filters: 'language:en',
    },
  },
};

<DocSearchAI
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['product_docs', 'api_reference']}
  askAi={askAi}
/>;

Define stable objects outside the component, or memoize them, when they contain tools.

Add prompt suggestions

Show matching prompts next to keyword results:

jsx title="promptsuggestionssearch.jsx"
<DocSearchAI
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['product_docs']}
  askAi={{
    assistantId: 'YOUR_ASSISTANT_ID',
    suggestedQuestions: true,
    promptSuggestions: {
      indexName: 'docsearch_prompt_suggestions',
      hitsPerPage: 3,
    },
  }}
/>

suggestedQuestions shows published assistant questions on a new conversation. promptSuggestions searches your prompt index while the user types a keyword query.

Route Ask AI to another view

Return true from interceptAskAiEvent after handling the message:

jsx title="interceptaskai.jsx"
<DocSearchAI
  appId="YOUR_APP_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  indices={['product_docs']}
  askAi="YOUR_ASSISTANT_ID"
  interceptAskAiEvent={(initialMessage) => {
    openCustomAssistant(initialMessage);
    return true;
  }}
/>

For the supported modal and Sidepanel integration, use hybrid mode.

Lazy-load the Sidepanel

Import the trigger from @docsearch/react/sidepanelButton, then dynamically import Sidepanel from @docsearch/react/sidepanelPanel. The button entry excludes the panel and its Ask AI dependencies. Dynamically importing the panel entry defers those dependencies until needed.

Don't statically import the button from @docsearch/react/sidepanel when you need this boundary. Tree shaking depends on the bundler: a production Bun build with both a static button import and a dynamic panel import from the shared @docsearch/react/sidepanel entry includes the AI SDK and Markdown renderer in the initial chunks. Using the dedicated sidepanelButton/sidepanelPanel entries keeps those dependencies deferred and avoids bundling the button twice.

text
/* Detailed source-code truncated for AI context efficiency. */

Hover, focus, and touch start preload the module without opening the panel. Activation also loads it if preloading hasn't finished. This example disables the global shortcut because the panel's keyboard listener isn't mounted before activation, and unmounts the panel on close. To preserve an in-progress conversation, keep it mounted after the first activation and control visibility with isOpen.

For provider-based composition, @docsearch/sidepanel/button also uses the lightweight trigger entry. Keep the panel mounted when you need provider refs, keyboard shortcuts, or hybrid handoff before a user activates the trigger.


Packages Website Docs Packages Sidepanel Js Api (`packages/website/docs/packages/sidepanel-js/api.mdx`)


title: Sidepanel JS API reference toc_max_heading_level: 2

`sidepanel`

ts
function sidepanel(props: SidepanelProps): SidepanelInstance;

The function resolves container, mounts the component, and returns immediately. Use onReady or instance.isReady to detect the mounted state.

Mounting props

`container`

type: HTMLElement | string | required

Element or CSS selector that receives the Sidepanel application.

`environment`

type: typeof window | optional

Environment used to resolve a selector. Defaults to the browser window. A selector without a browser environment throws.

The function throws if a selector doesn't match an element.

Connection props

`appId`

type: string | required

Algolia application ID.

`apiKey`

type: string | required

Public API key with search permission.

`agentId`

type: string | required

Agent Studio agent ID.

UI props

`theme`

type: 'light' | 'dark' | optional

Sets data-theme on the document root while mounted.

`keyboardShortcuts`

type: { 'Ctrl/Cmd+I'?: boolean } | optional

Enables or disables the Sidepanel shortcut. The shortcut is enabled by default.

`button`

type: SidepanelButtonProps | optional

Configures the built-in button. Defaults to {}.

button accepts variant: 'floating' | 'inline' and translations.buttonText or translations.buttonAriaLabel.

`panel`

type: SidepanelPanelProps | optional

Configures layout, suggested questions, and translations. Defaults to {}.

panel accepts variant, side, pushSelector, width, expandedWidth, portalContainer, suggestedQuestions, translations, tools, memory, and indices. Panel-level tools, memory, and indices override their root values. Don't set panel.keyboardShortcuts; configure shortcuts at the root.

Callbacks

`onReady`

type: () => void | optional

Runs once after the component mounts.

`onOpen`

type: () => void | optional

Runs when the Sidepanel opens.

`onClose`

type: () => void | optional

Runs when the Sidepanel closes.

Use these Sidepanel-specific callbacks rather than the inherited React provider callback names.

Agent Studio options

`tools`

type: Record<string, ToolDefinition> | optional

Handles and renders custom Agent Studio tools. Defaults to {}.

`memory`

type: { enabled?: boolean; userToken?: string } | optional

Configures memory-tool rendering and authentication.

`indices`

type: string[] | optional

Index names available to Agent Studio. Put descriptions and tool defaults on the agent configuration. Put per-index runtime overrides in searchParameters.

These fields are root props:

js title="load-sidepanel.js"
const assistant = sidepanel({
  container: '#docsearch-sidepanel',
  appId: 'YOUR_APPLICATION_ID',
  apiKey: 'YOUR_SEARCH_API_KEY',
  agentId: 'YOUR_AGENT_ID',
  memory: {
    enabled: true,
    userToken: userMemoryToken,
  },
  indices: ['docs', 'support_articles'],
  searchParameters: {
    docs: { filters: 'version:v5' },
    support_articles: { filters: 'visibility:public' },
  },
  tools: {
    getReleaseChannel: {
      async onToolCall({ input, addToolOutput }) {
        const channel = await readReleaseChannel(input);
        await addToolOutput({ output: { channel } });
      },
      render({ message }) {
        return `Release channel: ${message.output.channel}`;
      },
    },
  },
});

ToolDefinition requires render({ message: { input, output } }), which returns a string. It can also define onToolCall and translations.callingToolText. If you handle a client-side tool, call addToolOutput.

Generate memory.userToken on your server. The package sends it as x-algolia-secure-user-token.

`SidepanelInstance`

Calls to open and close before the internal ref is ready are no-ops.

InitialAskAiMessage is:

ts title="types.ts"
type InitialAskAiMessage = {
  query: string;
  messageId?: string;
  suggestedQuestionId?: string;
};

`isReady`

type: readonly boolean

Whether the component is mounted.

`isOpen`

type: readonly boolean

Whether the panel is open.

`open`

type: (initialMessage?: InitialAskAiMessage) => void

Opens the panel, optionally with a question or stored-message IDs.

`close`

type: () => void

Closes the panel.

`destroy`

type: () => void

Unmounts the component and marks the instance not ready.

Exports

@docsearch/sidepanel-js has one value export: the default sidepanel function.

It also exports the SidepanelProps, SidepanelInstance, and SidepanelCallbacks TypeScript types. It doesn't provide a named sidepanel export or package subpaths.

ts title="load-sidepanel.ts"
import sidepanel, {
  type SidepanelCallbacks,
  type SidepanelInstance,
  type SidepanelProps,
} from '@docsearch/sidepanel-js';

Packages Website Docs Packages Sidepanel Advanced Use Cases (`packages/website/docs/packages/sidepanel/advanced-use-cases.mdx`)


title: React Sidepanel advanced use cases

Push page content

Use the inline panel variant to add a margin to the first element that matches pushSelector. On screens up to 768 pixels wide, the panel overlays the page instead.

tsx title="docs.tsx"
<SidepanelButton variant="inline" />
<Sidepanel
  appId="YOUR_APPLICATION_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  agentId="YOUR_AGENT_ID"
  variant="inline"
  side="left"
  pushSelector="#documentation"
  width="24rem"
  expandedWidth="36rem"
/>

Keep pushSelector narrow enough to identify one layout container. The implementation uses the first matching element and restores its inline margin and transition when it unmounts.

Render into another container

Both the floating button and panel default to document.body. Set portalContainer on the panel and portalcontainer on the button to use another element.

tsx title="assistantportal.tsx"
const assistantRoot = document.getElementById('assistant-root');

<DocSearch>
  <SidepanelButton portalcontainer={assistantRoot} />
  <Sidepanel
    appId="YOUR_APPLICATION_ID"
    apiKey="YOUR_SEARCH_API_KEY"
    agentId="YOUR_AGENT_ID"
    portalContainer={assistantRoot}
  />
</DocSearch>;

An inline SidepanelButton renders where it appears in the React tree and doesn't use its portal container.

Control the panel with a ref

Attach a DocSearchRef to the provider. openSidepanel accepts an optional initial message.

tsx title="support.tsx"
import { DocSearch, type DocSearchRef } from '@docsearch/core';
import { Sidepanel } from '@docsearch/sidepanel';
import { useRef } from 'react';

export function Support() {
  const docsearchRef = useRef<DocSearchRef>(null);

  return (
    <DocSearch ref={docsearchRef}>
      <button
        type="button"
        onClick={() =>
          docsearchRef.current?.openSidepanel({
            query: 'How do I rotate an API key?',
          })
        }
      >
        Ask about API keys
      </button>
      <Sidepanel
        appId="YOUR_APPLICATION_ID"
        apiKey="YOUR_SEARCH_API_KEY"
        agentId="YOUR_AGENT_ID"
      />
    </DocSearch>
  );
}

Call the method after the Sidepanel has mounted and registered its view. Check isSidepanelOpen to read its open state. See Hybrid Mode for cross-view ref behavior.

Keep a controlled panel mounted

The low-level Sidepanel from @docsearch/react/sidepanel accepts isOpen, onOpen, and onClose. Unlike Sidepanel from @docsearch/sidepanel, it doesn't require a DocSearch provider. Render it on the client and keep it mounted when closed to preserve the current conversation, draft prompt, and panel state. Unmounting discards that in-memory state; saved conversation history is separate.

The component owns closed-state visibility and interaction: its stylesheet hides the panel, and the closed root is inert, excluding its descendants from keyboard navigation and the accessibility tree. Reopening restores interaction without resetting the conversation. Closing doesn't stop an active response.

The panel focuses its prompt when opened on desktop and blurs the prompt when closed. It doesn't autofocus on mobile or restore focus to your trigger. Your integration owns isOpen and focus restoration. Route close actions through a handler that returns focus to the trigger, or another appropriate element if the trigger no longer exists.

tsx title="controlledassistant.tsx"
import { Sidepanel } from '@docsearch/react/sidepanel';
import { useCallback, useRef, useState, type JSX } from 'react';
import '@docsearch/react/style';
import '@docsearch/react/style/sidepanel';

export function ControlledAssistant(): JSX.Element {
  const [isOpen, setIsOpen] = useState(false);
  const triggerRef = useRef<HTMLButtonElement>(null);
  const open = useCallback(() => setIsOpen(true), []);
  const close = useCallback(() => {
    triggerRef.current?.focus();
    setIsOpen(false);
  }, []);

  return (
    <>
      <button type="button" ref={triggerRef} aria-expanded={isOpen} onClick={open}>
        Ask AI
      </button>
      <Sidepanel
        appId="YOUR_APPLICATION_ID"
        apiKey="YOUR_SEARCH_API_KEY"
        agentId="YOUR_AGENT_ID"
        isOpen={isOpen}
        onOpen={open}
        onClose={close}
      />
    </>
  );
}

Handle Agent Studio tools

Key each client tool by the name emitted by your agent. Always return tool output through addToolOutput when you provide onToolCall.

tsx title="tools.tsx"
const tools = {
  getReleaseChannel: {
    translations: { callingToolText: 'Reading release settings' },
    async onToolCall({ input, addToolOutput }) {
      const channel = await readReleaseChannel(input);
      await addToolOutput({ output: { channel } });
    },
    render({ message }) {
      const output = message.output as { channel: string };
      return `Release channel: ${output.channel}`;
    },
  },
};

<Sidepanel
  appId="YOUR_APPLICATION_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  agentId="YOUR_AGENT_ID"
  tools={tools}
/>;

Define tools outside the component or memoize it. Tool errors don't render a tool result.

Enable memory

Pass a server-generated Agent Studio user JWT. enabled controls whether memory tool activity appears in the conversation; userToken authenticates the user's memory requests.

tsx title="memory.tsx"
<Sidepanel
  appId="YOUR_APPLICATION_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  agentId="YOUR_AGENT_ID"
  memory={{
    enabled: true,
    userToken: userMemoryToken,
  }}
/>

Don't generate or sign the token in the browser.

Provide dynamic indices

Use indices to select the indices Agent Studio can search at request time.

tsx title="dynamicindices.tsx"
<Sidepanel
  appId="YOUR_APPLICATION_ID"
  apiKey="YOUR_SEARCH_API_KEY"
  agentId="YOUR_AGENT_ID"
  searchParameters={{
    docs: { filters: 'version:v5' },
    support_articles: { filters: 'visibility:public' },
  }}
  indices={['docs', 'support_articles']}
/>

Search parameters are keyed by index name. See the Sidepanel API for the supported fields.


Packages Website Docs Packages Sidepanel Api (`packages/website/docs/packages/sidepanel/api.mdx`)


title: React Sidepanel API reference toc_max_heading_level: 2

`Sidepanel`

Render Sidepanel inside DocSearch from @docsearch/core.

Set theme on DocSearch; SidepanelProps omits it. Set lifecycle callbacks such as onSidepanelOpen and onSidepanelClose on the provider. Don't pass inherited onOpen or onClose callbacks to Sidepanel, because they replace the wrapper's state handlers.

Connection props

`appId`

type: string | required

Algolia application ID.

`apiKey`

type: string | required

Public API key with search permission.

`agentId`

type: string | required

Agent Studio agent ID.

`searchParameters`

type: Record<string, AgentStudioIndexSearchParameters> | optional

Search parameters keyed by index name.

AgentStudioIndexSearchParameters supports filters, attributesToRetrieve, restrictSearchableAttributes, and distinct.

Layout props

`variant`

type: 'floating' | 'inline' | optional

Overlays the page or pushes matching page content on desktop. Defaults to 'floating'.

`side`

type: 'left' | 'right' | optional

Sets the side from which the panel opens. Defaults to 'right'.

`pushSelector`

type: string | optional

Selects the first element pushed by the inline panel. Defaults to '#root, main, .app, body'.

`width`

type: number | string | optional

Sets the normal width. Numbers use pixels. Defaults to 360.

`expandedWidth`

type: number | string | optional

Sets the expanded width. Numbers use pixels. Defaults to 580.

`portalContainer`

type: DocumentFragment | Element | null | optional

Receives the panel portal. Defaults to document.body.

Behavior props

`keyboardShortcuts`

type: { 'Ctrl/Cmd+I'?: boolean } | optional

Enables or disables the Sidepanel shortcut. The shortcut is enabled by default.

`suggestedQuestions`

type: boolean | optional

Whether to show Agent Studio suggested questions on the new-conversation screen. Defaults to false.

`translations`

type: SidepanelTranslations | optional

Supplies partial strings for header, promptForm, conversationScreen, newConversationScreen, and logo. Defaults to {}.

`tools`

type: Record<string, ToolDefinition> | optional

Handles and renders custom Agent Studio tools. Defaults to {}.

`memory`

type: { enabled?: boolean; userToken?: string } | optional

Configures Agent Studio memory rendering and authentication.

`indices`

type: string[] | optional

Index names available to Agent Studio. Put descriptions and tool defaults on the agent configuration. Put per-index runtime overrides in searchParameters.

Translation groups

Group Keys
header title, conversationHistoryTitle, newConversationText, viewConversationHistoryText
promptForm promptPlaceholderText, promptAnsweringText, promptAskAnotherQuestionText, promptDisclaimerText, promptLabelText, promptAriaLabelText
newConversationScreen titleText, introductionText
logo poweredByText
conversationScreen Tool status, source, copy, feedback, error, disclaimer, and suggested-prompt strings exposed by ConversationScreenTranslations

Agent Studio options

V5 uses Agent Studio for Sidepanel conversations. It doesn't expose an agentStudio prop.

`ToolDefinition`

ts
type ToolDefinition = {
  render: (params: { message: { input: unknown; output: unknown } }) => string;
  onToolCall?: (params: {
    input: unknown;
    addToolOutput: (props: { output: unknown }) => Promise<void>;
    toolCallId: string;
    toolName: string;
    dynamic?: boolean;
  }) => Promise<void> | void;
  translations?: { callingToolText?: string };
};

`memory`

enabled defaults to false and controls memory-tool status rendering. userToken is sent as the x-algolia-secure-user-token header.

`SidepanelButton`

`variant`

type: 'floating' | 'inline' | optional

Renders an icon-only floating button or an inline button with text. Defaults to 'floating'.

`translations`

type: { buttonText?: string; buttonAriaLabel?: string } | optional

Changes visible and accessible text. buttonText applies to the inline variant. Defaults to the English labels.

`portalcontainer`

type: DocumentFragment | Element | null | optional

Receives the floating button portal. Defaults to document.body.

The wrapper supplies its click handler and keyboard shortcut configuration from DocSearch. An inline button renders at its position in the React tree.

Programmatic control

Sidepanel doesn't expose its lower-level SidepanelRef directly. Attach a DocSearchRef to the provider and use:

`openSidepanel`

type: (initialMessage?: InitialAskAiMessage) => void

Opens a registered Sidepanel.

`close`

type: () => void

Returns the provider to its ready state.

`isSidepanelOpen`

type: boolean

Whether the Sidepanel is open.

`isReady`

type: boolean

Whether the provider is mounted.

InitialAskAiMessage is { query: string; messageId?: string; suggestedQuestionId?: string }. See the @docsearch/core API for the full ref.

Exports

Import path Value exports Type exports
@docsearch/sidepanel Sidepanel, SidepanelButton SidepanelProps, SidepanelButtonProps
@docsearch/sidepanel/sidepanel Sidepanel SidepanelProps
@docsearch/sidepanel/button SidepanelButton SidepanelButtonProps

Import @docsearch/sidepanel/button and dynamically import @docsearch/sidepanel/sidepanel to defer the panel and its Ask AI dependencies, the same way as the React lazy-load example. Internally, these entries build on the equivalent @docsearch/react/sidepanelButton and @docsearch/react/sidepanelPanel entries, so no further split is needed.


--- METRICS ---