> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Use Algolia Experiences in a React app

> Embed an Algolia Experience in a React single-page app with a custom Hook that re-initializes on route changes.

<Callout icon="flask-conical" color="#14b8a6">
  This is a **pilot feature** according to [Algolia's Terms of Service ("Beta Services")](https://www.algolia.com/policies/terms/). Functionality may change before general availability.
</Callout>

In a React single-page app, routes change without a full page reload, so a plain `<script>` tag alone can't re-initialize the experience between routes.

This guide shows how to create a custom Hook that manages the Algolia Experiences lifecycle in your React codebase.

## Before you begin

You need:

* A React app with a client-side router that exposes the current path on navigation, such as [React Router](https://reactrouter.com/), [Remix](https://remix.run/), or [TanStack Router](https://tanstack.com/router).
* An Algolia Experience created in the dashboard. See [Get started](/doc/guides/building-search-ui/algolia-experiences/get-started).

## Declare the global type

If you use TypeScript, extend the `Window` interface so `window.AlgoliaExperiences` is typed:

```ts global.d.ts theme={"system"}
interface Window {
  AlgoliaExperiences?: { run: () => void; dispose: () => void };
}
```

## Create the Hook

Create a Hook that loads the library script on first mount, calls `run()` on later route changes, and calls `dispose()` on cleanup:

<CodeGroup>
  ```ts useAlgoliaExperiences.ts expandable theme={"system"}
  import { useEffect, useRef } from 'react';
  import { useLocation } from 'react-router-dom';

  export function useAlgoliaExperiences(opts: {
    src: string;
    appId: string;
    apiKey: string;
    experienceId: string;
  }) {
    const { pathname } = useLocation();
    const injected = useRef(false);

    useEffect(() => {
      if (!injected.current) {
        injected.current = true;
        const { src, ...params } = opts;
        const url = new URL(src);
        for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
        const script = document.createElement('script');
        script.src = url.href;
        document.head.appendChild(script);
      } else {
        window.AlgoliaExperiences?.run();
      }
      return () => window.AlgoliaExperiences?.dispose();
    }, [pathname]);
  }
  ```

  ```js useAlgoliaExperiences.js expandable theme={"system"}
  import { useEffect, useRef } from 'react';
  import { useLocation } from 'react-router-dom';

  export function useAlgoliaExperiences(opts) {
    const { pathname } = useLocation();
    const injected = useRef(false);

    useEffect(() => {
      if (!injected.current) {
        injected.current = true;
        const { src, ...params } = opts;
        const url = new URL(src);
        for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
        const script = document.createElement('script');
        script.src = url.href;
        document.head.appendChild(script);
      } else {
        window.AlgoliaExperiences?.run();
      }
      return () => window.AlgoliaExperiences?.dispose();
    }, [pathname]);
  }
  ```
</CodeGroup>

The example imports `useLocation` from React Router.
If your app uses a different router, swap it for the equivalent path Hook from that router.
The Hook only needs the current path as its effect dependency.

The Hook manages the experience lifecycle:

1. On first mount, it builds the loader URL with your credentials as query parameters and appends the script to `<head>`.
2. On later route changes, calls `run()` to remount the experience in the current page's container.
3. On unmount or before the next route change, calls `dispose()` to clean up the previous instance.

## Use the Hook in your layout

Call the Hook from a component that wraps all routes where you want the experience to appear.

<CodeGroup>
  ```tsx Layout.tsx theme={"system"}
  import { Outlet } from 'react-router-dom';
  import { useAlgoliaExperiences } from './useAlgoliaExperiences';

  function Layout() {
    useAlgoliaExperiences({
      src: 'https://cdn.jsdelivr.net/npm/@algolia/experiences/dist/experiences.js',
      appId: 'ALGOLIA_APPLICATION_ID',
      apiKey: 'ALGOLIA_SEARCH_API_KEY',
      experienceId: 'EXPERIENCE_ID',
    });

    return <Outlet />;
  }
  ```

  ```jsx Layout.jsx theme={"system"}
  import { Outlet } from 'react-router-dom';
  import { useAlgoliaExperiences } from './useAlgoliaExperiences';

  function Layout() {
    useAlgoliaExperiences({
      src: 'https://cdn.jsdelivr.net/npm/@algolia/experiences/dist/experiences.js',
      appId: 'ALGOLIA_APPLICATION_ID',
      apiKey: 'ALGOLIA_SEARCH_API_KEY',
      experienceId: 'EXPERIENCE_ID',
    });

    return <Outlet />;
  }
  ```
</CodeGroup>

Make sure the container element configured in the editor (for example, `<div id="autocomplete" />`) renders on the pages where the experience should appear.

## Next steps

* Verify the experience renders on every route, including after browser back and forward navigation.
* Check the [troubleshooting guide](/doc/guides/building-search-ui/algolia-experiences/troubleshooting) for content security policy directives and common issues.
