Guides

Guide To Using Algolia's InstantSearch.js With Meilisearch

Who Is This Guide For?

This guide is for website owners and digital marketing leads. You have some knowledge of the different tech components that make up the website you manage, but you need a bit of background into how something like Meilisearch would work on your site.

Why Do I Need This Guide?

The InstantSearch javascript library makes the creation of the search interface on your website easy and inexpensive. If you're planning to improve site search using Meilisearch, the way it will be done is important to you. This guide should help.

Meilisearch

Meilisearch is an advanced search utility that you integrate into your website or mobile app. It returns highly relevant results faster than you can blink. It is in the family of Algolia, Typesense, &c. It's highly configurable and extremely flexible. Meilisearch is available as a service or it can be self-hosted. But in either case, it runs on separate servers from your website.

If you would like to read a more comprehensive introduction to Meilisearch you can read our overview post about it here. We also created a demo if you want to just jump into experiencing it here.

InstantSearch

Algolia, a competitor with Meilisearch, offers a number of open source libraries to help build the front-end aspect of search interfaces. Algolia offers libraries for Vue, React, and Angular Javascript frameworks as well as libraries for Android and iOS apps. Additionally, they offer a more vanilla Javascript library called InstantSearch.js. That's the library that this guide covers.

If your site reflects the complex business rules of your organization’s offerings, your developers may already be using React or Vue. If this is the case they may opt to use the Vue or React InstantSearch libraries. Otherwise, they will get a lot of good use out of InstantSearch.js.

Install It

InstantSearch.js can be installed alongside most any other Javascript code on your site. The library uses variable prefixing and other methods to avoid conflicting with your other website code.

Your developers may opt to install InstantSearch.js using a package manager like npm or they may simply include the library in whatever website pages they need. Algolia's installation guide is a friendly read and can give you more background.

Invoke It

So your developer has added the InstantSearch.js library to one of your site pages. Now they invoke it in one of your site's main Javascript files. You can see in our demo that the app.js file here creates an instance of InstantSearch for the page using code like this:

const search = instantsearch({
  indexName: 'places',
  searchClient: instantMeiliSearch(
    'https://meilisearch.solspace.net/',
    '7675b9292628ccf044e98c557257783b91889793852ed8869836e6747f76f70f'
  )
});

The const search = instantsearch part creates an instance of the InstantSearch class. All the methods that are part of that class become available to us on the page. We tell InstantSearch that we want it to use the instantMeiliSearch library to make the connection between our Meilisearch service and InstantSearch. You can see more about that connector here.

Send In The Widgets!

InstantSearch treats all of the interesting UX components as widgets. Within the search object you invoked above, you add all of the widgets you might need. For example, the widget that contains your search results is called the 'hits' widget. You invoke it like this:

search.addWidgets([
  instantsearch.widgets.hits({
    container: '#hits'
  })
])

'#hits' is the id of an HTML element on your page, like a DIV tag or SECTION tag or something. InstantSearch will drop in its own HTML of your search results in real-time as people search on your page.

Add A Keyword Search Field

A search field is just another widget on your page. A standard search field comes prepackaged with InstantSearch. You can tell InstantSearch to add it to your page in an HTML element with an id of 'searchbox'.

search.addWidgets([
  searchBox({
    container: '#searchbox',
  });
])

Search Filters

If all you need is keyword searching you might not even need Meilisearch, but most of our clients need to support complex searches with multiple filters. These are often checkboxes, pulldowns and radio buttons arranged in complex ways to make sifting through intricate data sets possible. For this, you need the InstantSearch refinementList widget.

Your Meilisearch index (or often indexes) is made up of documents. Each document has the same set of fields and attributes. For example, in our demo, each business listing has a city field and a state field. Each listing has an ambience attribute, etc. Some of these fields have a finite set of options, such as ambience having values like romantic or touristy. You can add a filter for each attribute and InstantSearch will populate that with the relevant choices for the attribute. Here's how you would add an ambience filter:

search.addWidgets([
  instantsearch.widgets.refinementList({
    container: '#facetAmbience',
    attribute: 'ambience',
  }),
])

The above snippet of InstantSearch code looks for an HTML element on the page with an id of 'facetAmbience'. It builds a list of checkbox values inside that HTML element. Users can click on one or more checkboxes to filter results. By default the filters are additive. If you select 'romantic' and 'touristy' you only get results that have both of those values in their ambience list. You can build as many filters as you want like this into your web page just by adding more refinementList widgets.

