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 Provider
The search provider you've synced your data with.Result type
Search result data type.Search query
Set to the Typing TriggerOutput text
for best results. An empty search query returns all results matchingFilters
.Fields to search
The Bubble fields to search supplied as a JSON list.Filters
This section allows you to compose your filters using Javascript. For details, checkout our Filters Deep Dive section.Sort by
A dictionary of the fields to sort by specified in JSON.Results per page
Number of search results returned in each page of results.Page
The current page of search results to display starting at "1".Field to highlight
Field name to return highlights for. Must be one of the fields already listed inFields to search
.Advanced options
Additional options for tuning search results. See details in our Advanced options section
Outputs
Search Results
List of matched bubble things of the data type specified byData Type
.Results Count
Number of results.Search Time
The time it took to return a search result in milliseconds.Page Count
Number of pages of results for the current search.Returned error
A Yes/No indicating whether there was an error.Error description
Additional text describing the error.Highlights
List of matched highlight snippets.Actual page
The 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_count
is 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_count
is 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
categories
field contains all of the items fromMultidropdown Categories
, but only ifMultidropdown Categories
has 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
categories
field contains all of the items fromMultidropdown Categories
, but only ifMultidropdown Categories
has 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 Categories
filter from our last example. - A
usage_count
filter using Algolia's numeric range filter syntax. - A
published_open_source
filter using Algolia's boolean filter syntax. If the relevant checkbox is checked, then we format it's value as a text where'yes'
istrue
and'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 Categories
filter from our last example. - A
usage_count
filter using Typesense's numeric range filter syntax. - A
published_open_source
filter using Typesense's boolean filter syntax. If the relevant checkbox is checked, then we format it's value as a text where'yes'
istrue
and'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
Filters
text 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_b
If
ternary_filter_a
is inactive due to, say, an empty Bubble dropdown, then onlyternary_filter_b
contributes tomy_filter
. Butternary_filter_b
likely 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
yes
andno
as Javascript's booleantrue
andfalse
, respectively. We interpret quoted appearances of the phrase:yes
and:no
as the phrase:true
and:false
, respectively. Together, this allows you to use Bubble's Dynamicyes
/no
expressions in filters without having toFormatted as text
the value totrue
orfalse
, which is what Algolia expects.We interpret non-quoted dates as UNIX timestamps (ms) as follows:
MMM D, YYYY h:mm a
The 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 a
The 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
Filters
text 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_b
If
ternary_filter_a
is inactive due to, say, an empty Bubble dropdown, then onlyternary_filter_b
contributes tomy_filter
. Butternary_filter_b
likely 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
yes
andno
as Javascript's booleantrue
andfalse
, respectively. We interpret quoted appearances of the phrase:yes
and:no
as the phrase:true
and:false
, respectively. Together, this allows you to use Bubble's Dynamicyes
/no
expressions without having toFormatted as text
the value totrue
orfalse
, which is what Typesense expects.We interpret non-quoted dates as UNIX timestamps (ms) as follows:
MMM D, YYYY h:mm a
The 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 a
The 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):
hitsPerPage
attributesToRetrieve
filters
restrictSearchableAttributes
attributesToHighlight
highlightPreTag
highlightPostTag
page
Omnisearch parameters
Internally, we have two unique parameters for controlling the output of search results:
clearSciousSearch
Can be
true
orfalse
. Default isfalse
. Iftrue
, thenSearch Results
is 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.freezeSciousSearch
Can be
true
orfalse
. Default isfalse
. Iftrue
, thenSearch Results
will 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):
collection
q
per_page
include_fields
filter_by
sort_by
query_by
highlight_fields
highlight_start_tag
highlight_end_tag
page
Omnisearch parameters
Internally, we have two unique parameters for controlling the output of search results:
clear_scious_search
Can be
true
orfalse
. Default isfalse
. Iftrue
, thenSearch Results
is 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_search
Can be
true
orfalse
. Default isfalse
. Iftrue
, thenSearch Results
will 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 ID
The unique ID of the relevant Bubble input element.Typing timeout
The milliseconds between keystrokes before fetching new search results. Set to0
to 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 minimum
The minimum number of characters needed in a query to return search results.
Outputs
Output text
The current text value of the input with IDSearch element ID
.Is typing
Boolean 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 types
Your Bubble app's data types as a list.Data type fields
Your Bubble app's data type's fields as a list.Browser ID
A 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 provider
Result type
Search result data type.Facet type
Set to the "Facet (🔍)" type.Search query
Keywords to search. Set to the Typing Trigger Value for best results.Fields to search
The Bubble fields to search supplied as a JSON list.Fields to facet
The Bubble fields to facet supplied as a JSON list. Specifies the order of returned "Facets".Filters
This section allows you to compose your filters using Javascript. It works exactly like the Omnisearch visual element'sFilters
input. Details here.Max values per facet
The maximum number of facet values returned per facet.Facet query
Keywords to search inFields to facet
. Set to the Typing Trigger'sOutput text
for best results.Advanced options
Additional options for tuning search results. It works exactly like the Omnisearch visual element'sAdvanced options
input. Details here.
Outputs
Returned error
A Yes/No indicating whether there was an error.Error description
Additional text describing the error.Facets
The 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.