> ## 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.

```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>