Note that for the filtering functionality to work you have to Meilisearch that a given attribute is filterable. There will be a separate guide on these configuration options soon.

Sorting

When would you show users search results but not allow them to sort the results based on the various criteria they care about? InstantSearch offers a sort field widget that you can use for this. Here's how you create it on the page:

search.addWidgets([
  instantsearch.widgets.sortBy({
    container: '#sortBy',
    items: [{
      label: 'Highest Rated',
      value: 'places: stars:desc'
    }, {
      label: 'Alphabetical',
      value: 'places:title:asc'
    }, {
      label: 'Random',
      value: 'places:randomNumber:asc'
    }]
  }),
])

As with the other widgets, you target an HTML element on your page by its id. In the case of the sortBy widget though, you also provide a list of Meilisearch indexes. The sortBy widget assumes that you have defined individual Meilisearch indexes for each type of sort. This is a lot of work, so luckily there is an alternative method. It's not well documented, but it's very useful.

As above, you indicate an index name, then a colon, then an attribute, then a sort order. This way you only need one Meilisearch index. And as long as the index has a proper set of sortable fields indicated in the 'sortableAttributes' index setting, you'll be fine.

Random Sorting

In the above example, you may have noticed a random sort option. Your actual users would likely not care to use such an option, but the ability to sort search results randomly is still useful for other business reasons.

We have a client whose customers pay a monthly fee to be listed on their website. Part of their contract is the assurance that they will have an equal chance of appearing at the top of search results. An architecture principle in Meilisearch is that you should always get the same set of results for the same search criteria. Meilisearch, therefore, does not have built-in randomization capability. We work around this by assigning a random number to a special 'randomNumber' field on every document in a Meilisearch index. We then sort on this field to get randomized results. We have a back-end process that re-randomizes all documents every 24 hours. In the future, Meilisearch may add support for randomization, but for now, this method works.

Pagination

You will almost always want to provide paginated search results. Showing 50 to 100 results per page instead of all 50,000 in one scroll is much more user-friendly and it takes the load off of the server and the web browser's ability to return a page.

Here's the code to invoke the pagination widget:

search.addWidgets([
  instantsearch.widgets.pagination({
    container: '#pagination'
  })
])

As with the other widgets, you target an HTML element by its id. InstantSearch adds its own HTML to that div. You can style that code with your CSS or you can manipulate it with some additional template or CSS widget options. Pretty much all InstantSearch widgets have this override capability.

Hard-coding Stuff

When creating interfaces for customers and clients, it can be really powerful to hard-code some search behaviors. Sometimes you may want to create a page that forces a certain filter on every search. In our demo, we hard-code a filter on every search such that only results with a value of 'true' for a field called 'enabled' are shown. In our CMS, an entry can be enabled or disabled. Disabled entries don't show on the website. When we built our Meilisearch index we just decided to include all entries, enabled or disabled. We knew we could filter out entries on the page itself. Here's how:

InstantSearch exposes a helper class that provides a bunch of useful utilities. You use this helper class to manipulate search, among other things.

helper.setQueryParameter('filters', 'enabled=true').search();

The above snippet tells InstantSearch to always filter results by the enabled / true value. Here's how it looks when you invoke it on the search object:

const search = instantsearch({
  indexName: 'places',
  searchClient: instantMeiliSearch(
    'https://meilisearch.solspace.net/',
    '7675b9292628ccf044e98c557257783b91889793852ed8869836e6747f76f70f'
  ),
  searchFunction: function(helper) {
    //  Return only entries marked as enabled.
    helper.setQueryParameter('filters', 'enabled=true').search();
  }
});

Wrapping Up

This guide was an attempt to show the merits of using the ready-made InstantSearch Javascript library with Meilisearch. InstantSearch takes a lot of the trouble out of building a search interface on your site. Your developer will be estimating the costs of adding Meilisearch to your site. The interface is a big part of the cost. InstantSearch reduces the cost.

The big question for you and your team is can InstantSearch be customized enough for your needs or do you need to write more raw code to get the job done?

Remember that you can always build websites and website features in phases. You don't have to get it right the first time and you likely will not. Adopt an attitude of progressive improvement based on customer feedback and user data and you will do well. InstantSearch allows you to fairly easily add Meilisearch to your site. You can customize it from there.