Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugins): introduce Insights plugin #373

Merged
merged 5 commits into from
Nov 30, 2020

Conversation

francoischalifour
Copy link
Member

@francoischalifour francoischalifour commented Nov 19, 2020

This introduces a new Autocomplete plugin for Algolia Insights.

ac-insights-plugin

Introduction

This plugin aims at integrating Algolia Insights in your Autocomplete experience without setup. For advanced use cases, we inject the Insights API in the Context to have access to its methods anywhere in the Autocomplete hooks.

Usage

Insights events can be sent by default from:

  • onStateState: 400ms debounced when items change. The default is to send viewedObjectIDs events for each Algolia index.
  • onSelect: the default is to send a clickedObjectIDsAfterSearch event.
  • onHighlight: no default

If users need to send events for other actions, they can use the Context API.

Basic usage

const searchClient = algoliasearch(appId, apiKey);
insightsClient('init', { appId, apiKey });

const algoliaInsightsPlugin = createAlgoliaInsightsPlugin({ insightsClient });

autocomplete({
  container: '#autocomplete',
  plugins: [algoliaInsightsPlugin],
  getSources({ query }) {
    return [
      {
        getItems() {
          return getAlgoliaInsightsHits({
            searchClient,
            queries: [
              {
                query,
                indexName: 'instant_search',
              },
            ],
          });
        },
        templates: {
          item({ item }) {
            return item.name;
          },
        },
      },
    ];
  },
});

Custom usage

const algoliaInsightsPlugin = createAlgoliaInsightsPlugin({
  insightsClient,
  onHighlight({ insights, insightsEvents, event }) {
    if (event.type === 'keydown') {
      insights.viewedObjectIDs(
        ...insightsEvents.map((insightsEvent) => ({
          eventName: 'Item Highlighted with Keyboard',
          ...insightsEvent,
        }))
      );
    }
  },
});

Usage with other plugins

Other plugins usually using getAlgoliaHits need this search method to be replaced with an Insights-compatible method. We support this in the Query Suggestions plugin:

const querySuggestionsPlugin = createQuerySuggestionsPlugin({
  searchClient,
  indexName: 'instant_search_demo_query_suggestions',
  getAlgoliaHits: getAlgoliaInsightsHits,
  getSearchParams() {
    return recentSearchesPlugin.data.getAlgoliaSearchParams();
  },
});

The hits coming from the QS index will now have their index name and query ID attached for the Insights plugin to work.

Advanced usage using Context

If you want to send custom events from your templates (e.g., a conversion event from an "Add to cart" button), the Insights API is stored in the Context.

autocomplete({
  container: '#autocomplete',
  plugins: [algoliaInsightsPlugin],
  getSources({ query }) {
    return [
      {
        getItems() {
          return getAlgoliaInsightsHits({
            searchClient,
            queries: [
              {
                query,
                indexName: 'instant_search',
              },
            ],
          });
        },
        templates: {
          item({ item, state, root }) {
            const { insights } = state.context.algoliaInsightsPlugin;
            const element = document.createElement('div');
            const title = document.createElement('div');
            title.textContent = item.name;
            const button = document.createElement('button');
            button.textContent = 'Add to cart';
            button.addEventListener('click', (event) => {
              event.preventDefault();
              event.stopPropagation();

              insights.convertedObjectIDsAfterSearch({
                eventName: 'Added to cart',
                index: item.__autocomplete_indexName,
                objectIDs: [item.objectID],
                queryID: item.__autocomplete_queryID,
              });
            });

            element.appendChild(title);
            element.appendChild(button);
            root.appendChild(element);
          },
        },
      },
    ];
  },
});

Implementation

The plugin API has changed its subscription API

We used to have a subscribed object like this:

const myPlugin = {
  subscribed: {
    onSelect() {
      console.log('A source was selected.');
    },
  },
};

We now have a subscribe method that received all the setters and subscriber functions.

const myPlugin = {
  subscribe({ setContext, onSelect }) {
    setContext({ myPluginData });

    onSelect(() => {
      console.log('A source was selected.');
    });
  },
};

This reduces the API surface and make initial interactions with State and Context possible.

The Query Suggestions plugin now accepts a getAlgoliaHits method

This allows to plug the getAlgoliaInsightsHit method to make your QS compatible with Insights.

Next steps

  • It'd be nice to add a way to extend the state.context TypeScript type from plugins.
  • Write documentation

@codesandbox-ci
Copy link

codesandbox-ci bot commented Nov 19, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit e369512:

Sandbox Source
@algolia/js-example Configuration
@algolia/react-renderer-example Configuration

Copy link
Contributor

@Haroenv Haroenv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall, looks pretty good!

item,
insightsEvents: [
{
eventName: 'Item Selected',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might want to prefix these event names with autocomplete, that way it would be clearer how the usage is working exactly. Selected can mean a lot otherwise

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I asked the Insights team recommendation about that—waiting for their answer.

examples/js/app.ts Outdated Show resolved Hide resolved
@francoischalifour
Copy link
Member Author

In 11fcb2c I removed the getAlgoliaInsightsHits function and embedded the Insights feature in getAlgoliaHits.

Copy link
Contributor

@Haroenv Haroenv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, quick question

Copy link
Contributor

@Haroenv Haroenv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is good, but would like to keep freedom to consolidate or override the events. Could maybe done after the fact though, not sure!

@Haroenv
Copy link
Contributor

Haroenv commented Nov 30, 2020

Should there be a getAlgoliaInsightsQueryParameters (like there is for recent searches) that just sets clickAnalytics: true? Do we allow chaining of those methods (or a separate merging happening in the library itself)?

@francoischalifour
Copy link
Member Author

would like to keep freedom to consolidate or override the events

Does the current API not provide enough flexibility?

Should there be a getAlgoliaInsightsQueryParameters [...]

Possibly! We can introduce this in other PRs.

@Haroenv
Copy link
Contributor

Haroenv commented Nov 30, 2020

I misread what the public API is, it totally makes sense for the function call to be able to override the event name!

@francoischalifour francoischalifour merged commit 2e967be into next Nov 30, 2020
@francoischalifour francoischalifour deleted the feat/plugin-algolia-insights branch November 30, 2020 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants