close
Skip to main content

Documentation Index

Fetch the complete documentation index at: https://algolia.com/llms.txt

Use this file to discover all available pages before exploring further.

This quickstart walks through the main building blocks of an Algolia app:
  • Create an index, which is the searchable version of your data.
  • Build an interface that helps users find what they need.
  • Configure relevance and ranking, so the most useful results appear first.
This quickstart builds a React app that searches a sample product catalog, filters by product type, and paginates results.

Before you begin

Make sure you have:

Set up your app and index sample data

Set up your project and index a sample product dataset. In Algolia, the way you structure and configure your index affects both the search experience and how results are ranked.
1

Create a Vite app

Create a new Vite app with React and TypeScript.
npm create vite@latest algolia-quickstart-products -- --template react-ts --no-interactive
cd algolia-quickstart-products
2

Install dependencies

Install the packages for indexing and search:
  • algoliasearch sends data to Algolia.
  • react-instantsearch builds the search UI.
  • instantsearch.css provides base styles.
  • tsx runs the indexing script.
  • ora shows progress in the terminal while the script runs.
npm install algoliasearch instantsearch.css react-instantsearch ora tsx
3

Add your Algolia credentials

In the Algolia dashboard, open the API Keys page and copy these values:
  • Application ID. Identifies your Algolia application.
  • Write API key. Used by the indexing script to update records and index settings.
  • Search API key. Used by the React app to query the index from the browser.
Create a .env.local file and add the values to it:
.env.local
VITE_ALGOLIA_APPLICATION_ID=
ALGOLIA_WRITE_API_KEY=
VITE_ALGOLIA_SEARCH_API_KEY=
Keep your Write API key secret. Don’t commit .env.local to version control or expose the write key in your app.
4

Create the indexing script

Create a scripts directory and a scripts/indexing.ts file.
mkdir scripts && touch scripts/indexing.ts
This script loads your credentials, fetches a sample product dataset, uploads those products as records to Algolia with saveObjects, and adds product_type as a facet with setSettings so your UI can filter results.Run this script once to create and configure the index before connecting it to your UI. Since indexing operations are asynchronous, waitForTasks and waitForTask make sure the records and settings are applied before the script exits.
scripts/indexing.ts
import { algoliasearch } from "algoliasearch";
import ora from "ora";
import { loadEnv } from "vite";

const env = loadEnv(process.env.MODE ?? "dev", process.cwd(), "");

const appId = env.VITE_ALGOLIA_APPLICATION_ID;
const writeApiKey = env.ALGOLIA_WRITE_API_KEY;
const indexName = "quickstart-products";

if (!appId) {
  throw new Error("Missing VITE_ALGOLIA_APPLICATION_ID environment variable.");
}

if (!writeApiKey) {
  throw new Error("Missing ALGOLIA_WRITE_API_KEY environment variable.");
}

const client = algoliasearch(appId, writeApiKey);
const spinner = ora();

async function indexProducts() {
  spinner.start("Fetching the products dataset...");

  const response = await fetch(
    "https://dashboard.algolia.com/api/1/sample_datasets?type=apparel",
  );

  if (!response.ok) {
    throw new Error(
      `Error fetching products dataset: ${response.status} ${response.statusText}`,
    );
  }

  const products = await response.json();

  spinner.text = `Indexing ${products.length.toLocaleString()} products into ${indexName}...`;

  await client.saveObjects({
    indexName,
    objects: products,
    waitForTasks: true,
  });

  spinner.text = `Add facet to ${indexName}...`;

  const { taskID } = await client.setSettings({
    indexName,
    indexSettings: {
      attributesForFaceting: ["product_type"],
    },
  });

  await client.waitForTask({ indexName, taskID });
}

try {
  await indexProducts();
  spinner.succeed("Successfully indexed products.");
} catch (error) {
  spinner.fail("Indexing failed.");
  console.error(error);
  process.exitCode = 1;
}
5

Index the sample products

Add the indexing script to package.json:
npm pkg set scripts.index:products="tsx scripts/indexing.ts"
Run the script to create the quickstart-products index and add the sample records.
npm run index:products
You should see the message Successfully indexed products. in your terminal. At this point, your data is ready for search and you can explore the quickstart-products index in the Algolia dashboard. In the next section, you’ll connect a React UI to this index.

