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

# InstantSearch custom hooks

> Custom hooks that change the behavior of the search results page.

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

export const Filter = () => <Tooltip tip="A filter is a condition that limits which records Algolia returns. Filters often use one or more facet-value pairs, such as brand:Apple AND color:red. You can also filter by numeric values, dates, tags, booleans, or geographic constraints." cta="Filtering" href="/doc/guides/managing-results/refine-results/faceting">
    filter
  </Tooltip>;

## `beforeInstantSearchAsyncFunction`

Use this hook to run asynchronous work (for example, an external API request) before InstantSearch sets any parameters.
Add several `await` statements to run tasks in sequence.

### Parameters

This hook doesn't accept parameters.

### Returns

This hook doesn't return a value. Return a `Promise` to delay InstantSearch until your work completes.

### Examples

<AccordionGroup>
  <Accordion title="Delay InstantSearch until an async task completes">
    Return a `Promise` to pause InstantSearch while you run async work.

    ```js JavaScript icon=code theme={"system"}
    const sleep = (ms, hookName) =>
    	new Promise((resolve) => {
    		console.log("sleeping for ", ms, hookName);
    		setTimeout(resolve, ms);
    	});
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchAsyncFunction",
    		async () => {
    			console.log(
    				"----------- beforeInstantSearchAsyncFunction started ----------------",
    			);
    			await sleep(1000, "beforeInstantSearchAsyncFunction");
    		},
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchConfigurationOptions`

Changes InstantSearch options.

### Parameters

