Skip to main content

How to Add Algolia Search to Your Website

·APIScout Team
algoliasearch apiinstantsearchtutorialapi integration

How to Add Algolia Search to Your Website

Algolia delivers search results in under 50ms. This guide covers the full integration: indexing your data, building a search UI with InstantSearch, adding filters and facets, and tracking search analytics.

What You'll Build

  • Full-text search with typo tolerance and highlighting
  • Faceted filtering (category, price range, tags)
  • Search-as-you-type with instant results
  • Search analytics (what users search for, no-result queries)

Prerequisites: React 18+ or Next.js 14+, Algolia account (free: 10K searches/month).

1. Setup

Install

npm install algoliasearch react-instantsearch

Get Your Credentials

From the Algolia Dashboard:

  • Application ID — identifies your app
  • Search-Only API Key — safe for client-side (read-only)
  • Admin API Key — for indexing (server-side only)

Environment Variables

# .env.local
NEXT_PUBLIC_ALGOLIA_APP_ID=YOUR_APP_ID
NEXT_PUBLIC_ALGOLIA_SEARCH_KEY=your_search_only_key
ALGOLIA_ADMIN_KEY=your_admin_key  # Server-side only

2. Index Your Data

Push Data to Algolia

// scripts/index-data.ts
import algoliasearch from 'algoliasearch';

const client = algoliasearch(
  process.env.NEXT_PUBLIC_ALGOLIA_APP_ID!,
  process.env.ALGOLIA_ADMIN_KEY!
);

const index = client.initIndex('products');

const products = [
  {
    objectID: '1',
    name: 'React Query',
    description: 'Powerful data fetching for React',
    category: 'Data Fetching',
    stars: 38000,
    tags: ['react', 'data', 'cache'],
  },
  {
    objectID: '2',
    name: 'Zustand',
    description: 'Small, fast state management',
    category: 'State Management',
    stars: 42000,
    tags: ['react', 'state', 'lightweight'],
  },
  // ... more records
];

// Push records to Algolia
await index.saveObjects(products);
console.log('Indexed', products.length, 'records');

Configure Index Settings

await index.setSettings({
  // Which fields to search
  searchableAttributes: ['name', 'description', 'tags'],

  // Which fields to use as filters
  attributesForFaceting: ['category', 'tags', 'filterOnly(stars)'],

  // Custom ranking (Algolia handles relevance, you add business logic)
  customRanking: ['desc(stars)'],

  // Highlighting
  highlightPreTag: '<mark>',
  highlightPostTag: '</mark>',
});

Keep Data in Sync

For real-time sync, update Algolia when your database changes:

// When a product is created/updated
await index.saveObject({
  objectID: product.id,
  name: product.name,
  description: product.description,
  category: product.category,
  stars: product.stars,
  tags: product.tags,
});

// When a product is deleted
await index.deleteObject(product.id);

3. Basic Search UI

InstantSearch Provider

// components/SearchProvider.tsx
'use client';
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch } from 'react-instantsearch';

const searchClient = algoliasearch(
  process.env.NEXT_PUBLIC_ALGOLIA_APP_ID!,
  process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY!
);

export function SearchProvider({ children }: { children: React.ReactNode }) {
  return (
    <InstantSearch searchClient={searchClient} indexName="products">
      {children}
    </InstantSearch>
  );
}

Search Box + Results

// components/Search.tsx
'use client';
import {
  SearchBox,
  Hits,
  Highlight,
  Stats,
  Pagination,
} from 'react-instantsearch';

function HitComponent({ hit }: { hit: any }) {
  return (
    <article>
      <h3>
        <Highlight attribute="name" hit={hit} />
      </h3>
      <p>
        <Highlight attribute="description" hit={hit} />
      </p>
      <span className="category">{hit.category}</span>
      <span className="stars">⭐ {hit.stars.toLocaleString()}</span>
    </article>
  );
}

export function Search() {
  return (
    <div>
      <SearchBox
        placeholder="Search APIs..."
        classNames={{
          input: 'search-input',
          submit: 'search-submit',
        }}
      />
      <Stats />
      <Hits hitComponent={HitComponent} />
      <Pagination />
    </div>
  );
}

