Search (Elasticsearch)
The website search is powered by Elasticsearch via the elastic-search-with-i18n Strapi plugin. Content is automatically indexed when published in Strapi, and search is exposed through a custom API endpoint consumed by the frontend.
How It Works
- When content is published in Strapi, the plugin indexes the configured fields into an Elasticsearch index.
- The frontend sends the user's query to
/api/elastic/search?query=...&language=en. - The CMS controller builds an Elasticsearch query and returns the matching documents.
- The frontend groups results by content type and displays them in tabs.
Indexed Content Types
Only content types with "index": true on at least one field are active in search. The table below lists the searchable content types and their indexed fields.
| Content Type | Indexed Fields |
|---|---|
api::product.product | modelName, description, slug, product_series, featuredImage, excerpt, seo |
api::product-category.product-category | name, slug, description, excerpt, family, reasonsToBelive, seo |
api::blog-post.blog-post | title, slug, featuredImage, resourceCategories, resourceDate, resourceAuthor, content, resourcesCta, seo |
api::news-article.news-article | title, slug, featuredImage, resourceCategories, resourceDate, content, resourcesCta, seo |
api::event.event | title, slug, featuredImage, resourceCategories, eventDate, eventLocation, content, resourcesCta, seo |
api::testimonial.testimonial | title, slug, featuredImage, resourceCategories, resourceDate, resourceAuthor, content, resourcesCta, seo |
api::video.video | title, slug, description, type, videoFile, videoThumbnail, youtubeID, resourceCategories |
api::training.training | title, slug, description, type, videoFile, videoThumbnail, youtubeID, resourceCategories |
api::faq.faq | title, content, faqs_category |
api::faqs-category.faqs-category | title, slug, description, faqs |
api::content-page.content-page | title, slug, description, frontendTitle, hero, content, featuredImage, seo |
api::contacts-page.contacts-page | title, description, email, contactCards, content, seo |
Note: Fields such as
locale,localizations, and most relational/spec fields are not indexed and will never appear in search results.
Query Fields & Relevance Weights
When a search is performed, the query runs a multi_match across the following fields with these boost weights:
| Field | Boost | Notes |
|---|---|---|
seo | ×100 | SEO metadata — highest priority |
title | ×20 | Page/article/product title |
name | ×20 | Used by product categories and series |
modelName | ×20 | Used by products |
excerpt | ×5 | Short summary |
description | ×5 | Long description |
content | ×5 | Rich text / dynamic zone body content |
In addition, two prefix queries are run to support partial model/name lookups (e.g. searching hbmx will match hbmx55):
| Field | Boost | Purpose |
|---|---|---|
modelName | ×15 | Prefix match for product model numbers |
name | ×15 | Prefix match for category/series names |
Fuzzy Matching
The multi_match query uses fuzziness: "AUTO", which automatically adjusts the allowed edit distance based on term length:
| Term length | Max edits allowed |
|---|---|
| 1–2 chars | 0 (exact match only) |
| 3–5 chars | 1 |
| 6+ chars | 2 |
prefix_length: 2 means the first 2 characters of the query must always match exactly.
Language / Locale Filtering
When a language parameter is provided (e.g. language=en), results are filtered to match either:
- Documents with
localeequal to the requested language, or - Documents with no
localeset (null/missing) — this covers content types likeapi::faq.faqthat are not localised.
Result Limits
- A maximum of 50 documents are returned per query.
- The frontend paginates non-product results in pages of 5.
- Product results are shown in a carousel (all at once) or grouped by series in the Products tab.
Frontend Routing (Search Result URLs)
Each content type maps to a frontend URL:
| Content Type | URL Pattern |
|---|---|
api::product.product | /products/{categorySlug}/{seriesSlug}/{slug} |
api::product-category.product-category | /products/{slug} |
api::blog-post.blog-post | /resources/blog/{slug} |
api::news-article.news-article | /resources/news/{slug} |
api::event.event | /resources/events/{slug} |
api::testimonial.testimonial | /resources/testimonials/{slug} |
api::video.video | /resources/videos (opens inline player) |
api::training.training | /resources/trainings (opens inline player) |
api::faq.faq | /faqs/{categorySlug}?faq={documentId} — opens the FAQ accordion item directly |
api::faqs-category.faqs-category | /faqs/{slug} |
api::content-page.content-page | /{slug} |
api::contacts-page.contacts-page | /contacts |