<ParamField body="options" type="object">
  InstantSearch configuration [options](/doc/api-reference/widgets/instantsearch/js#options).
</ParamField>

### Returns

<ResponseField name="options" type="object">
  Modified configuration options.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Customize InstantSearch configuration options">
    Update InstantSearch options before it initializes.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchConfigurationOptions",
    		(options) => {
    			// Modify default options, then return them
    			options.numberLocale = "fr";
    			options.stalledSearchDelay = 500;

    			return options;
    		},
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchOptions`

Changes the following parameters:

### Parameters

<ParamField body="options" type="object">
  InstantSearch options with the following properties:

  * `colors`
  * `distinct`
  * `facets`
  * `hitsPerPage`
  * `selector`
  * `sortOrders`
</ParamField>

### Returns

<ResponseField name="options" type="object">
  Modified InstantSearch options.
</ResponseField>

## `beforeInstantSearchAllowParamsArray`

Preserves URL parameters when navigating through the search results.

### Parameters

<ParamField body="allowParamsArray" type="string[]">
  URL parameter names to preserve.
</ParamField>

### Returns

<ResponseField name="allowParamsArray" type="string[]">
  Modified parameter names.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Preserve a custom URL parameter">
    Add `ref` to the allowlist so InstantSearch preserves it in the URL.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchAllowParamsArray",
    		function () {
    			// Add a new search parameter
    			const allowParamsArray = [...arguments, "ref"];
    			return allowParamsArray;
    		},
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchFiltersString`

Changes the [filter parameter](/doc/api-reference/api-parameters/filters) of the search results page.

### Parameters

<ParamField body="defaultFilter" type="string">
  Default <Filter /> (may be empty).
</ParamField>

### Returns

<ResponseField name="filters" type="string">
  Filters to apply.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Add a filter condition">
    Append a price filter to the existing filter string, if present.

    ```js JavaScript icon=code theme={"system"}
    // Modify default `defaultFilter` if it exists
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchFiltersString",
    		(defaultFilter) => {
    			// Modify or replace the default string, then return a string
    			if (defaultFilter) {
    				return defaultFilter + " AND price > 5";
    			} else {
    				return "price > 5";
    			}
    		},
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchRuleContexts`

Modifies the [`ruleContexts`](/doc/api-reference/api-parameters/ruleContexts) sent with InstantSearch queries.
Use this hook to trigger [Rules](/doc/guides/managing-results/rules/rules-overview) based on page context, such as UTM parameters, customer segments, or custom page metadata.

On collection pages, the default contexts include the collection handle and `shopify_default_collection`.

### Parameters

<ParamField body="ruleContexts" type="string[]">
  Default rule contexts. On collection pages, this includes the collection handle and `shopify_default_collection`. On other pages, this is an empty array.
</ParamField>

### Returns

<ResponseField name="ruleContexts" type="string[]">
  Modified rule contexts. Duplicates are removed and the list is limited to 10 items.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Add rule contexts based on UTM parameters">
    This example adds a rule context based on the `utm_source` URL parameter.

    ```js JavaScript icon=code highlight={7} theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchRuleContexts", (...rules) => {
    			var params = new URLSearchParams(window.location.search);
    			var utmSource = params.get("utm_source");
    			if (utmSource) {
    				rules.push("campaign-" + utmSource);
    			}
    			return rules;
    		},
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchMainTemplate`

Template for the main template container.

If you're using the [facet display](/doc/integration/shopify/building-search-ui/instant-search#facet-display) feature,
include a `div` with `class="ais-facets-container"` to display the facets.

### Parameters

<ParamField body="_defaultTemplate">
  Default template.
</ParamField>

<ParamField body="data" type="object">
  Contains facets and configuration.
</ParamField>

<ParamField body="html">
  Tagged template function for rendering HTML.
</ParamField>

### Returns

<ResponseField name="template">
  Template to render.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Customize the main template">
    Return a custom page layout that includes facet, stats, and results containers.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchMainTemplate",
    		(_defaultTemplate, data, html) => html`
          <div class="ais-page">
            <h1 class="ais-h2">${algoliaShopify.translations.searchTitle}</h1>
            <div class="ais-input">
              <div class="ais-search-box-container"></div>
              <div class="ais-input-button">
                <div class="ais-clear-input-icon"></div>
              </div>
            </div>
            <div class="ais-facets-button">
              ${algoliaShopify.translations.showFilters}
            </div>
            <div class="ais-facets">
              <div class="ais-clear-refinements-container"></div>
              <div class="ais-current-refined-values-container"></div>
              ${
    						algoliaShopify.config.app_blocks_dynamic_widgets_beta_enabled
    							? html`
                    <div class="ais-dynamic-widgets-container"></div>
                  `
    							: data.facets.map(
    									(facet) =>
    										html`
                        <div
                          class="ais-facet-dropdown-wrapper ais-facet-${facet.type} ais-facet-${facet.escapedName}"
                        >
                          <label
                            for="${facet.escapedName}"
                            class="ais-range-slider--header ais-facet--header ais-header"
                            >${facet.title}</label
                          >
                          <input
                            class="ais-dropdown-checkbox"
                            type="checkbox"
                            id="${facet.escapedName}"
                            name="dropdown"
                          />
                          <div
                            class="ais-facet-${facet.escapedName}-container ais-facet-dropdown-container"
                          ></div>
                        </div>
                      `,
    								)
    					}
            </div>
            <div class="ais-block">
              <div class="ais-search-header">
                <div class="ais-stats-container"></div>
                <div class="ais-change-display">
                  <span class="ais-change-display-block ais-change-display-selected"
                    ><i class="fa fa-th-large"></i
                  ></span>
                  <span class="ais-change-display-list"
                    ><i class="fa fa-th-list"></i
                  ></span>
                </div>
                <div class="ais-sort">
                  ${
    								data.multipleSortOrders
    									? html`
                        ${algoliaShopify.translations.sortBy}
                        <span class="ais-sort-orders-container"></span>
                      `
    									: html`
                        ${algoliaShopify.translations.sortBy}
                        ${algoliaShopify.translations.relevance}
                      `
    							}
                </div>
              </div>
              <div class="ais-hits-container ais-results-as-block"></div>
            </div>
            <div class="ais-pagination-container"></div>
          </div>
        `,
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchProductTemplate`

Template for product hits in the search results.

When using this template,
also call `trackSearchAttribution(hit)` to properly handle events.

### Parameters

<ParamField body="_defaultTemplate">
  Default template.
</ParamField>

<ParamField body="hit" type="object">
  Product hit.
</ParamField>

<ParamField body="html">
  Tagged template function for rendering HTML.
</ParamField>

<ParamField body="components" type="object">
  InstantSearch components (like `Highlight`).
</ParamField>

<ParamField body="trackSearchAttribution">
  Function to track search attribution.
  Equivalent to `algoliaShopify.helpers.handleItemClick`.
</ParamField>

### Returns

<ResponseField name="template">
  Template to render.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Customize product hits">
    Return a custom product-hit template and call `trackSearchAttribution(hit)` to track events.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchProductTemplate",
    		(_defaultTemplate, hit, html, components, trackSearchAttribution) => html`
          <div
            class="ais-hit ais-product"
            data-algolia-index="${hit.index}"
            data-algolia-position="${hit.productPosition}"
            data-algolia-queryid="${hit.queryID}"
            data-algolia-objectid="${hit.objectID}"
            data-handle="${hit.handle}"
            data-variant-id="${hit.objectID}"
            data-distinct="${hit._distinct}"
            data-product-id="${hit.id}"
            onClick="${() => trackSearchAttribution(hit)}"
          >
            <img
              class="ais-hit--picture"
              src="${algoliaShopify.helpers.mediumImage(hit)}"
              alt="${hit.title} - ${hit.variant_title}"
            />

            <div class="ais-hit--details">
              <p class="ais-hit--title">
                <a
                  data-algolia-index="${hit.index}"
                  data-algolia-position="${hit.productPosition}"
                  data-algolia-queryid="${hit.queryID}"
                  data-algolia-objectid="${hit.objectID}"
                  href="${algoliaShopify.helpers.instantsearchLink(hit)}"
                  title="${algoliaShopify.helpers.fullTitle(
    								hit.title,
    								hit._distinct,
    								hit.variant_title,
    							)}"
                >
                  ${components.Highlight({ attribute: "title", hit })}
                  ${algoliaShopify.helpers.variantTitleAddition(hit, hit._distinct)}
                </a>
              </p>
              <p
                class="ais-hit--subtitle"
                title="${hit.product_type}${algoliaShopify.translation_helpers.by(
    							hit.vendor,
    						)}"
              >
                ${components.Highlight({ attribute: "product_type", hit })}
                ${
    							hit.vendor &&
    							html`
                    <span> ${algoliaShopify.translations.by} </span>
                  `
    						}
                ${hit.vendor && components.Highlight({ attribute: "vendor", hit })}
              </p>
              <p class="ais-hit--price">
                <b>${algoliaShopify.helpers.displayPrice(hit, hit._distinct)}</b>
                ${
    							!hit._distinct &&
    							html`
                    <span class="ais-hit--price-striked"
                      ><span
                        >${algoliaShopify.helpers.displayStrikedPrice(
    											hit.price,
    											hit.compare_at_price,
    										)}</span
                      ></span
                    >
                  `
    						}
                ${
    							!hit._distinct &&
    							html`
                    <span class="ais-hit--price-discount"
                      >${algoliaShopify.helpers.displayDiscount(
    										hit.price,
    										hit.compare_at_price,
    										hit.price_ratio,
    									)}</span
                    >
                  `
    						}
              </p>
              <!-- Extra info examples - Remove the display: none to show them -->
              <p class="ais-hit--info" style="display: none">
                ${
    							hit.sku &&
    							html`
                    <span class="algolia-sku"
                      >${components.Highlight({ attribute: "sku", hit })}</span
                    >
                  `
    						}
                ${
    							hit.barcode &&
    							html`
                    <span class="algolia-barcode"
                      >${components.Highlight({ attribute: "barcode", hit })}</span
                    >
                  `
    						}
                ${
    							hit.weight &&
    							html`
                    <span class="algolia-weight">${hit.weight}</span>
                  `
    						}
                ${
    							!hit.taxable &&
    							html`
                    <span class="algolia-taxable"
                      >${algoliaShopify.translations.taxFree}</span
                    >
                  `
    						}
              </p>
              <!-- Tags example - Remove the display: none to show them -->
              <p class="ais-hit--tags" style="display: none">
                ${hit?._highlightResult.tags?.map(
    							(tag) =>
    								html`
                      <span class="ais-hit--tag">${tag.value}</span>
                    `,
    						)}
              </p>
              ${
    						!hit._distinct &&
    						html`
                  <form
                    id="algolia-add-to-cart-${hit.objectID}"
                    style="display: none;"
                    action="/cart/add"
                    method="post"
                    enctype="multipart/form-data"
                  >
                    <input type="hidden" name="id" value="${hit.objectID}" />
                  </form>
                  <p class="ais-hit--cart">
                    ${
    									hit.can_order
    										? html`
                          <button
                            class="ais-hit--cart-button"
                            data-form-id="algolia-add-to-cart-${hit.objectID}"
                          >
                            ${algoliaShopify.translations.addToCart}
                          </button>
                        `
    										: html`
                          <button
                            class="ais-hit--cart-button ais-hit--cart-button__disabled"
                          >
                            ${algoliaShopify.translations.outOfStock}
                          </button>
                        `
    								}
                  </p>
                `
    					}
            </div>
          </div>
        `,
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchNoResultTemplate`

