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

# Send click and conversion events with InstantSearch.js

> Unlock Algolia's most powerful features by sending click and conversion events from your InstantSearch app.

export const FlavorSwitcher = ({current, baseHref = "", options = [], label = "InstantSearch framework"}) => {
  if (options.length === 0) {
    return <div className="not-prose" role="alert" style={{
      margin: "0.25rem 0 1.5rem",
      padding: "0.75rem",
      border: "1px solid #f59e0b",
      borderRadius: "0.625rem",
      color: "inherit",
      fontSize: "0.875rem"
    }}>
        FlavorSwitcher requires at least one option.
      </div>;
  }
  const selected = options.find(option => option.value === current) ?? options[0];
  return <div className="not-prose mint-flavor-switcher">
      <style>{`
        .mint-flavor-switcher {
          --mfs-bg: #ffffff;
          --mfs-bg-hover: #f4f4f5;
          --mfs-bg-current: #eef2ff;
          --mfs-border: #d4d4d8;
          --mfs-fg: #18181b;
          --mfs-muted: #71717a;
          --mfs-accent: #4f46e5;
          position: relative;
          width: min(100%, 19rem);
          margin: 0.25rem 0 1.5rem;
          color: var(--mfs-fg);
          font-size: 0.875rem;
          line-height: 1.25rem;
        }

        .dark .mint-flavor-switcher {
          --mfs-bg: #18181b;
          --mfs-bg-hover: #27272a;
          --mfs-bg-current: #272747;
          --mfs-border: #3f3f46;
          --mfs-fg: #fafafa;
          --mfs-muted: #a1a1aa;
          --mfs-accent: #a5b4fc;
        }

        .mint-flavor-switcher details {
          position: relative;
        }

        .mint-flavor-switcher summary {
          display: flex;
          min-height: 2.75rem;
          box-sizing: border-box;
          align-items: center;
          justify-content: space-between;
          gap: 0.75rem;
          padding: 0.625rem 0.75rem;
          border: 1px solid var(--mfs-border);
          border-radius: 0.625rem;
          background: var(--mfs-bg);
          color: var(--mfs-fg);
          cursor: pointer;
          font-weight: 600;
          list-style: none;
          transition: border-color 150ms ease, box-shadow 150ms ease;
        }

        .mint-flavor-switcher summary::-webkit-details-marker {
          display: none;
        }

        .mint-flavor-switcher summary:hover {
          border-color: var(--mfs-accent);
        }

        .mint-flavor-switcher summary:focus-visible {
          outline: 2px solid var(--mfs-accent);
          outline-offset: 2px;
        }

        .mint-flavor-switcher__label {
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }

        .mint-flavor-switcher__chevron {
          flex: none;
          transition: transform 150ms ease;
        }

        .mint-flavor-switcher details[open] .mint-flavor-switcher__chevron {
          transform: rotate(180deg);
        }

        .mint-flavor-switcher__menu {
          position: absolute;
          z-index: 50;
          top: calc(100% + 0.375rem);
          left: 0;
          width: 100%;
          box-sizing: border-box;
          margin: 0;
          padding: 0.375rem;
          border: 1px solid var(--mfs-border);
          border-radius: 0.625rem;
          background: var(--mfs-bg);
          box-shadow: 0 12px 30px rgb(0 0 0 / 16%);
          list-style: none;
        }

        .mint-flavor-switcher__menu li {
          margin: 0;
          padding: 0;
        }

        .mint-flavor-switcher__option {
          display: grid;
          gap: 0.125rem;
          padding: 0.625rem 0.75rem;
          border-radius: 0.4rem;
          color: var(--mfs-fg);
          text-decoration: none;
        }

        .mint-flavor-switcher__option:hover {
          background: var(--mfs-bg-hover);
        }

        .mint-flavor-switcher__option:focus-visible {
          outline: 2px solid var(--mfs-accent);
          outline-offset: -2px;
        }

        .mint-flavor-switcher__option[aria-current="page"] {
          background: var(--mfs-bg-current);
          color: var(--mfs-accent);
        }

        .mint-flavor-switcher__name {
          font-weight: 600;
        }

        .mint-flavor-switcher__description {
          color: var(--mfs-muted);
          font-size: 0.8125rem;
        }

        @media (prefers-reduced-motion: reduce) {
          .mint-flavor-switcher summary,
          .mint-flavor-switcher__chevron {
            transition: none;
          }
        }
      `}</style>

      <details>
        <summary aria-label={`${label}: ${selected.label}`}>
          <span className="mint-flavor-switcher__label">{selected.label}</span>
          <svg className="mint-flavor-switcher__chevron" width="18" height="18" 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>
        </summary>

        <ul className="mint-flavor-switcher__menu" aria-label={label}>
          {options.map(option => {
    const isCurrent = option.value === selected.value;
    const href = option.href ?? `${baseHref.replace(/\/$/, "")}/${encodeURIComponent(option.value)}`;
    return <li key={option.value}>
                <a className="mint-flavor-switcher__option" href={href} aria-current={isCurrent ? "page" : undefined}>
                  <span className="mint-flavor-switcher__name">
                    {option.label}
                  </span>
                  {option.description ? <span className="mint-flavor-switcher__description">
                      {option.description}
                    </span> : null}
                </a>
              </li>;
  })}
        </ul>
      </details>
    </div>;
};

