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

# middleware

> Adds custom logic to your InstantSearch.js apps.

<div className="not-prose algolia-flavor-switcher">
  <div className="afs-dropdown">
    <div className="afs-trigger" role="button" tabIndex="0" aria-haspopup="listbox">
      <span className="afs-current">JavaScript</span>

      <svg className="afs-chevron lucide lucide-chevron-down" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
        <path d="m6 9 6 6 6-6" />
      </svg>
    </div>

    <ul className="afs-menu" role="listbox">
      <li role="option" aria-selected="true"><a className="afs-option is-current" href="/doc/api-reference/widgets/middleware/js"><span className="afs-option-name">JavaScript</span><span className="afs-option-lib">InstantSearch.js</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/api-reference/widgets/middleware/react"><span className="afs-option-name">React</span><span className="afs-option-lib">React InstantSearch</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/api-reference/widgets/middleware/vue"><span className="afs-option-name">Vue</span><span className="afs-option-lib">Vue InstantSearch</span></a></li>
    </ul>
  </div>
</div>

```ts Signature theme={"system"}
function middleware({ instantSearchInstance }) {
  return {
    onStateChange({ uiState }) {},
    subscribe() {},
    unsubscribe() {},
  };
}
const search = instantsearch({
  // ...
});
search.use(middleware);
```

## About this widget

Middleware is a function that returns an object with [`onStateChange`](#param-on-state-change),
[`subscribe`](#param-subscribe),
and [`unsubscribe`](#param-unsubscribe) functions.

The `middleware` function doesn't perform any actions itself but lets you inject logic into InstantSearch.js,
for example, [sending events to Google Analytics](/doc/guides/building-search-ui/going-further/integrate-google-analytics/js).
To [send Algolia click and conversion events](/doc/guides/building-search-ui/events/js),
use the [`insights`](/doc/api-reference/widgets/insights/js) middleware.

### Requirements

* [InstantSearch.js](https://github.com/algolia/instantsearch) v4.8.3 or later.

## Examples

```js JavaScript icon=code theme={"system"}
function middleware({ instantSearchInstance }) {
  return {
    onStateChange({ uiState }) {
      // Do something with `uiState` whenever the state changes.
    },
    subscribe() {
      // Do something when the InstantSearch instance starts.
    },
    unsubscribe() {
      // Do something when the InstantSearch instance is disposed of.
    },
  };
}

// Declare your instantSearch instance normally
const search = instantsearch({
  // ...
});

// Use your middleware function
search.use(middleware);
```

## Options

<ParamField body="instantSearchInstance" type="object" required>
  You have access to [the instance of `instantsearch`](/doc/api-reference/widgets/instantsearch/js)
  which lets you read values from the instance or call instance methods like `addWidgets`, `setUiState`, and `refresh`.

  ```js JavaScript icon=code theme={"system"}
  function middleware({ instantSearchInstance }) {
    return {
      onStateChange({ uiState }) {
        // ...
      },
      subscribe() {
        // ...
      },
      unsubscribe() {
        // ...
      },
    };
  }
  ```
</ParamField>

## Hooks

<ParamField body="onStateChange" type="({ uiState }) => void" required>
  The function is called with [`uiState`](/doc/api-reference/widgets/ui-state/js) whenever the state changes.

  ```js JavaScript icon=code theme={"system"}
  function middleware({ instantSearchInstance }) {
    return {
      // ...
      onStateChange({ uiState }) {
        const indexName = "<your-index-name>";
        const { query } = uiState[indexName];
        const title = document.querySelector("<your-selector>");
        title.innerText = query ? `Query: ${query}` : `No query`;
      },
    };
  }
  ```
</ParamField>

<ParamField body="subscribe" type="() => void" required>
  This function is called when the InstantSearch instance starts (when `search.start()` is called).
  This is where you can add event listeners, subscribe to an API, and run any side effects.

  ```js JavaScript icon=code theme={"system"}
  function middleware({ instantSearchInstance }) {
    let subscription;
    let listener;

    return {
      // ...
      subscribe() {
        subscription = someAPI.subscribe();

        listener = (event) => {
          // do something
        };
        document
          .querySelector("<your-selector>")
          .addEventListener("click", listener);
      },
    };
  }
  ```
</ParamField>

<ParamField body="unsubscribe" type="() => void" required>
  The function is called when the InstantSearch instance is disposed of.
  You can clean up anything you initiated in the `subscribe` function.

  ```js JavaScript icon=code theme={"system"}
  function middleware({ instantSearchInstance }) {
    let subscription;
    let listener;

    return {
      // ...
      unsubscribe() {
        subscription.unsubscribe();

        document
          .querySelector("<your-selector>")
          .removeEventListener("click", listener);
      },
    };
  }
  ```
</ParamField>