Template for when there are no results.

### Parameters

<ParamField body="_defaultTemplate">
  Default template.
</ParamField>

<ParamField body="html">
  Tagged template function for rendering HTML.
</ParamField>

### Returns

<ResponseField name="template">
  Template to render.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Customize the no results template">
    Replace the default empty state with a custom template.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchNoResultTemplate",
    		(_defaultTemplate, html) => html`
          <div class="ais-hit-empty">
            <div class="ais-hit-empty--title">
              ${algoliaShopify.translations.noResultFound}
            </div>
            <div class="ais-hit-empty--clears">
              ${algoliaShopify.translations.try} ${" "}
              <a class="ais-hit-empty--clear-filters ais-link">
                ${algoliaShopify.translations.clearFilters} ${" "}
              </a>
              ${algoliaShopify.translations.or} ${" "}
              <a class="ais-hit-empty--clear-input ais-link">
                ${algoliaShopify.translations.changeInput}
              </a>
            </div>
          </div>
        `,
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchStatsTemplate`

Template for [`search stats`](/doc/api-reference/widgets/stats/js)

<Note>
  If the active sort order uses a [virtual replica](/doc/guides/managing-results/refine-results/sorting/in-depth/relevant-sort/), the response includes `nbSortedHits`:
  the number of results Algolia considered were relevant enough to sort.
  Use `nbSortedHits` to show a message such as "42 relevant results sorted out of 1,247"
  instead of only the total hit count.
</Note>

### Parameters

<ParamField body="_defaultTemplate">
  Default template.
</ParamField>

<ParamField body="data" type="object">
  Contains search statistics, for example `nbHits`, `nbSortedHits`, `page`, and `hitsPerPage`.
</ParamField>

<ParamField body="html">
  Tagged template function for rendering HTML.
</ParamField>

### Returns

<ResponseField name="template">
  Template to render.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Customize the stats template">
    Customize the stats template for one or many results.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchStatsTemplate",
    		(_defaultTemplate, data, html) => html`
          ${
    				data.hasOneResult &&
    				html`
              <span class="ais-stats--nb-results">
                1 result found
              </span>
            `
    			}
          ${
    				data.hasManyResults &&
    				html`
              ${data.page * data.hitsPerPage + 1} - ${" "}
              ${Math.min((data.page + 1) * data.hitsPerPage, data.nbHits)} ${" "}
              out of
              <span class="ais-stats--nb-results">
                ${" "} ${algoliaShopify.helpers.formatNumber(data.nbHits)} ${" "}
                results found
              </span>
            `
    			}
          ${" "} in ${data.processingTimeMS / 1000}s
        `,
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchTransformItems`