Full Page

// app/search/page.tsx
import { SearchProvider } from '@/components/SearchProvider';
import { Search } from '@/components/Search';

export default function SearchPage() {
  return (
    <SearchProvider>
      <h1>Search APIs</h1>
      <Search />
    </SearchProvider>
  );
}

4. Faceted Filtering

Add sidebar filters for categories, tags, and numeric ranges:

// components/SearchWithFilters.tsx
'use client';
import {
  SearchBox,
  Hits,
  RefinementList,
  RangeInput,
  ClearRefinements,
  CurrentRefinements,
  Highlight,
  Pagination,
} from 'react-instantsearch';

export function SearchWithFilters() {
  return (
    <div className="search-layout">
      <aside className="filters">
        <ClearRefinements />
        <CurrentRefinements />

        <h3>Category</h3>
        <RefinementList attribute="category" />

        <h3>Tags</h3>
        <RefinementList
          attribute="tags"
          limit={10}
          showMore
          searchable
          searchablePlaceholder="Search tags..."
        />

        <h3>Minimum Stars</h3>
        <RangeInput attribute="stars" />
      </aside>

      <main className="results">
        <SearchBox placeholder="Search..." />
        <Hits hitComponent={HitComponent} />
        <Pagination />
      </main>
    </div>
  );
}

5. Autocomplete / Search-as-You-Type

For a dropdown autocomplete experience:

'use client';
import { useState, useEffect } from 'react';
import algoliasearch from 'algoliasearch/lite';

const searchClient = algoliasearch(
  process.env.NEXT_PUBLIC_ALGOLIA_APP_ID!,
  process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY!
);
const index = searchClient.initIndex('products');

export function Autocomplete() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState<any[]>([]);

  useEffect(() => {
    if (query.length < 2) {
      setResults([]);
      return;
    }

    const search = async () => {
      const { hits } = await index.search(query, {
        hitsPerPage: 5,
        attributesToRetrieve: ['name', 'category'],
      });
      setResults(hits);
    };

    const debounce = setTimeout(search, 200);
    return () => clearTimeout(debounce);
  }, [query]);

  return (
    <div className="autocomplete">
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search APIs..."
      />
      {results.length > 0 && (
        <ul className="suggestions">
          {results.map((hit) => (
            <li key={hit.objectID}>
              <a href={`/api/${hit.objectID}`}>
                {hit.name} <span className="category">{hit.category}</span>
              </a>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

6. Search Analytics

Track what users search for and improve results:

Enable Analytics

await index.setSettings({
  enableAnalytics: true,
});

Click Analytics

Track which results users click:

import { createInsightsMiddleware } from 'instantsearch.js/es/middlewares';
import { Hits, Configure } from 'react-instantsearch';

// In your InstantSearch component
<Configure clickAnalytics />

// In your hit component, send click events
function HitComponent({ hit, sendEvent }: { hit: any; sendEvent: Function }) {
  return (
    <article onClick={() => sendEvent('click', hit, 'Product Clicked')}>
      <h3>{hit.name}</h3>
    </article>
  );
}

Dashboard Metrics

Algolia's dashboard shows:

  • Top searches — what users search for most
  • No-result searches — queries that return nothing (add synonyms or content)
  • Click-through rate — are users finding what they need?
  • Click position — do users click result #1 or scroll to #10?

Pricing

TierSearches/MonthRecordsPrice
Free10,00010,000$0
Build10,000100,000$0 (included)
Grow10,000100,000From $0 (usage-based)
PremiumCustomUnlimitedCustom

Overage: $1 per additional 1,000 search requests.

Common Mistakes

MistakeImpactFix
Indexing too many fieldsSlow search, higher costsOnly index searchable fields
Not configuring searchable attributesPoor relevanceSet searchableAttributes with priority order
Exposing admin key to clientData can be deletedUse search-only key in browser
Not handling empty statesUsers see blank pageShow "No results" with suggestions
Stale index dataSearch shows deleted/outdated itemsSync on create/update/delete

Adding search to your app? Compare Algolia vs Meilisearch vs Typesense on APIScout — pricing, performance, and ease of integration.

Comments