InstantSearch and virtual refinements

Hi,
I am using InstantSearch JS and hidden/virtual refinements that filter the results based on parameters hidden for the end users. The problem is that when there are no refinements there is only one query section in the request to Algolia, but the moment some refinements are applied there are the same amount of additional queries added to the request with “hitsPerPage=1”. That generates more search operations for my plan quota.
Do you know how to solve that?
Thanks in advance

Hi @kristiyan

If the hidden filters don’t need to be disjuctive, you can just use “configure” widget for this.

instantsearch.widgets.configure({
  filters: 'brand:Apple',
}),

This won’t add any extra query.

Plus, if you upgrade to the latest pricing plan, multiple queries in a request is just counted as one.

Let me know how it goes!

Hi @eunjae.lee
Is there a way to dynamically add/remove filters without page reload?

Hi @kristiyan

  instantsearch.widgets.configure({
    filters: 'brand:Apple',
  }),

This will set the initial filter of “brand:Apple”.

And this custom widget will help you change it later.

const customWidget = instantsearch.connectors.connectConfigure(
  ({ widgetParams, refine }, isFirstRendering) => {
    const container = document.querySelector(widgetParams.container);
    if (isFirstRendering) {
      container.innerHTML = `
        <button type="button">Click me</button>
      `;
      container.querySelector('button').addEventListener('click', () => {
        refine({ filters: 'brand:Samsung' });
      });
    }
  }
);

When users click this button, it will refine with “brand:Samsung”. You can also save this refine function somewhere in upper level or globally, then you can call it anytime programmatically.

Does it help you? Let me know :slight_smile:

Hi @eunjae.lee
I will test this approach.
In the meantime is there a way to get the current filters parameter or configuration from the instantsearch instance (from “search”)

const search = instantsearch({…})

Hello,
You can get the filters via “helper” which is an internal API, but I don’t recommend it.

If you implement it with the custom widget like I suggested above, you can store the filters somewhere in the upper scope.

let filters; // <- like this

const customWidget = instantsearch.connectors.connectConfigure(
  ({ widgetParams, refine }, isFirstRendering) => {
    const container = document.querySelector(widgetParams.container);
    if (isFirstRendering) {
      container.innerHTML = `
        <button type="button">Click me</button>
      `;
      container.querySelector('button').addEventListener('click', () => {
        filters = 'brand:Samsung';
        refine({ filters });
      });
    }
  }
);

Thank you for the advices,

I will modify the “helper.state.filters” property, because refine is executing a search, that is not needed all the time. In my case I have to modify the filters and only if the user type something to search and show results.

Oh in that case, the modification in helper.state.filters can get lost, because that’s not how we mutate helper.state.

You may want to utilize searchFunction.

const search = instantsearch({
  // ...
  searchFunction(helper) {
    if (insert-your-condition) {
      helper.setQueryParameter('filters', ....)
            .search();
    }
  }
});

Let me know how it goes.