<div className="mint-flavor-switcher-slot not-prose">
  <FlavorSwitcher
    current="js"
    baseHref="/doc/guides/building-search-ui/events"
    options={[
{ value: "js", label: "JavaScript", description: "InstantSearch.js" },
{ value: "react", label: "React", description: "React InstantSearch" },
{ value: "vue", label: "Vue", description: "Vue InstantSearch" },
{ value: "ios", label: "iOS", description: "InstantSearch iOS" },
{ value: "android", label: "Android", description: "InstantSearch Android" },
{ value: "flutter", label: "Flutter", description: "Algolia for Flutter" },
]}
  />
</div>

## What are events?

Events are actions that users take on your app or website.
They unlock powerful features, such as recommendations,
personalization, smarter search results,
and analytics that help you optimize your user experience.

For more information, see [Choose how to send events](/doc/guides/sending-events/getting-started).

## How to send events

InstantSearch widgets can automatically send certain events if you enable the [`insights`](/doc/api-reference/widgets/instantsearch/js#param-insights)
option when setting up your app.

For a full guide to implementing events, see [Send events with InstantSearch](/doc/guides/sending-events/instantsearch/send-events).

## Default events

With the `insights` middleware, your InstantSearch widgets send default events.
To check the default events, go to the [**Events Debugger**](https://dashboard.algolia.com/events/debugger).

For more information, see [Validate your events](/doc/guides/sending-events/guides/validate).

### Default click events for refinement widgets

The following widgets send `click` events ("Filter Applied") when users select a refinement.
[Custom widgets](/doc/guides/building-search-ui/widgets/customize-an-existing-widget/js) using the connectors send the same events.

| Widget                                                                                 | Connector                 |
| -------------------------------------------------------------------------------------- | ------------------------- |
| [`hierarchicalMenu`](/doc/api-reference/widgets/hierarchical-menu/js#param-send-event) | `connectHierarchicalMenu` |
| [`menu`](/doc/api-reference/widgets/menu/js#param-send-event)                          | `connectMenu`             |
| [`menuSelect`](/doc/api-reference/widgets/menu-select/js#param-send-event)             | `connectMenu`             |
| [`ratingMenu`](/doc/api-reference/widgets/rating-menu/js#param-send-event)             | `connectRatingMenu`       |
| [`refinementList`](/doc/api-reference/widgets/refinement-list/js#param-send-event)     | `connectRefinementList`   |
| [`toggleRefinement`](/doc/api-reference/widgets/toggle-refinement/js#param-send-event) | `connectToggleRefinement` |

<Note>
  Numeric refinement widgets don't send `clicked` events as the `clickedFilters` event does not apply to numeric filters. This is relevant for `connectNumericMenu`- and `connectRange`-based widgets.
</Note>

### Default view events for results widgets

The following widgets send `view` events ("Hits Viewed") for the visible items in the search results.
[Custom widgets](/doc/guides/building-search-ui/widgets/create-your-own-widgets/js) using the connectors send the same events.

| Widget                                                                         | Connector             |
| ------------------------------------------------------------------------------ | --------------------- |
| [`autocomplete`](/doc/api-reference/widgets/autocomplete/js#param-indices)     | `connectAutocomplete` |
| [`geoSearch`](/doc/api-reference/widgets/geo-search/js#param-send-event)       | `connectGeoSearch`    |
| [`hits`](/doc/api-reference/widgets/hits/js#param-send-event)                  | `connectHits`         |
| [`infiniteHits`](/doc/api-reference/widgets/infinite-hits/js#param-send-event) | `connectInfiniteHits` |

### Default click events for results widgets

The following widgets send `click` events ("Hit Clicked") when users click a search result.

| Widget                                                                         | Connector                                                                                                      |
| ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
| [`hits`](/doc/api-reference/widgets/hits/js#param-send-event)                  | [`connectHits`](/doc/api-reference/widgets/hits/js#customize-the-ui-with-connecthits)                          |
| [`infiniteHits`](/doc/api-reference/widgets/infinite-hits/js#param-send-event) | [`connectInfiniteHits`](/doc/api-reference/widgets/infinite-hits/js#customize-the-ui-with-connectinfinitehits) |

<Note>
  Because of technical limitations, the default `click` events aren't sent when using `connectHits` or `connectInfiniteHits`.
  If you're using connectors, make sure to set up `click` events on them.
</Note>

```js JavaScript theme={"system"}
function render(renderOptions, isFirstRender) {
  const { items, sendEvent, widgetParams } = renderOptions;

  widgetParams.container.innerHTML = `
    <ul>
      ${items
        .map(
          (item) =>
            `<li>
              ${instantsearch.highlight({ attribute: 'name', hit: item })}
            </li>`
        )
        .join('')}
    </ul>
  `;

  [...widgetParams.container.querySelectorAll('li')]
    .forEach((element, index) => {
      element.addEventListener('click', (event) => {
        sendEvent('click', hits[index], 'Hit Clicked');
      });
    });
}

const customHits = connectHits(render);
// or
const customInfiniteHits = connectInfiniteHits(render);
```
