Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@meilisearch/instant-meilisearch
Advanced tools
The search client to use Meilisearch with InstantSearch.
β‘ How to integrate a front-end search bar in your website using Meilisearch
Meilisearch is an open-source search engine. Discover what Meilisearch is!
This library is the search client that you should use to make Meilisearch work with InstantSearch. InstantSearch, an open-source project developed by Algolia, is the tool that renders all the components needed to start searching in your front-end application.
Instead of reinventing the wheel, we have opted to reuse the InstantSearch library for our own front-end tooling. We will contribute upstream any improvements that may result from our adoption of InstantSearch.
If you use Angular, React, or Vue, you might want to check out these repositories:
NB: If you don't have any Meilisearch instance running and containing your data, you should take a look at this getting started page.
For general information on how to use Meilisearchβsuch as our API reference, tutorials, guides, and in-depth articlesβrefer to our main documentation website.
Say goodbye to server deployment and manual updates with Meilisearch Cloud. No credit card required.
Use npm
or yarn
to install instant-meilisearch
:
npm install @meilisearch/instant-meilisearch
yarn add @meilisearch/instant-meilisearch
instant-meilisearch
is a client for instantsearch.js
. It does not create any UI component by itself.
To be able to create a search interface, you'll need to install instantsearch.js
as well.
import { instantMeiliSearch } from '@meilisearch/instant-meilisearch'
const { searchClient, setMeiliSearchParams } = instantMeiliSearch(
'https://ms-adf78ae33284-106.lon.meilisearch.io', // Host
'a63da4928426f12639e19d62886f621130f3fa9ff3c7534c5d179f0f51c4f303' // API key
)
where searchClient
is to be passed to instantsearch.js or its many framework adaptations, and setMeiliSearchParams
is a function used to set/modify certain Meilisearch search parameters to be overridden.
Host
- URL of Meilisearch instanceAPI Key
- Meilisearch access API Key. This can either be a string or a synchronous function that returns a string. β οΈ Prefer using a key with only search permissions as it is used on your front-end.instant-meilisearch
offers some options you can set to further fit your needs.
placeholderSearch
: Enable or disable placeholder search (default: true
).finitePagination
: Enable finite pagination when using the pagination
widget (default: false
) .primaryKey
: Specify the primary key of your documents (default undefined
).keepZeroFacets
: Show the facets value even when they have 0 matches (default false
).requestConfig
: Use custom request configurations.httpClient
: Use a custom HTTP client.meiliSearchParams
: Override a selection of Meilisearch search parameters (default undefined
).The options are added as the third parameter of the instantMeilisearch
function.
import { instantMeiliSearch } from '@meilisearch/instant-meilisearch'
const { searchClient } = instantMeiliSearch(
'https://ms-adf78ae33284-106.lon.meilisearch.io',
'a63da4928426f12639e19d62886f621130f3fa9ff3c7534c5d179f0f51c4f303',
{
placeholderSearch: false, // default: true.
primaryKey: 'id', // default: undefined
// ...
}
)
Placeholders search means showing results even when the search query is empty. By default it is true
.
When placeholder search is set to false
, no results appears when searching on no characters. For example, if the query is "" no results appear.
{ placeholderSearch : true } // default true
Finite pagination is used when you want to add a numbered pagination at the bottom of your hits (for example: << < 1, 2, 3 > >>
).
It requires the usage of the Pagination
widget.
Example:
{ finitePagination: true } // default: false
Specify the field in your documents containing the unique identifier (undefined
by default). By adding this option, we avoid instantSearch errors that are thrown in the browser console. In React
particularly, this option removes the Each child in a list should have a unique "key" prop
error.
{ primaryKey : 'id' } // default: undefined
keepZeroFacets
set to true
keeps the facets even when they have 0 matching documents (default false
).
When using refinementList
it happens that by checking some facets, the ones with no more valid documents disapear.
Nonetheless you might want to still showcase them even if they have 0 matched documents with the current request:
Without keepZeroFacets
set to true
:
genres:
With keepZeroFacets
set to false
, comedy
disapears:
genres:
{ keepZeroFacets : true } // default: false
You can provide a custom request configuration. Available field can be found here.
for example, with custom headers.
{
requestConfig: {
headers: {
Authorization: AUTH_TOKEN
},
credentials: 'include'
}
}
You can use your own HTTP client, for example, with axios
.
{
httpClient: async (url, opts) => {
const response = await $axios.request({
url,
data: opts?.body,
headers: opts?.headers,
method: (opts?.method?.toLocaleUpperCase() as Method) ?? 'GET'
})
return response.data
}
}
meiliSearchParams
lets you override a set of search parameters that are sent off to Meilisearch.
The following options can be overridden:
attributesToCrop
attributesToHighlight
attributesToRetrieve
attributesToSearchOn
cropLength
cropMarker
distinct
highlightPreTag
, highlightPostTag
hybrid
matchingStrategy
showMatchesPosition
showRankingScore
rankingScoreThreshold
instantMeiliSearch(
// ...
{
meiliSearchParams: {
attributesToHighlight: ['overview'],
highlightPreTag: '<em>',
highlightPostTag: '</em>',
attributesToSearchOn: ['overview'],
},
}
)
instantMeiliSearch
returns an instance with two properties on it, one of them being setMeiliSearchParams
.
const { searchClient, setMeiliSearchParams } = instantMeiliSearch(/*...*/)
It modifies (or sets if not already set) the overridden Meilisearch search parameters.
It only modifies parameters that are defined on the provided object, the following will not change attributesToHighlight
.
const { setMeiliSearchParams } = instantMeiliSearch(
// ...
{
meiliSearchParams: {
attributesToHighlight: ['overview'],
highlightPreTag: '<em>',
highlightPostTag: '</em>',
attributesToSearchOn: ['overview'],
},
}
)
setMeiliSearchParams({
highlightPreTag: '<mark>',
highlightPostTag: '</mark>',
attributesToSearchOn: ['overview', 'title'],
})
The open-source InstantSearch library powered by Algolia provides all the front-end tools you need to highly customize your search bar environment.
InstantSearch requires that you provide an indexName. The indexName corresponds to the index uid
in which your document are stored in Meilisearch.
In index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<body>
<div>
<div id="searchbox"></div>
<div id="hits"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/@meilisearch/instant-meilisearch/dist/instant-meilisearch.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4"></script>
<script src="./app.js"></script>
</body>
</html>
In app.js
:
const { searchClient } = instantMeiliSearch(
'https://ms-adf78ae33284-106.lon.meilisearch.io',
'a63da4928426f12639e19d62886f621130f3fa9ff3c7534c5d179f0f51c4f303'
)
const search = instantsearch({
indexName: 'steam-video-games',
searchClient,
})
search.addWidgets([
instantsearch.widgets.searchBox({
container: '#searchbox',
}),
instantsearch.widgets.hits({
container: '#hits',
templates: {
item: `
<div>
<div class="hit-name">
{{#helpers.highlight}}{ "attribute": "name" }{{/helpers.highlight}}
</div>
</div>
`,
},
}),
])
search.start()
π For a full getting started example, please take a look at this CodeSandbox:
π‘ If you have never used InstantSearch, we recommend reading this getting started documentation.
Supported InstantSearch.js versions:
This package only guarantees the compatibility with the version v4 of InstantSearch.js. It may work with older or newer InstantSearch versions, but these are not tested nor officially supported at this time.
Supported Meilisearch versions:
This package guarantees compatibility with version v1.x of Meilisearch, but some features may not be present. Please check the issues for more info.
Node / NPM versions:
List of all the components that are available in instantSearch and their compatibility with Meilisearch.
instantSearch
is the main component. It manages the widget and lets you add new ones.
uid
of your index. requiredconst search = instantsearch({
indexName: 'instant_search',
searchClient: instantMeiliSearch(
'https://ms-adf78ae33284-106.lon.meilisearch.io',
'a63da4928426f12639e19d62886f621130f3fa9ff3c7534c5d179f0f51c4f303',
{
// ... InstantMeiliSearch options
}
).searchClient,
// ... InstantSearch options
routing: true // for example
})
Index
is the component that lets you apply widgets to a dedicated index. Itβs useful if you want to build an interface that targets multiple indices.
The searchBox
widget is used to let the user perform a text-based query.
instantsearch.widgets.searchBox({
container: '#searchbox',
autofocus: true,
...searchBoxOptions
}),
The configure
widget lets you provide raw search parameters to the Algolia API without rendering anything.
Because these are the search parameters of AlgoliaSearch and not the InstantSearch parameters, some of them are ignored by InstantSearch.
Since we do not act as AlgoliaSearch on search parameters, detailed compatibility can be found in this issue.
This component should only be used if no other component provides the same configuration.
We also suggest looking at Meilisearch's search parameters to determine how they act.
instantsearch.widgets.configure({
hitsPerPage: 20,
// other algoliasearch parameters
})
ConfigureRelatedItems references.
No compatibility with Meilisearch because the component uses sumOrFiltersScores and optionalFilters search parameters that do not exist in Meilisearch.
The panel
widget wraps other widgets in a consistent panel design.
Deprecated component in InstantSearch in favor of autocomplete package.
InstantMeilisearch is not compatible with the autocomplete package.
The voiceSearch
widget lets the user perform a voice-based query.
Search Insights lets you report click, conversion and view metrics.
More details about the subject are given in this issue.
Requires InstantSearch v4.8.3 or later.
Middleware is a function returning an object with onStateChange
, subscribe
and unsubscribe
functions. With the middleware API, you can inject functionalities in the InstantSearch lifecycle.
Provides all the data and functions from the widgets.
It works only on widgets that are compatible with instant-meilisearch
.
Used to display a list of results.
instantsearch.widgets.hits({
container: '#hits',
templates: {
item: `
<div>
<div class="hit-name">
{{#helpers.highlight}}{ "attribute": "title" }{{/helpers.highlight}}
</div>
</div>
`,
},
})
The infiniteHits
widget is used to display a list of results with a βShow moreβ button.
instantsearch.widgets.infiniteHits({
container: '#infinite-hits',
templates: {
item: `
<h2>
{{#helpers.highlight}}{ "attribute": "name" }{{/helpers.highlight}}
</h2>
`,
},
})
The highlight
function returns an attribute from a hit into its highlighted form, when relevant.
See Hits for an example.
The snippet
function returns an attribute from a hit into its snippet form, when relevant.
Note that the attribute has to be added to attributesToSnippet
in configuration. Highlight is applied on snippeted fields.
Snippeting is called cropping
in Meilisearch, more about it here. It is possible to change the size of the snippeting by adding its character size in the attributesToSnippet parameter.
For example: "description:40"
.
The 40
value represents the number of characters (rounded down to always have full words) and not the number of words. Thus, the snippet string size is always equal to or lower than 40
characters.
instantsearch.widgets.configure({
attributesToSnippet: ['description:40'],
})
instantsearch.widgets.hits({
// ...
templates: {
item: `
<p>{{#helpers.snippet}}{ "attribute": "description" }{{/helpers.snippet}}</p>
`,
},
})
The geoSearch
widget displays search results on a Google Map. It lets you search for results based on their position and provides some common usage patterns such as βsearch on map interactionsβ.
β container: The CSS Selector or HTMLElement to insert the Google maps into. required
β googleReference: The reference to the global window.google object. See the Google Maps documentation for more information. required
β initialZoom: When no search results are found, google map will default to this zoom.
β initialPosition: When no search results are found, google map will default to this position.
β mapOptions: The options forwarded to the Google Maps constructor.
β builtInMarker: Used to customize Google Maps markers. Because of lack of tests we cannot guarantee its compatibility. For more information please visit InstantSearch related documentation.
customHTMLMarker: Same as builtInMarker
. Because of lack of tests, we cannot guarantee its compatibility. For more information please visit InstantSearch related documentation.
β enableRefine: If true, the map is used for refining the search. Otherwise, itβs only for display purposes.
β
enableClearMapRefinement: If true
, a button is displayed on the map when the refinement is coming from interacting with it, to remove it.
β
enableRefineControl: If true
, the map is used for refining the search. Otherwise, itβs only for display purposes.
β
enableRefineOnMapMove: If true
, a button is displayed on the map when the refinement is coming from interacting with it, to remove it.,
β templates: The templates to use for the widget.
β cssClasses: The CSS classes to override.
See our playground for a working exemple and this section in our contributing guide to set up your Meilisearch
.
The Geosearch widgey only works with a valid Google API key.
In order to communicate your Google API key, your instantSearch
widget should be surrounded by the following function:
import injectScript from 'scriptjs'
injectScript(
`https://maps.googleapis.com/maps/api/js?v=quarterly&key=${GOOGLE_API}`,
() => {
const search = instantsearch({
indexName: 'geo',
// ...
})
// ...
})
Replace ${GOOGLE_API}
with you google api key.
See code example in the playground
The classic usage, with only the required
elements, renders an embedded Google Map on which you can move and refine search based on the position maps.
instantsearch.widgets.geoSearch({
container: '#maps',
googleReference: window.google,
}),
For further customization, for example to determine an initial position for the map. Contrary to initialZoom
and initialPosition
, triggers a search request with the provided information.
The following parameters exist:
boundingBox
: The Google Map window box. It is used as parameter in a search request. It takes precedent on all the following parameters.aroundLatLng
: The middle point of the Google Map. If insideBoundingBox
or boundingBox
is present, it is ignored.aroundRadius
: The radius around a Geo Point, used for sorting in the search request. It only works if aroundLatLng
is present as well. If insideBoundingBox
or boundingBox
is present, it is ignored.For exemple, by adding boundingBox
in the instantSearch
widget parameters, the parameter will be used as a search parameter for the first request.
initialUiState: {
geo: {
geoSearch: {
boundingBox:
'50.680720183653065, 3.273798366642514,50.55969330590075, 2.9625244444490253',
},
},
},
Without providing this parameter, Google Maps will default to a window containing all markers from the provided search results.
Alternatively, the parameters can be passed through the searchFunction
parameter of the instantSearch
widget. Contrary to initialUiState
these parameters overwrite the values on each search.
searchFunction: function (helper) {
helper.setQueryParameter('aroundRadius', 75000)
helper.setQueryParameter('aroundLatLng', '51.1241999, 9.662499900000057');
helper.search()
},
Read the guide on how GeoSearch works in Meilisearch.
No compatibility because Meilisearch does not support this experimental feature.
The refinementList
widget is one of the most common widgets you can find in a search UI. With this widget, the user can filter the dataset based on facets.
and
or or
(and
is the default value).searchable
.searchable
.transformItems
options.The following example will create a UI component with the a list of genres on which you will be able to facet.
instantsearch.widgets.refinementList({
container: '#refinement-list',
attribute: 'genres',
})
β οΈ To make refinementList work, please refer to this.
The hierarchicalMenu
widget is used to create navigation based on a hierarchy of facet attributes. It is commonly used for categories with subcategories. See usage below.
2
).>
).To make it work with Meilisearch your documents must have a specific structure, an explanation of the structure can be found here.
Contrary to instantsearch.js
, the hierarchical fields are added in filterableAttributes
.
Example: Give the following document structure:
{
"id": 1,
"name": "Basic T-shirt",
"categories.lvl0": "Men",
"categories.lvl1": "Men > clothes",
"categories.lvl2": "Men > clothes > t-shirt"
}
You have to add the fields categories.lvl0
, categories.lvl1
and categories.lvl2
in the filterableAttributes
in your Meilisearch settings.
{
"filterableAttributes": [
"categories.lvl0",
"categories.lvl1",
"categories.lvl2"
]
}
The rangeSlider
widget provides a user-friendly way to filter the results, based on a single numeric range.
rangeSlider
.To be able to use the rangeSlider
on an attribute, the attribute must be in thefilterableAttributes
and must contain numeric values.
The menu
widget displays a menu that lets the user choose a single value for a specific attribute.
showMoreLimit > limit
transformItems
options.The currentRefinements
widget displays a list of refinements applied to the search.
The rangeInput
widget allows a user to select a numeric range using a minimum and maximum input.
To be able to use the RangeInput
on an attribute, the attribute must be in thefilterableAttributes
and must contain numeric values.
The menuSelect
widget allows a user to select a single value to refine inside a select element.
transformItems
options.The numericMenu widget displays a list of numeric filters in a list. Those numeric filters are pre-configured when creating the widget.
The toggleRefinement widget provides an on/off filtering feature based on an attribute value.
The numericMenu
widget displays a list of numeric filters in a list. Those numeric filters are pre-configured when creating the widget.
The RatingMenu
widget lets the user refine search results by clicking on stars. The stars are based on the selected attribute.
Contrary to instantsearch.js
, To be able to use RatingMenu
the field containing the rating has to be added in the filterableAttributes
setting in your index settings.
The clearRefinement
widget displays a button that lets the user clean every refinement applied to the search. You can control which attributes are impacted by the button with the options.
instantsearch.widgets.clearRefinements({
container: '#clear-refinements',
}),
The pagination
widget displays a pagination system allowing the user to change the current page. It should be used alongside the finitePagination
setting to render the correct amount of pages.
instantsearch.widgets.pagination({
container: '#pagination',
})
The hitsPerPage
widget displays a dropdown menu to let the user change the number of displayed hits.
The breadcrumb
widget is a secondary navigation scheme that lets the user see where the current page is in relation to the facetβs hierarchy. The HierarchicalMenu
widget has the same requirements, see its usage to make breadcrumb work.
>
).The stats
widget displays the total number of matching hits and the time it took to get them (time spent in the Algolia server).
instantsearch.widgets.stats({
container: '#stats',
})
Deprecated. See Insight.
QueryRuleCustomData references
You may want to use this widget to display banners or recommendations returned by Rules, and that match search parameters.
No compatibility because Meilisearch does not support Rules.
The queryRuleContext widget lets you apply ruleContexts based on filters to trigger context-dependent Rules.
No compatibility because Meilisearch does not support Rules.
The SortBy
widget is used to create multiple sort formulas. Allowing a user to change the way hits are sorted.
The usage of the SortBy
widget differs from the one found in Algolia's documentation. In instant-meilisearch the following is possible:
sort
rules on the same index.The items list is composed of objects containing every sort possibility you want to provide to your user. Each object must contain two fields:
label
: What is showcased on the user interface ex: Sort by Ascending Price
value
: The sort formula.A sort formula is expressed like this: index:attribute:order
.
index
is mandatory, and when adding attribute:order
, they must always be added together.
When sorting on an attribute, the attribute has to be added to the sortableAttributes
setting on your index.
Example:
[
{ label: 'Sort By Price', value: 'clothes:price:asc' }
]
In this scenario, in the clothes
index, we want the price to be sorted in an ascending way. For this formula to be valid, price
must be added to the sortableAttributes
settings of the clothes
index.
The impact sorting has on the returned hits is determined by the ranking-rules
ordered list of each index. The sort
ranking-rule position in the list makes sorting documents more or less important than other rules. If you want to change the sort impact on the relevancy, it is possible to change it in the ranking-rule setting. For example, to favor exhaustivity over relevancy.
See relevancy guide.
instantsearch.widgets.sortBy({
container: '#sort-by',
items: [
{ value: 'clothes', label: 'Relevant' }, // default index
{
value: 'clothes:price:desc', // Sort on descending price
label: 'Ascending price using query time sort',
},
{
value: 'clothes:price:asc', // Sort on ascending price
label: 'Descending price using query time sort',
},
{
value: 'clothes-sorted', // different index with different ranking rules.
label: 'Custom sort using a different index',
},
],
}),
Virtual indices allow you to use Relevant sort, a sorting mechanism that favors relevancy over the attribute youβre sorting on.
Routing is configured inside instantSearch
component. Please refer to the documentation for further implementation information.
Any new contribution is more than welcome in this project!
If you want to know more about the development workflow or want to contribute, please visit our contributing guidelines for detailed instructions!
Meilisearch provides and maintains many SDKs and Integration tools like this one. We want to provide everyone with an amazing search experience for any kind of project. If you want to contribute, make suggestions, or just know what's going on right now, visit us in the integration-guides repository.
FAQs
The search client to use Meilisearch with InstantSearch.
The npm package @meilisearch/instant-meilisearch receives a total of 19,326 weekly downloads. As such, @meilisearch/instant-meilisearch popularity was classified as popular.
We found that @meilisearch/instant-meilisearch demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.