Visual elements
Omnisearch
This visual element is the work horse of Omnisearch - it's what returns search results from your provider of choice.

Inputs
Search ProviderThe search provider you've synced your data with.Result typeSearch result data type.Search querySet to the Typing TriggerOutput textfor best results. An empty search query returns all results matchingFilters.Fields to searchThe Bubble fields to search supplied as a JSON list.FiltersThis section allows you to compose your filters using Javascript. For details, checkout our Filters Deep Dive section.Sort byA dictionary of the fields to sort by specified in JSON.Results per pageNumber of search results returned in each page of results.PageThe current page of search results to display starting at "1".Field to highlightField name to return highlights for. Must be one of the fields already listed inFields to search.Advanced optionsAdditional options for tuning search results. See details in our Advanced options section
Outputs
Search ResultsList of matched bubble things of the data type specified byData Type.Results CountNumber of results.Search TimeThe time it took to return a search result in milliseconds.Page CountNumber of pages of results for the current search.Returned errorA Yes/No indicating whether there was an error.Error descriptionAdditional text describing the error.HighlightsList of matched highlight snippets.Actual pageThe actual page of search results returned.
Filters deep dive
This section applies to the following visual elements:
Whether you want to filter by a single dropdown or apply 12 different criteria with conditional dependencies, our filtering capability is flexible enough to accomodate most needs. The most important thing to know is our Filters input exists to accomplish one goal:
Make a string of text your search provider can interpret as filters.
That's the big idea. Our search providers expect filter strings that contain boolean operators, numeric comparisons, GeoJSON, and more - so to accomodate this, we've made our Filters input expect Javascript. If you're familiar with the Expression element from the Toolbox plugin, then you should feel right at home using this.
The examples that follow will get you filtering with Omnisearch, starting simple and then getting more complex. We'll be looking at search provider specific implementations, so be sure to click the right one below to follow along.
Low Complexity
- Algolia
- Typesense
These examples are from our Algolia Filter demo. Check out it's Bubble editor page to see and interact with these in context.
Behold. The simplist filter you can build.
"usage_count<40"
Like we said, the goal of the Filters expression is to create a set of filter intructions Algolia can understand. Here, this text asks Algolia to:
Return all records where the
usage_countis less than40
We're leaning on Algolia's Filter by numeric syntax to accomplish this. To learn about all of Algolia's filter grammars, check out their excellent documentation here.
Finally, please note that field names themselves (i.e. usage_count above) are case sensitive - they should match the case of the field names as written in your Bubble database.
These examples are from our Typesense Filter demo. Check out it's Bubble editor page to see and interact with these in context.
Behold. The simplist filter you can build.
"usage_count<40"
Like we said, the goal of the Filters expression is to create a set of filter intructions Typesense can understand. Here, this text asks Typesense to:
Return all records where the
usage_countis less than40
We're leaning on Typesense's numeric filtering syntax to accomplish this. To learn about all of Typesense's filter grammars, check out their excellent documentation here.
Finally, please note that field names themselves (i.e. usage_count above) are case sensitive - they should match the case of the field names as written in your Bubble database.
Mid Complexity
- Algolia
- Typesense
This next example uses Javascript's ternary operator to conditionally build a filter text.
var categories_filter = (Multidropdown Categories value:count > 0) ? "categories:'Multidropdown Categories value:each items Display join with ' AND categories:''": ""
categories_filter
Let's break it down. We're asking Algolia to:
Return all records where the
categoriesfield contains all of the items fromMultidropdown Categories, but only ifMultidropdown Categorieshas at least one value selected.
If we were to build this filter in Bubble's native search, we'd Do a search for and check ignore empty constraints to ignore the Multidropdown Categories when empty.
Javascript's ternary operator is our way of accomplishing the same thing. It's a condensed form of an if... else... statement and it looks like this:
var our_variable = (some_condition) ? "value_A" : "value_B"
What happens here is when some_condition is true, then our_variable will be assigned the text "value_A". Otherwise it will be assigned "value_B".
So in our example,
var categories_filter = (Multidropdown Categories value:count > 0) ? "categories:'Multidropdown Categories value:each items Display join with ' AND categories:''": ""
categories_filter
we check if Multidropdown Categories value:count > 0.
If it is zero, then we assign the empty text
""tocategories_filter. As a result, Algolia will not apply any filters to our search results.If it is greater than zero, here we ultimately want to make text that looks something like
"categories:'technical' AND categories:'social network'"So to do that, we:
- start with the phrase
categories:' - append
' AND categories:'to eachMultidropdown Categories value - and finish off the string with a single quotation mark
'
Put it all together, and that looks like:
"categories:'Multidropdown Categories value:each items Display join with ' AND categories:''"- start with the phrase
With the categories_filter variable completely defined, the last thing to do in the Filters input is state the variable we want to return. Since we only have one filter variable, categories_filter, that's the one we state.
To close, in this example we leaned on Algolia's Boolean Operator syntax to AND multiple category filters together. Whether our source values come from a Multidropdown, a List Intersection, or some other list, you can use the same approach to make filters that return records matching ALL items within a list field. Note that Algolia also has the boolean operator OR which can be used to return records that match ANY items within a list field. They've also got a NOT operator that, along with AND and OR, can be chained and scoped using parenthesis () to craft even more sophisticated filters.
This next example uses Javascript's ternary operator to conditionally build a filter text.
var categories_filter = (Multidropdown Categories value:count > 0) ? "categories:='Multidropdown Categories value:each items Display join with ' && categories:''": ""
categories_filter
Let's break it down. We're asking Typesense to:
Return all records where the
categoriesfield contains all of the items fromMultidropdown Categories, but only ifMultidropdown Categorieshas at least one value selected.
If we were to build this filter in Bubble's native search, we'd Do a search for and check ignore empty constraints to ignore the Multidropdown Categories when empty.
Javascript's ternary operator is our way of accomplishing the same thing. It's a condensed form of an if... else... statement and it looks like this:
var our_variable = (some_condition) ? "value_A" : "value_B"
What happens here is when some_condition is true, then our_variable will be assigned the text "value_A". Otherwise it will be assigned "value_B".
So in our example,
var categories_filter = (Multidropdown Categories value:count > 0) ? "categories:='Multidropdown Categories value:each items Display join with ' && categories:''": ""
categories_filter
we check if Multidropdown Categories value:count > 0.
If it is zero, then we assign the empty text
""tocategories_filter. As a result, Typesense will not apply any filters to our search results.If it is greater than zero, here we ultimately want to make text that looks something like
"categories:='technical' && categories:='social network'"So to do that, we:
- start with the phrase
categories:=' - append
' && categories:='to eachMultidropdown Categories value - and finish off the string with a single quotation mark
'
Put it all together, and that looks like:
"categories:='Multidropdown Categories value:each items Display join with ' && categories:''"- start with the phrase
With the categories_filter variable completely defined, the last thing to do in the Filters input is state the variable we want to return. Since we only have one filter variable, categories_filter, that's the one we state.
To close, in this example we leaned on Typesense's Boolean Operator syntax to && multiple category filters together. Whether our source values come from a Multidropdown, a List Intersection, or some other list, you can use the same approach to make filters that return records matching ALL items within a list field. Note that Typesense also has the boolean operator || which can be used to return records that match ANY items within a list field. Their && and || operators can be chained and scoped using parenthesis () to craft even more sophisticated filters.
High-ish Complexity
- Algolia
- Typesense
Let's combine multiple filters.
var categories_filter = (Multidropdown Categories value:count > 0) ? " AND categories:'Multidropdown Categories value:each items Display join with ' AND categories:''": ""
var usage_filter = " AND usage_count:SliderInput Usage Counts value:min TO SliderInput Usage Counts value:max"
// Format our condition so that yes is "true" and no is 'false'
var open_source_filter = " AND published_open_source:Checkbox Is open source is checked:formatted as text"
var filters = categories_filter + usage_filter + open_source_filter
filters
Our three filters are as follow:
- The
Multidropdown Categoriesfilter from our last example. - A
usage_countfilter using Algolia's numeric range filter syntax. - A
published_open_sourcefilter using Algolia's boolean filter syntax. If the relevant checkbox is checked, then we format it's value as a text where'yes'istrueand'no'isfalse(since that's what Algolia expects).
With all three filter texts defined, we then concatenate them together into the variable filters using Javascript's + operator. Finally, we write filters so that our visual element knows it's the variable containing our full filter text.
Readers may notice we start each filter with the phrase " AND ". As mentioned in our mid-complexity example, this is done so that when our filter strings are appended to each other, there's an AND in between them just the way Algolia expects. Of course, if your use case merits something else - you can also use OR or NOT as Algolia allows.
Let's combine multiple filters.
var categories_filter = (Multidropdown Categories value:count > 0) ? " && categories:='Multidropdown Categories value:each items Display join with ' && categories:=''": ""
var usage_filter = " && usage_count:[SliderInput Usage Counts value:min..SliderInput Usage Counts value:max]"
// Format our condition so that yes is "true" and no is 'false'
var open_source_filter = " && published_open_source:=Checkbox Is open source is checked:formatted as text"
var filters = categories_filter + usage_filter + open_source_filter
filters
Our three filters are as follow:
- The
Multidropdown Categoriesfilter from our last example. - A
usage_countfilter using Typesense's numeric range filter syntax. - A
published_open_sourcefilter using Typesense's boolean filter syntax. If the relevant checkbox is checked, then we format it's value as a text where'yes'istrueand'no'isfalse(since that's what Typesense expects).
With all three filter texts defined, we then concatenate them together into the variable filters using Javascript's + operator. Finally, we write filters so that our visual element knows it's the variable containing our full filter text.
Readers may notice we start each filter with the phrase " && ". As mentioned in our mid-complexity example, this is done so that when our filter strings are appended to each other, there's an && in between them just the way Typesense expects. Of course, if your use case merits something else - you can also use OR as Typesense allows.
Filter input vs Toolbox's Expression element
- Algolia
- Typesense
Earlier we said the Filters input behaves like the Expression element from the Toolbox plugin. In truth, we've made a few changes behind the scenes to make writing filters as easy possible:
If the resulting
Filterstext starts with the phrase' AND 'or' OR ', then we remove that part before sending your filters to Algolia.To understand why, imagine a filter composed of two ternary operators:
var my_filter = ternary_filter_a + ternary_filter_bIf
ternary_filter_ais inactive due to, say, an empty Bubble dropdown, then onlyternary_filter_bcontributes tomy_filter. Butternary_filter_blikely starts with the phraseAND(orOR) which, if sent to Algolia, would cause an error. So, to maintain order in the universe, we remove those leading phrases.We interpret non-quoted appearances of the phrase
yesandnoas Javascript's booleantrueandfalse, respectively. We interpret quoted appearances of the phrase:yesand:noas the phrase:trueand:false, respectively. Together, this allows you to use Bubble's Dynamicyes/noexpressions in filters without having toFormatted as textthe value totrueorfalse, which is what Algolia expects.We interpret non-quoted dates as UNIX timestamps (ms) as follows:
MMM D, YYYY h:mm aThe date Dec 23, 2023 10:31 pm converts to 1703392260000. This is the default date format produced by Bubble dynamic expressions that resolve a date.MMMM D, YYYY h:mm aThe date December 23, 2023 10:31 pm converts to 1703392260000.
This allows you to use Bubble's Dynamic date expressions in filters without having to remember to
Extract UNIX timestamps (ms), which is the format Algolia expects.
Earlier we said the Filters input behaves like the Expression element from the Toolbox plugin. In truth, we've made a few changes behind the scenes to make writing filters as easy possible:
If the resulting
Filterstext starts with the phrase' && 'or' || ', then we remove that part before sending your filters to Typesense.To understand why, imagine a filter composed of two ternary operators:
var my_filter = ternary_filter_a + ternary_filter_bIf
ternary_filter_ais inactive due to, say, an empty Bubble dropdown, then onlyternary_filter_bcontributes tomy_filter. Butternary_filter_blikely starts with the phraseAND(orOR) which, if sent to Typesense, would cause an error. So, to maintain order in the universe, we remove those leading phrases.We interpret non-quoted appearances of the phrase
yesandnoas Javascript's booleantrueandfalse, respectively. We interpret quoted appearances of the phrase:yesand:noas the phrase:trueand:false, respectively. Together, this allows you to use Bubble's Dynamicyes/noexpressions without having toFormatted as textthe value totrueorfalse, which is what Typesense expects.We interpret non-quoted dates as UNIX timestamps (ms) as follows:
MMM D, YYYY h:mm aThe date Dec 23, 2023 10:31 pm converts to 1703392260000. This is the default date format produced by Bubble dynamic expressions that resolve a date.MMMM D, YYYY h:mm aThe date December 23, 2023 10:31 pm converts to 1703392260000.
This allows you to use Bubble's Dynamic date expressions in filters without having to remember to
Extract UNIX timestamps (ms), which is the format Typesense expects.
Want to see your Filters without having to print them to a text box? Open your browser developer tools (on Windows, press CTRL+SHFT+i, on Mac press Option + ⌘ + i) and you'll see your search filter printed to console. Filter logs are only printed to console in dev environments. If you also want them to appear in live, you can include a console.log() statement in your filter's javascript. Of course, this would double such logs in your dev environmnets.
Advanced options
- Algolia
- Typesense
This section applies to the following visual elements:
While Algolia's search defaults are great for many use cases, some applications can benefit from search result tuning. The Advanced options input is the place where we can make such adjustments. This input accepts a JSON dictionary of two kinds of parameters:
- Algolia specific parameters.
- Omnisearch specific parameters.
Algolia parameters
For the full list, check out their search parameter documentation. Of those, you can set any parameter except the following ones (which we use and cannot be overridden):
hitsPerPageattributesToRetrievefiltersrestrictSearchableAttributesattributesToHighlighthighlightPreTaghighlightPostTagpage
Omnisearch parameters
Internally, we have two unique parameters for controlling the output of search results:
clearSciousSearchCan be
trueorfalse. Default isfalse. Iftrue, thenSearch Resultsis set to an empty list regardless of any other input. This effectively "turns off" the Omnisearch visual element and it should be used instead of toggling the element's visibility.freezeSciousSearchCan be
trueorfalse. Default isfalse. Iftrue, thenSearch Resultswill hold the current state - whatever that was - regardless of any other input. This effectively "freezes" your search results.
This section applies to the following visual elements:
While Typesense's search defaults are great for many use cases, some applications can benefit from search result tuning. The Advanced options input is the place where we can make such adjustments. This input accepts a JSON dictionary of two kinds of parameters:
- Typesense specific parameters.
- Omnisearch specific parameters.
Typesense parameters
For the full list, check out their search parameter documentation. Of those, you can set any parameter except the following ones (which we use and cannot be overridden):
collectionqper_pageinclude_fieldsfilter_bysort_byquery_byhighlight_fieldshighlight_start_taghighlight_end_tagpage
Omnisearch parameters
Internally, we have two unique parameters for controlling the output of search results:
clear_scious_searchCan be
trueorfalse. Default isfalse. Iftrue, thenSearch Resultsis set to an empty list regardless of any other input. This effectively "turns off" the Omnisearch visual element and it should be used instead of toggling the element's visibility.freeze_scious_searchCan be
trueorfalse. Default isfalse. Iftrue, thenSearch Resultswill hold the current state - whatever that was - regardless of any other input. This effectively "freezes" your search results.
Typing Trigger
The Typing Trigger is used to instantly feed new values into the Omnisearch Visual Element. The reasons for building this element are threefold:
- To remove the time delay that standard Bubble Inputs have between when a user types and keystroke values become available in Bubble.
- new search request on every keystroke is running up the number of monthly search, allows you to tune the rate at which this value to reduce the number of unnecessary real time search requests initiated by queries that were typed quickly.
set the To run a new search on every input keypress, set the Typing Trigger's Typing timeout to 0 milliseconds. Alternatively, set

Inputs
Search element IDThe unique ID of the relevant Bubble input element.Typing timeoutThe milliseconds between keystrokes before fetching new search results. Set to0to run a new search on every keystroke or set this value higher to reduce the number of unnecessary real time search requests initiated by queries that were typed quickly.Character minimumThe minimum number of characters needed in a query to return search results.
Outputs
Output textThe current text value of the input with IDSearch element ID.Is typingBoolean indicator that toggles On and then Off every time a key is added to the search input referenced bySearch element ID.
Get Data Types
This visual element does not have any inputs.
Outputs
Data typesYour Bubble app's data types as a list.Data type fieldsYour Bubble app's data type's fields as a list.Browser IDA developer specific output. The current user's browser ID. Used for locking sync admin capabilities to a particular device. Will be removed in future releases.
Get Facets

Inputs
Search providerResult typeSearch result data type.Facet typeSet to the "Facet (🔍)" type.Search queryKeywords to search. Set to the Typing Trigger Value for best results.Fields to searchThe Bubble fields to search supplied as a JSON list.Fields to facetThe Bubble fields to facet supplied as a JSON list. Specifies the order of returned "Facets".FiltersThis section allows you to compose your filters using Javascript. It works exactly like the Omnisearch visual element'sFiltersinput. Details here.Max values per facetThe maximum number of facet values returned per facet.Facet queryKeywords to search inFields to facet. Set to the Typing Trigger'sOutput textfor best results.Advanced optionsAdditional options for tuning search results. It works exactly like the Omnisearch visual element'sAdvanced optionsinput. Details here.
Outputs
Returned errorA Yes/No indicating whether there was an error.Error descriptionAdditional text describing the error.FacetsThe facet items and statistics for each field specified inFields to facet.
Api calls
We have a single data API call named Facets (🔍). This API call does not return any usable data. It exists solely to set the type of data that the Get Facets visual element returns. Do not use this API call outside of the Get Facets visual element. Don't like that we did this? Neither do we. Show your support for fixing this problem by commenting on and upvoting this feature request.