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

# Upgrade Vue InstantSearch

> Upgrade your Vue InstantSearch version

export const UserToken = () => <Tooltip tip="A user token is a pseudonymous ID that represents an individual user across Algolia searches and events. It links queries, clicks, and conversions to a user profile, enabling user-level analytics, personalization, and recommendations." cta="User token" href=" /doc/guides/sending-events/concepts/usertoken">
    user token
  </Tooltip>;

export const SearchQuery = () => <Tooltip tip="The text users enter into a search box. In the Search API, this corresponds to the query parameter. A search query is often used with filters, facets, and other parameters, but these aren't part of the query text itself.">
    search query
  </Tooltip>;

export const Index = () => <Tooltip tip="An Algolia index is a searchable dataset that consists of records and configuration settings. These settings define how the records are searched and ranked.">
    index
  </Tooltip>;

## Upgrade event tracking

**Starting from v4.9.0, Vue InstantSearch simplifies the event tracking process with the [`insights`](/doc/api-reference/widgets/instantsearch/vue#param-insights) option.**
You no longer need to install the [`search-insights`](/doc/libraries/search-insights) library or set up the [`insights`](/doc/api-reference/widgets/insights/vue) middleware yourself.

Here are some benefits when using the [`insights`](/doc/api-reference/widgets/instantsearch/vue#param-insights) option:

* It better handles the <UserToken />. Once you set it, all search and event tracking calls include the token.
* It automatically sends default events from built-in widgets such as [`ais-refinement-list`](/doc/api-reference/widgets/refinement-list/vue), [`ais-menu`](/doc/api-reference/widgets/menu/vue), etc. You can also change the event payloads, or remove them altogether.
* It lets you send custom events from your custom widgets.
* It simplifies forwarding events to third-party trackers.

If you've been tracking events directly with [`search-insights`](/doc/libraries/search-insights) or with the [`insights`](/doc/api-reference/widgets/insights/vue) middleware, you should:

1. Upgrade Vue InstantSearch to v4.9.0 or greater
2. [Migrate](#use-the-insights-option) from using the [`insights`](/doc/api-reference/widgets/insights/vue) middleware to the [`insights`](/doc/api-reference/widgets/instantsearch/vue#param-insights) option
3. Either [update](#update-search-insights) or [remove](#remove-search-insights) the [`search-insights`](/doc/libraries/search-insights) library

### Use the Insights option

**Starting from v4.9.0, Vue InstantSearch lets you enable event tracking with the [`insights`](/doc/api-reference/widgets/instantsearch/vue#param-insights) option.** You no longer need to set up the [`insights`](/doc/api-reference/widgets/insights/vue) middleware yourself.

```vue Vue icon=code theme={"system"}
<template>
  <ais-instant-search
    :insights="true"
  >
    <!-- widgets -->
  </ais-instant-search>
</template>
```

If you had already set up the [`insights`](/doc/api-reference/widgets/insights/vue) middleware in your code, you can now remove it and move its configuration to the [`insights`](/doc/api-reference/widgets/instantsearch/vue#param-insights) option.

```diff Vue theme={"system"}
  <template>
    <ais-instant-search
-    :middlewares="middlewares"
+    :insights="insights"
    >
      <!-- widgets -->
    </ais-instant-search>
  </template>

  <script>
-  import { createInsightsMiddleware } from 'instantsearch.js/es/middlewares';

-  const insightsMiddleware = createInsightsMiddleware({
-    insightsInitParams: {
-      useCookie: false,
-    }
-  });

    export default {
      data() {
        return {
-        middlewares: [insightsMiddleware],
+        insights: {
+          insightsInitParams: {
+            useCookie: false,
+          }
+        }
        }
      },
    }
  </script>
```

### Update `search-insights`

**Starting from v4.9.0, Vue InstantSearch can load [`search-insights`](/doc/libraries/search-insights) for you so the [`insightsClient`](/doc/api-reference/widgets/insights/vue#param-insights-client) option is no longer required.**

If you prefer loading it yourself, make sure to update [`search-insights`](/doc/libraries/search-insights) to at least v2.4.0 and forward the reference to [`insights`](/doc/api-reference/widgets/instantsearch/vue#param-insights).

If you're using the UMD bundle with a `<script>` tag, make sure to update the full code snippet (not just the version):

```html HTML icon=code-xml theme={"system"}
<script>
  var ALGOLIA_INSIGHTS_SRC = "https://cdn.jsdelivr.net/npm/search-insights@2.17.3/dist/search-insights.min.js";

  !function(e,a,t,n,s,i,c){e.AlgoliaAnalyticsObject=s,e[s]=e[s]||function(){
  (e[s].queue=e[s].queue||[]).push(arguments)},e[s].version=(n.match(/@([^\/]+)\/?/) || [])[1],i=a.createElement(t),c=a.getElementsByTagName(t)[0],
  i.async=1,i.src=n,c.parentNode.insertBefore(i,c)
  }(window,document,"script",ALGOLIA_INSIGHTS_SRC,"aa");
</script>
```

If you're using a package manager, you can upgrade it to the latest version.

```sh Command line icon=square-terminal theme={"system"}
npm install search-insights
```

Now you can pass the reference to the [`insights`](/doc/api-reference/widgets/instantsearch/vue#param-insights) option.

<CodeGroup>
  ```vue UMD theme={"system"}
  <template>
    <ais-instant-search
      :insights="{
        insightsClient: window.aa
      }"
    >
      <!-- widgets -->
    </ais-instant-search>
  </template>
  ```

  ```vue Module theme={"system"}
  <template>
    <ais-instant-search
      :insights="insights"
    >
      <!-- widgets -->
    </ais-instant-search>
  </template>

  <script>
    import aa from 'search-insights';

    export default {
      data() {
        return {
          // …
          insights: {
            insightsClient: aa
          }
        }
      }
    }
  </script>
  ```
</CodeGroup>

Otherwise, you can [remove it and let Vue InstantSearch handle it for you](#remove-search-insights).

### Remove `search-insights`

**Starting from v4.9.0, Vue InstantSearch loads [`search-insights`](/doc/libraries/search-insights) for you from jsDelivr if not detected in the page.** If you've installed [`search-insights`](/doc/libraries/search-insights), you can now remove it.

If you're using the UMD bundle with a `<script>` tag, you can remove the snippet in any page that uses Vue InstantSearch:

```diff HTML icon="code=xml" theme={"system"}
- <script>
-   var ALGOLIA_INSIGHTS_SRC = "https://cdn.jsdelivr.net/npm/search-insights@2.17.3/dist/search-insights.min.js";
-
-   !function(e,a,t,n,s,v,i,c){e.AlgoliaAnalyticsObject=s,e[s]=e[s]||function(){
-   (e[s].queue=e[s].queue||[]).push(arguments)},e[s].version=(n.match(/@([^\/]+)\/?/) || [])[1],i=a.createElement(t),c=a.- getElementsByTagName(t)[0],
-   i.async=1,i.src=n,c.parentNode.insertBefore(i,c)
-   }(window,document,"script",ALGOLIA_INSIGHTS_SRC,"aa");
- </script>
```

If you're using a package manager, you can remove it from your dependencies.

```sh Command line icon=square-terminal theme={"system"}
npm uninstall search-insights
```

Then you can remove the reference to [`search-insights`](/doc/libraries/search-insights) from your code:

<CodeGroup>
  ```diff UMD theme={"system"}
  <template>
    <ais-instant-search
      :insights="{
  -     insightsClient: window.aa
      }"
    >
      <!-- widgets -->
    </ais-instant-search>
  </template>
  ```

  ```diff Module theme={"system"}
  <template>
      <ais-instant-search
        :insights="insights"
      >
        <!-- widgets -->
      </ais-instant-search>
    </template>

    <script>
  -   import aa from 'search-insights';

      export default {
        data() {
          return {
            // …
            insights: {
  -           insightsClient: aa
            }
          }
        }
      }
    </script>
  ```
</CodeGroup>

<Note>
  Vue InstantSearch loads [`search-insights`](/doc/libraries/search-insights) from the jsDelivr CDN, which requires that your site or app allows script execution from foreign resources. Check the [security best practices](/doc/guides/security/security-best-practices) for recommendations.
</Note>

## Upgrade from v3 to v4

You can use Vue InstantSearch v4 with Vue 2 and Vue 3.

### Server-side rendering

Using Vue InstantSearch v4 introduces one breaking change in the server-side rendering.

`findResultsState` in `serverPrefetch` now takes `component` and `renderToString: (app) => Promise<string>` in the first argument.

#### Vue 3

```js JavaScript icon=code theme={"system"}
import { renderToString } from '@vue/server-renderer';

// ...

serverPrefetch() {
  return this.instantsearch.findResultsState({
    component: this,
    renderToString,
  });
},
```

#### Vue 2

The renderToString function from `vue-server-renderer/basic` is callback-based.
You need to promisify it like this:

```js JavaScript icon=code theme={"system"}
import _renderToString from 'vue-server-renderer/basic';

function renderToString(app) {
  return new Promise((resolve, reject) => {
    _renderToString(app, (err, res) => {
      if (err) reject(err);
      resolve(res);
    });
  });
}

// ...

serverPrefetch() {
  return this.instantsearch.findResultsState({
    component: this,
    renderToString,
  });
},
```

### If you upgrade to Vue 3

#### Import the library

The path to import Vue InstantSearch has changed for Vue 3, and is now:

```js JavaScript icon=code theme={"system"}
import InstantSearch from "vue-instantsearch/vue3/es";

// ...
app.use(InstantSearch);
```

#### Vue Router v4

If you're using Vue Router and upgrading it to v4, [`currentRoute`](https://router.vuejs.org/api/#currentroute) is now a reference instead of an object.

```js JavaScript icon=code theme={"system"}
// previously
vueRouter.currentRoute.query;

// now
vueRouter.currentRoute.value.query;
```

It's not directly related to Vue InstantSearch,
but if you are upgrading to Vue Router 4 along with Vue 3,
you will encounter this issue anyway.
It's mentioned here for your information.

## Upgrade from v2 to v3

This guide contains all the major changes that were introduced in v3, and how to migrate from v2.

Vue InstantSearch v3 uses InstantSearch.js v4, so all breaking changes using the InstantSearch.js API also apply here.
You can find more information in its respective [upgrade guide](/doc/guides/building-search-ui/upgrade-guides/js).

### Federated search (multi-index)

If you were using a [`ais-configure`](/doc/api-reference/widgets/configure/vue) or a [`ais-search-box`](/doc/api-reference/widgets/search-box/vue) to synchronize between two [`ais-instant-search`](/doc/api-reference/widgets/instantsearch/vue) instances, you can now replace either one of them with the new [`ais-index`](/doc/api-reference/widgets/index-widget/vue) widget like this:

```vue Vue icon=code theme={"system"}
<template>
  <ais-instant-search index-name="parent">
    <!-- root widgets are synchronized with every child -->
    <ais-searchbox />
    <ais-hits />

    <ais-index index-name="child">
      <!-- same query is used as parent -->
      <ais-hits />
      <!-- but this refinement list is only for the child -->
      <ais-refinement-list attribute="brands" />
    </ais-index>
  </ais-instant-search>
</template>
```

### ais-autocomplete

The `indices` option has been removed in favor of [`ais-index`](/doc/api-reference/widgets/index-widget/vue).

This means that:

```vue Vue icon=code theme={"system"}
<template>
  <ais-autocomplete :indices="[{ name: 'additional' }]">
    <!-- custom rendering -->
  </ais-autocomplete>
</template>
```

Should be replaced with:

```vue Vue icon=code theme={"system"}
<template>
  <ais-index index-name="additional" />
  <ais-autocomplete>
    <!-- custom rendering -->
  </ais-autocomplete>
</template>
```

### `ais-state-results`

This widget used to expose the search results only, you can now access the search parameters as well.
This lets you use <SearchQuery /> information to perform view logic instead of waiting for the response to retrieve the data.

```diff Vue icon=code theme={"system"}
<ais-state-results>
-  <template v-slot="{ query, nbHits }">
+  <template v-slot="{ state: { query }, results: { nbHits } }">
  </template>
<ais-state-results>
```

The results you have access to are always scoped to the current <Index />.

### Routing and URLs

Since the introduction of federated search, it's now possible to have multiple indices in a single app. This means that the default state mapping for routing now takes multiple indices into account. If you want to keep on using the same URLs as before, make the following change:

```diff JavaScript icon=code theme={"system"}
- import { simple as simpleMapping } from 'instantsearch.js/es/lib/stateMappings';
+ import { singleIndex as singleIndexMapping } from 'instantsearch.js/es/lib/stateMappings';

export default {
  data() {
    return {
      routing: {
-        stateMapping: simpleMapping(),
+        stateMapping: singleIndexMapping('myIndex'),
      }
    }
  }
}
```

For more information about custom routers,
consult the [InstantSearch.js upgrade guide](/doc/guides/building-search-ui/upgrade-guides/js#routing).

### Server-side rendering (SSR)

This major version of Vue InstantSearch also includes an overhaul of the server-side rendering implementation. This takes two points into consideration:

* work fully with `serverPrefetch`
* no repetition needed between the template and parameters

To do this the following changes have been made:

1. `createInstantSearch` -> `createServerRootMixin`

   ```js JavaScript icon=code theme={"system"}
   import { createServerRootMixin } from "vue-instantsearch";

   const app = new Vue({
     mixins: [
       createServerRootMixin({
         searchClient,
         indexName: "instant_search",
       }),
     ],
     serverPrefetch() {
       return this.instantsearch.findResultsState(this);
     },
     beforeMount() {
       if (typeof window === "object" && window.__ALGOLIA_STATE__) {
         this.instantsearch.hydrate(window.__ALGOLIA_STATE__);
         delete window.__ALGOLIA_STATE__;
       }
     },
     router,
     render: (h) => h(App),
   });
   ```

2. Using a compatible router

   The default routers in InstantSearch.js are based around browser location,
   and thus won't work on the server. An example router for Vue SSR can be made like this:

   ```js JavaScript icon=code theme={"system"}
   import qs from "qs";
   // get this from the environment, will be different in nuxt vs. vue ssr
   const serverUrl = context ? context.url : undefined;

   const router = {
     read() {
       const url = serverUrl
         ? serverUrl
         : typeof window.location === "object"
           ? window.location.href
           : "";
       const search = url.slice(url.indexOf("?"));

       return qs.parse(search, {
         ignoreQueryPrefix: true,
       });
     },
     write(routeState) {
       const query = qs.stringify(routeState, {
         addQueryPrefix: true,
       });

       if (typeof history === "object") {
         history.pushState(routeState, null, query);
       }
     },
     createURL(routeState) {
       const query = qs.stringify(routeState, {
         addQueryPrefix: true,
       });

       return query;
     },
     onUpdate(callback) {
       if (typeof window !== "object") {
         return;
       }

       this._onPopState = () => {
         if (this.writeTimer) {
           window.clearTimeout(this.writeTimer);
           this.writeTimer = undefined;
         }
         callback(this.read());
       };

       window.addEventListener("popstate", this._onPopState);
     },
     dispose() {
       if (this._onPopState && typeof window == "object") {
         window.removeEventListener("popstate", this._onPopState);
       }

       // Don't write on dispose to prevent double entries on navigation
     },
   };
   ```

A full example can be found in the [GitHub repository](https://github.com/algolia/instantsearch/tree/master/examples/vue). Read more detail in the dedicated [SSR guide](/doc/guides/building-search-ui/going-further/server-side-rendering/vue).

### Helper v3.x.x

This release includes version 3 of the [`algoliasearch-helper` package](https://www.npmjs.com/package/algoliasearch-helper/). **If you are using the built-in widgets or connectors, nothing changes for you.**

This version of `algoliasearch-helper` no longer includes [Lodash](https://lodash.com/), which significantly reduces its bundle size (from 27.5 KB to 9.1 KB Gzipped).

## Upgrade from v1 to v2

This guide contains all the major changes that were introduced in v2 and how to migrate from v1. You can still find the documentation for [Vue InstantSearch v1](https://community.algolia.com/vue-instantsearch).

### Renamed components

Some components have been renamed to be more consistent with other InstantSearch flavors.

* `ais-results` -> `ais-hits`
* `ais-tree-menu` -> `ais-hierarchical-menu`
* `ais-clear` -> `ais-clear-refinements`
* `ais-results-per-page-selector` -> `ais-hits-per-page`
* `ais-rating` -> `ais-rating-menu`
* `ais-sort-by-selector` -> `ais-sort-by`
* `ais-index` -> `ais-instant-search`

All individual component exports have also been renamed from, for example, `SearchBox` to `AisSearchBox`. This is to make it more ergonomic to use them as components in a Vue file with the same name as expected.

The `Component` mixin has been renamed to `createWidgetMixin({ connector })`. Read more about that in the [custom component guide](/doc/guides/building-search-ui/widgets/create-your-own-widgets/vue).

### New components

* [`ais-configure`](/doc/api-reference/widgets/configure/vue)

  This widget is the replacement of `query-parameters` on `ais-index`.

* [`ais-state-results`](/doc/api-reference/widgets/state-results/vue)

  This component can be used for conditional rendering, and getting information that's not returned in `ais-hits`.

* [`ais-breadcrumb`](/doc/api-reference/widgets/breadcrumb/vue)

  To be used together with `ais-hierarchical-menu`.

* [`ais-menu-select`](/doc/api-reference/widgets/menu-select/vue)

  A single-selectable menu, rendered inside a `select`

* [`ais-current-refinements`](/doc/api-reference/widgets/current-refinements/vue)

  Shows the current refinements, and allows them to be unset.

* [`ais-infinite-hits`](/doc/api-reference/widgets/infinite-hits/vue)

  Replaces `:stack="true"` on `ais-results` (now called `ais-hits`).

* [`ais-numeric-menu`](/doc/api-reference/widgets/numeric-menu/vue)

  Statically set numerical ranges can be used to refine using this widget.

* [`ais-panel`](/doc/api-reference/widgets/panel/vue)

  Wrap a widget in `ais-panel` to be able to give it a header and a footer. Replaces those options on each widget.

* [`ais-toggle-refinement`](/doc/api-reference/widgets/toggle-refinement/vue)

  Toggle a boolean refinement either refined/unrefined or refinement/another refinement. Useful for toggles or buttons with two states.

### Renamed options

Some options have been renamed. Largely those are:

* attribute-name -> attribute
* results -> hits
* anything in a list -> items / item
* header / footer -> wrap the widget in an `ais-panel`

If you see anything not mentioned here, [complete the feedback form](https://github.com/algolia/instantsearch/issues/new/choose).

### Removed options

* `query-parameters`

  This is now handled with the [`ais-configure`](/doc/api-reference/widgets/configure/vue) widget. Each query parameter becomes a prop on Configure.

* `query`

  You can now synchronize the query across indices either by using a `v-model` on two `ais-search-box`es of which you hide one, or with [`ais-configure`](/doc/api-reference/widgets/configure/vue) on both indices, and synchronizing between those like that.

* `appId` and `apiKey`

  This is now handled by the `search-client` prop. Search client is what gets returned if you call `algoliasearch`.

  ```diff Vue icon=code theme={"system"}
    <template>
  -   <ais-index
  -     app-id="appID"
  -     api-key="apiKey"
  -     index-name="myIndex"
  -   >
  +   <ais-instant-search
  +     :search-client="searchClient"
  +     index-name="myIndex"
  +   >
        <slot>My app</slot>
  +   </ais-instant-search>
  -   </ais-index>
    </template>

  + <script>
  + import { liteClient as algoliasearch } from 'algoliasearch/lite';
  + const searchClient = algoliasearch('appID', 'apiKey');

  + export default {
  +   data() {
  +     return {
  +       searchClient,
  +     };
  +   },
  + };
  + </script>
  ```

* `:stack="true"`

  When you used to put this on `ais-results` (now called [`ais-hits`](/doc/api-reference/widgets/hits/vue)),
  it allows to load next pages without pagination,
  but with a "next page" button,
  as well as showing all pages rather than a single one.
  Replaced by [`ais-infinite-hits`](/doc/api-reference/widgets/infinite-hits/vue).

* `auto-search`

  This option is removed in favor of a more complete way of not doing queries using the search client.
  For more information, see [Conditional requests](/doc/guides/building-search-ui/going-further/conditional-display/vue).

### Removed components

* `ais-input`

  This component has been removed with as alternative having two options:

  1. use [`ais-search-box`](/doc/api-reference/widgets/search-box/vue) and style it to not include the extra items
  2. use the default slot of `ais-search-box` to use it with your own custom input ([see live](https://community.algolia.com/vue-instantsearch/stories/?selectedKind=SearchBox)):

  ```vue Vue icon=code theme={"system"}
  <ais-search-box autofocus>
    <input
      v-slot="{ currentRefinement, refine }"
      :value="currentRefinement"
      @input="refine($event.currentTarget.value)"
      placeholder="Custom SearchBox"
    />
  </ais-search-box>
  ```

### CSS class names

All CSS class names are now different, since Algolia follows the [SUIT CSS](https://suitcss.github.io/) methodology now, rather than the previous, slightly wrong, implementation of 'block, element and modifier' (BEM).

Since the DOM output is also different in most widgets, it's best to start styling over from scratch on these widgets.

Each widget lists the CSS classes it uses in its documentation page.

### Known limitations

#### SSR (server-side rendering)

The implementation of server-side rendering with Vue InstantSearch slightly changed, with a simpler API. Read more on how to use it in the [SSR guide](/doc/guides/building-search-ui/going-further/server-side-rendering/vue).

#### Search store

The search store no longer exists. Custom widgets are either made by making a connector, or a combination of new widgets.

You no longer need to copy a widget to give it custom rendering. Now you can fill in the `default` slot, which will have everything needed to render that component.

If you're using this, and have suggestions or questions, [complete the feedback form](https://github.com/algolia/instantsearch/issues/new/choose).

#### Routing

You're now able to use routing in InstantSearch with, or without [Vue Router](/doc/guides/building-search-ui/going-further/routing-urls/vue).

#### Changing props on ais-instant-search

It's possible to change props on `ais-instant-search`, except `routing`. If you have a need for that to be changed as well, [complete the feedback form](https://github.com/algolia/instantsearch/issues/new/choose).