Change [items](/doc/guides/building-search-ui/upgrade-guides/js#transformdata-is-replaced-by-transformitems) before they're rendered.

### Parameters

<ParamField body="transformedItems" type="array">
  Search result items.
</ParamField>

<ParamField body="items" type="array">
  Original items.
</ParamField>

### Returns

<ResponseField name="items" type="array">
  Modified items.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Mark out-of-stock items">
    Set `can_order` to `false` for items with `inventory_quantity` equal to `0`.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchTransformItems",
    		(transformedItems, items) => {
    			// Mark out-of-stock items
    			return transformedItems.map((item) => {
    				if (item.inventory_quantity === 0) {
    					item.can_order = false;
    				}
    				return item;
    			});
    		},
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchStartAddWidgets`

Add InstantSearch widgets to the search results page.
You can add the following widgets:

* [`clearRefinements`](/doc/api-reference/widgets/clear-refinements/js)
* [`configure`](/doc/api-reference/widgets/configure/js)
* [`dynamicWidgets`](/doc/api-reference/widgets/dynamic-facets/js)
* [`hierarchicalMenu`](/doc/api-reference/widgets/hierarchical-menu/js)
* [`hits`](/doc/api-reference/widgets/hits/js)
* [`menu`](/doc/api-reference/widgets/menu/js)
* [`pagination`](/doc/api-reference/widgets/pagination/js)
* [`panel`](/doc/api-reference/widgets/panel/js)
* [`rangeSlider`](/doc/api-reference/widgets/range-slider/js)
* [`refinementList`](/doc/api-reference/widgets/refinement-list/js)
* [`searchBox`](/doc/api-reference/widgets/search-box/js)
* [`sortBy`](/doc/api-reference/widgets/sort-by/js)
* [`stats`](/doc/api-reference/widgets/stats/js)

### Returns

<ResponseField name="widgets" type="array">
  InstantSearch widgets.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Add a custom widget">
    Add a `searchBox` widget before InstantSearch adds default widgets.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchStartAddWidgets",
    		() => {
    			// Not all widgets are available
    			const { searchBox } = window.algoliaShopify.externals.widgets;

    			const searchBoxWidget = searchBox({
    				container: "#search-box",
    			});

    			return [searchBoxWidget];
    		},
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `afterInstantSearchStartRemoveDefaultWidgets`

Remove default widgets from the search results page.
You can remove these widgets (`widget.$$widgetType`):

* `ais.sortBy`
* `ais.searchBox`
* `ais.stats`
* `ais.hits`
* `ais.pagination`

### Parameters

<ParamField body="defaultWidgets" type="array">
  Default InstantSearch widgets.
</ParamField>

### Returns

<ResponseField name="widgets" type="array">
  Widgets to remove.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Remove a default widget">
    Remove the default pagination widget.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"afterInstantSearchStartRemoveDefaultWidgets",
    		(defaultWidgets) => {
    			// Find and return the default pagination widget to remove it
    			const defaultPaginationWidget = defaultWidgets.find(
    				(widget) => widget.$$widgetType === "ais.pagination",
    			);

    			return [defaultPaginationWidget];
    		},
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchFacetSearchablePlaceholder`

Changes the [`searchablePlaceholder`](/doc/api-reference/widgets/refinement-list/js#param-searchable-placeholder) for facet search.

<Note>
  Use [`beforeInstantSearchFacetParamsOptions`](#beforeinstantsearchfacetparamsoptions) instead.
</Note>

### Parameters

<ParamField body="placeholder" type="string">
  Default placeholder text.
</ParamField>

### Returns

<ResponseField name="placeholder" type="string">
  Modified placeholder text.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Change the facet search placeholder">
    Override the facet search placeholder text.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchFacetSearchablePlaceholder",
    		(placeholder) => "Search facets:",
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchFacetParamsOptions`

Update widget parameters before they're rendered.

### Parameters

<ParamField body="params" type="object">
  Widget parameters. Parameters depend on the widget type.
  Use `facet.type` to determine the widget.
</ParamField>

<ParamField body="facet" type="object">
  Facet metadata (read-only):

  * `title`
  * `name`
  * `type` (refinement parameters)
    * `slider`: [`rangeSlider`](/doc/api-reference/widgets/range-slider/js)
    * `menu`: [`menu`](/doc/api-reference/widgets/menu/js)
    * `conjunctive`: [`refinementList`](/doc/api-reference/widgets/refinement-list/js)
    * `disjunctive`: [`refinementList`](/doc/api-reference/widgets/refinement-list/js)
</ParamField>

### Returns

<ResponseField name="params" type="object">
  Modified widget parameters.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Customize facet widget parameters">
    Adjust facet widget parameters based on `facet.title` or `facet.type`.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchFacetParamsOptions",
    		(params, facet) => {
    			if (facet.title == "Tags") {
    				return {
    					...params,
    					limit: 5,
    					templates: {
    						searchableNoResults(data, { html }) {
    							return html`<span>No results</span>`;
    						},
    					},
    				};
    			}

    			if (facet.title == "Vendor") {
    				return {
    					...params,
    					transformItems(items) {
    						return items.map((item) => ({
    							...item,
    							label: item.label.toUpperCase(),
    						}));
    					},
    				};
    			}

    			if (facet.type == "slider") {
    				return {
    					...params,
    					pips: false,
    					tooltips: true,
    				};
    			}

    			return {
    				...params,
    			};
    		},
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchFacetPanelOptions`

Update the panel parameters before they're rendered.

### Parameters

<ParamField body="params" type="object">
  Panel parameters.
  For more information, see [`panel`](/doc/api-reference/widgets/panel/js).
</ParamField>

<ParamField body="facet" type="object">
  Facet metadata (read-only):

  * `title`
  * `name`
</ParamField>

### Returns

<ResponseField name="params" type="object">
  Modified panel parameters.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Customize panel parameters">
    Customize panel templates like `header`, `footer`, and `searchableNoResults`.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchFacetPanelOptions",
    		(params, facet) => {
    			if (facet.name == "tags" || facet.title == "Tags") {
    				return {
    					...params,
    					templates: {
    						// To avoid duplicate headers use the `beforeInstantSearchMainTemplate` hook and remove the  'ais-facet-dropdown-wrapper' container
    						header(options, { html }) {
    							if (options.results) {
    								return html`<span class="ais-facet--header">Tags Header (${options.results.nbHits} results)</span>`;
    							}
    						},
    					},
    				};
    			}

    			if (facet.type == "disjunctive") {
    				return {
    					...params,
    					templates: {
    						footer(options, { html }) {
    							if (options.results) {
    								return html`<span class="ais-facet--footer">Disjunctive footer (${options.results.nbHits} results)</span>`;
    							}
    						},
    						searchableNoResults(data, { html }) {
    							return html`<span>No results</span>`;
    						},
    					},
    				};
    			}

    			return {
    				...params,
    			};
    		},
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchInitSearchSortOrders`

Transform [`sort order`](/doc/api-reference/widgets/sort-by/js#param-transform-items) before they're rendered.

### Parameters

<ParamField body="...sortOrders" type="object[]">
  Sort orders, spread as individual arguments. The last argument is reserved for internal use: use rest syntax and `slice(0, -1)` to collect the sort order objects. Each has:

  * `label` (string): display name for the sort order
  * `value` (string): <Index /> name for the sort order
</ParamField>

### Returns

<ResponseField name="sortOrders" type="array">
  Modified sort orders.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Add a custom sort order">
    Add a custom sort option to the sort-by widget.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchInitSearchSortOrders", 
    		(...hookArgs) => {
    			const indexPrefix = algoliaShopify.config.index_prefix;
    			const sortOrders = hookArgs.slice(0, -1); // Drop the trailing internal argument

    			const replicaName = `price_asc_virtual`; 
    			const primaryIndex = `${indexPrefix}products`;
    			const sortOrderIndex = `${primaryIndex}_${replicaName}`;

    			sortOrders.push({
    				label: 'Lowest Price',
    				value: sortOrderIndex, // shopify_products_price_asc_virtual
    			});
    			return sortOrders;
    		}
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `beforeInstantSearchInitCollectionSortOrders`

Transform the sort order for collections.

### Parameters

<ParamField body="...sortOrders" type="object[]">
  Sort orders, spread as individual arguments. The last argument is reserved for internal use: use rest syntax and `slice(0, -1)` to collect the sort order objects. Each has:

  * `label` (string): display name for the sort order
  * `value` (string): <Index /> name for the sort order
</ParamField>

### Returns

<ResponseField name="sortOrders" type="array">
  Modified sort orders.
</ResponseField>

### Examples

<AccordionGroup>
  <Accordion title="Add a custom collection sort order">
    Add a custom sort option for collections.

    ```js JavaScript icon=code theme={"system"}
    document.addEventListener("algolia.hooks.initialize", () => {
    	algoliaShopify.hooks.registerHook(
    		"beforeInstantSearchInitCollectionSortOrders", 
    		(...hookArgs) => {
    			const indexPrefix = algoliaShopify.config.index_prefix;
    			const sortOrders = hookArgs.slice(0, -1); // Drop the trailing internal argument

    			const replicaName = `price_asc_virtual`; 
    			const primaryIndex = `${indexPrefix}products`;
    			const sortOrderIndex = `${primaryIndex}_${replicaName}`;

    			sortOrders.push({
    				label: 'Lowest Price',
    				value: sortOrderIndex, // shopify_products_price_asc_virtual
    			});
    			return sortOrders;
    		}
    	);
    });
    ```
  </Accordion>
</AccordionGroup>

## `afterInstantSearchHitClickAction` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchProductTemplate`](#beforeinstantsearchproducttemplate) instead.
</Note>

Runs after a user clicks a search result.
Return a function to override the default click behavior.

### Parameters

<ParamField body="_" type="any">
  First parameter (unused).
</ParamField>

<ParamField body="hit" type="object">
  Product search result (hit) that was clicked.
</ParamField>

### Returns

<ResponseField name="onClick">
  Function to run on click.
</ResponseField>

## `beforeInstantSearchFacetItemTemplate` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchFacetParamsOptions`](#beforeinstantsearchfacetparamsoptions) instead.
  The [`refinementList`](/doc/api-reference/widgets/refinement-list/js) widget can be added as a parameter in the template object.
</Note>

Template for rendering facet items.

### Parameters

<ParamField body="_defaultTemplate">
  Default template.
</ParamField>

<ParamField body="item" type="object">
  Facet.
</ParamField>

<ParamField body="html">
  Tagged template function for rendering HTML.
</ParamField>

## `beforeInstantSearchShowMoreTemplate` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchFacetParamsOptions`](#beforeinstantsearchfacetparamsoptions) instead.
  The [`refinementList`](/doc/api-reference/widgets/refinement-list/js) widget can be added as a parameter within the template object.
</Note>

Template for the [`showMoreText`](/doc/api-reference/widgets/refinement-list/js#param-show-more-text) button.

### Parameters

<ParamField body="_defaultTemplate">
  Default template.
</ParamField>

<ParamField body="data" type="object">
  Contains the `isShowingMore` property.
</ParamField>

<ParamField body="html">
  Tagged template function for rendering HTML.
</ParamField>

## `beforeInstantSearchFacetLimitNumber` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchFacetParamsOptions`](#beforeinstantsearchfacetparamsoptions) instead.
  The [`refinementList`](/doc/api-reference/widgets/refinement-list/js) widget can be added as a parameter.
</Note>

Changes the [`limit`](/doc/api-reference/widgets/refinement-list/js#param-limit) (default: 10).

### Parameters

<ParamField body="limit" type="number" default="10">
  Default limit.
</ParamField>

### Returns

<ResponseField name="limit" type="number">
  New limit.
</ResponseField>

## `beforeISFacetSearchablePlaceholderString` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchFacetSearchablePlaceholder`](#beforeinstantsearchfacetsearchableplaceholder) or
  [`beforeInstantSearchFacetParamsOptions`](#beforeinstantsearchfacetparamsoptions) instead.
  The [`searchablePlaceholder`](/doc/api-reference/widgets/refinement-list/js#param-searchable-placeholder) option can be added as a parameter in the template object.
</Note>

Changes the [`searchablePlaceholder`](/doc/api-reference/widgets/refinement-list/js#param-searchable-placeholder).

### Parameters

<ParamField body="placeholder" type="string">
  Default placeholder text.
</ParamField>

### Returns

<ResponseField name="placeholder" type="string">
  Modified placeholder text.
</ResponseField>

## `beforeISFacetSearchableNoResultsString` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchFacetParamsOptions`](#beforeinstantsearchfacetparamsoptions) instead.
  The [`searchableNoResults`](/doc/api-reference/widgets/refinement-list/js#param-searchable-no-results) option can be added as a parameter in the template object.
</Note>

Changes the [`searchableNoResults`](/doc/api-reference/widgets/refinement-list/js#param-searchable-no-results).

### Parameters

<ParamField body="noResultsText" type="string">
  Default "no results" text.
</ParamField>

### Returns

<ResponseField name="noResultsText" type="string">
  Modified "no results" text (string or template literal).
</ResponseField>

## `beforeInstantSearchFacetHeaderString` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchFacetPanelOptions`](#beforeinstantsearchfacetpaneloptions) instead.
  The [`header`](/doc/api-reference/widgets/panel/js#param-header) parameter can be added as a parameter in the template object.
  To avoid duplicate headers, use the `beforeInstantSearchMainTemplate` hook and remove the `ais-facet-dropdown-wrapper` container.
</Note>

Changes the facet header string.

### Parameters

<ParamField body="headerString" type="string">
  Default facet header.
</ParamField>

### Returns

<ResponseField name="headerString" type="string">
  Modified facet header.
</ResponseField>

## `beforeInstantSearchFacetTransformItemsOptions` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchFacetParamsOptions`](#beforeinstantsearchfacetparamsoptions) instead.
  Use `transformItems` as a parameter to transform the data.
</Note>

Transforms [`items`](/doc/api-reference/widgets/refinement-list/js#param-items) before they're rendered.

### Parameters

<ParamField body="options" type="object">
  Transform items options.
</ParamField>

### Returns

<ResponseField name="options" type="object">
  Modified options.
</ResponseField>

## `beforeISTransformItems` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchTransformItems`](#beforeinstantsearchtransformitems) instead.
</Note>

Change [items](/doc/guides/building-search-ui/upgrade-guides/js#transformdata-is-replaced-by-transformitems) before they're rendered.

### Parameters

<ParamField body="transformedItems" type="array">
  Transformed items.
</ParamField>

<ParamField body="items" type="array">
  Original items.
</ParamField>

### Returns

<ResponseField name="items" type="array">
  Modified items.
</ResponseField>

## `afterISStartRemoveDefaultWidget` (deprecated)

<Note>
  This hook is deprecated.
  Use [`afterInstantSearchStartRemoveDefaultWidgets`](#afterinstantsearchstartremovedefaultwidgets) instead.
</Note>

Remove default widgets from the search results page.
You can remove these widgets (`widget.widgetType`):

* `ais.sortBy`
* `ais.searchBox`
* `ais.stats`
* `ais.hits`
* `ais.pagination`

### Parameters

<ParamField body="defaultWidgets" type="array">
  Default InstantSearch widgets.
</ParamField>

### Returns

<ResponseField name="widgets" type="array">
  Widgets to remove.
</ResponseField>

## `beforeISearchInitSortOrdersArray` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchInitSearchSortOrders`](#beforeinstantsearchinitsearchsortorders) instead.
</Note>

Transform [`sort order`](/doc/api-reference/widgets/sort-by/js#param-transform-items) before they're rendered.

### Parameters

<ParamField body="sortOrders" type="array">
  Sort orders.
</ParamField>

### Returns

<ResponseField name="sortOrders" type="array">
  Modified sort orders.
</ResponseField>

## `beforeISStartAddWidgetArray` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchStartAddWidgets`](#beforeinstantsearchstartaddwidgets) instead.
</Note>

Add InstantSearch widgets to the search results page.
You can add the following widgets:

* `rangeSlider`
* `menu`
* `refinementList`
* `searchBox`
* `stats`
* `sortBy`
* `clearRefinements`
* `panel`
* `hits`
* `pagination`
* `configure`

### Returns

<ResponseField name="widgets" type="array">
  InstantSearch widgets.
</ResponseField>

## `beforeISInitCollectionSortOrdersArray` (deprecated)

<Note>
  This hook is deprecated.
  Use [`beforeInstantSearchInitCollectionSortOrders`](#beforeinstantsearchinitcollectionsortorders) instead.
</Note>

Transform the sort order for collections.

### Parameters

<ParamField body="sortOrders" type="array">
  Sort orders.
</ParamField>

### Returns

<ResponseField name="sortOrders" type="array">
  Modified sort orders.
</ResponseField>

## See also

* [Add custom hooks](/doc/integration/shopify/building-search-ui/frontend-custom-events)
* [Autocomplete hooks](/doc/integration/shopify/building-search-ui/autocomplete-hooks)
* [Insights and Recommend hooks](/doc/integration/shopify/building-search-ui/insights-recommend-hooks)