Build the search UI

Connect a React UI to your quickstart-products index. React InstantSearch automatically keeps the search box, filters, and pagination in sync with the current results.
1

Connect your app to Algolia

Replace src/App.tsx with the following code to connect your app to Algolia and render a basic search interface.
src/App.tsx
import { liteClient as algoliasearch } from "algoliasearch/lite";
import type { Hit } from "instantsearch.js";
import {
  Configure,
  Highlight,
  Hits,
  InstantSearch,
  Pagination,
  PoweredBy,
  RefinementList,
  SearchBox,
  Snippet,
} from "react-instantsearch";
import "instantsearch.css/themes/reset-min.css";
import "./App.css";

const appId = import.meta.env.VITE_ALGOLIA_APPLICATION_ID;
const apiKey = import.meta.env.VITE_ALGOLIA_SEARCH_API_KEY;

const searchClient = algoliasearch(appId, apiKey);

type ProductRecord = {
  title: string;
  description: string;
  product_type: string;
  price: number;
  showcase_image: string;
};

type ProductHit = Hit<ProductRecord>;

type ProductCardProps = {
  hit: ProductHit;
};

function ProductCard({ hit }: ProductCardProps) {
  return (
    <article className="product-card">
      <div className="product-card-image">
        <img src={hit.showcase_image} alt={hit.title} />
      </div>
      <div className="product-card-body">
        <p className="product-card-type">{hit.product_type}</p>
        <h2 className="product-card-title">
          <Highlight attribute="title" hit={hit} />
        </h2>
        <p className="product-card-description">
          <Snippet attribute="description" hit={hit} />
        </p>
        <p className="product-card-price">${hit.price}</p>
      </div>
    </article>
  );
}

export default function App() {
  return (
    <InstantSearch indexName="quickstart-products" searchClient={searchClient}>
      <Configure hitsPerPage={12} />
      <div className="search-header">
        <SearchBox placeholder="Search products" />
        <PoweredBy />
      </div>

      <div className="search-body">
        <div className="filter-panel">
          <div className="filter-panel-section">
            <div className="filter-panel-section-title">Product type</div>
            <RefinementList attribute="product_type" sortBy={["count:desc"]} />
          </div>
        </div>

        <div className="search-results">
          <Hits hitComponent={ProductCard} />
          <Pagination />
        </div>
      </div>
    </InstantSearch>
  );
}
This app connects to your quickstart-products index and renders a search interface.
3

Start the app

Start the development server.
npm run dev
Open http://localhost:5173 and start searching.
You see a product grid with images, a product type filter, and a search box. As you type, the product grid updates. Matching text is highlighted in the results.
You now have a working end-to-end search:
  • Records come from the quickstart-products index you created earlier.
  • Queries from SearchBox update the results and pagination together.
  • The product_type filter works because that attribute is configured for faceting.
  • Highlight and Snippet show which parts of each record match the query.

Improve relevance and add features

Your app already returns matching products. You can improve relevance by adjusting which matches appear first.Update the existing indexSettings object in scripts/indexing.ts, then rerun npm run index:products.
scripts/indexing.ts
const { taskID } = await client.setSettings({
  indexName,
  indexSettings: {
    attributesForFaceting: ["product_type"],
    searchableAttributes: [ 
      "unordered(title)",
      "unordered(product_type)",
      "unordered(description)",
    ],
    customRanking: ["desc(units_sold)", "desc(price)"],
  },
});
This makes search results more useful by prioritizing matches in product titles and types before descriptions, then ranking similar matches by best-selling and higher-priced products.
Add features that help users understand and refine results. For example, you can add search stats, active filters, or more ways to filter results, such as filter lists, menus, and numerical filters.
If you add more filtering features, update attributesForFaceting in scripts/indexing.ts to match.
Collect events from your UI to measure engagement and support Algolia features that use behavioral data.Update the InstantSearch component in src/App.tsx:
src/App.tsx
<InstantSearch
  indexName="quickstart-products"
  searchClient={searchClient}
  insights
>
This turns on the default React InstantSearch events, including view events for hits and filter click events for RefinementList.To send click events for hits, see Send events with React InstantSearch.

What’s next

Last modified on May 13, 2026