Skip to main content

Implementing an eCommerce Search Results Page (SERP)

Fast Simon JavaScript SDK allows developers to create a modern ecommerce search results page that includes Fast Simon advanced BigData AI, Merchandising, Personalization and more.

Using the Fast Simon JavaScript SDK, you can easily implement the following Search Results Page capabilities:

  • Displaying search results: Retrieves search results rendered in a product grid.

  • Filtering search results: Allows applying filters to refine the search results.

  • Navigating through search results: Support search result pages either in an infinite single scroll down page manner or as separate pages.

  • Reporting Shopper Activity: Records activities to enable Fast Simon analytics and improve search results relevancy.

Getting Search Results

The fullTextSearch method allows you to get the search results for a given shopper query.

The search method utilizes the Fast Simon search functionality to execute the search operation based on the shopper's input. It communicates with the Fast Simon SDK to retrieve the corresponding search results, filter data, and pagination details.

In the search query the shopper defines what they are looking for, which is implemented using the term parameter. The callback function contains the relevant products and filters matching the shopper term.

window.FastSimonSDK.fullTextSearch({
term: term,
page: this.page,
productsPerPage: 48,
narrowBy: this.narrowBy,
sortBy: this.sortBy,
onFacetsLoaded: (response) => {
this.renderFacets(response.payload.facets);
},
onProductsLoaded: (response) => {
this.renderProducts(response.payload.products);
windows.FastSimonSDK.event({
eventName: windows.FastSimonEventName.SmartCollectionPreformed,
data: {
categoryID: category_id,
narrowBy: this.narrowBy,
sortBy: this.sortBy,
products: response.payload.products.map(({id}) => id).toString(),
rescount: response.payload.totalResults,
pagenum: Math.ceil(response.payload.totalResults / 48)
}
});
}
});

The fullTextSearch method options:

OptionTypeDescription
termstring (required)Search query.
onProductsLoadedresponse void (required)Callback to handler the collection products results.
onFacetsLoadedresponse void (required)Callback to handler the collection facets results.
pagenumber Default: 1Page number to retrieve.
productsPerPageNumber Default: 40Determines how many products are displayed on each page. Note: Make sure that the productsPerPage is the same on all pages.
sortBysortBy Default: relevencyDetermines the sort order by which the shopper sorts the list of products. (add link to the relevant place in the docs, Extra)
narrowBynarrowBy Default: []Determines what filters are used to narrow the results. (add link to the relevant place in the docs, Extra)
facetsboolean Default: trueDetermines whether to fetch filters (to allow shoppers to narrowBy parameter).
withAttributesboolean Default: falseDetermines whether to include attributes in the product response. Note: might increase latency, so use only if you need product tags or attributes.
withProductTypesboolean Default: falseDetermines whether to include Product Types in the response.
searchWithinSearchstring (required)Search bar within the filters menu to refine results.

Getting Search Results and Reporting Shopper Activity

Having a fast rendered search results is key to optimizing user experience and conversion optimization. Below is a short code snippet illustrating getting search results, rendering products and filters and reporting on shopper activity.

window.FastSimonSDK.fullTextSearch({
term: term,
page: this.page,
productsPerPage: 48,
narrowBy: this.narrowBy,
sortBy: this.sortBy,
onFacetsLoaded: (response) => {
this.renderFacets(response.payload.facets);
},
onProductsLoaded: (response) => {
this.renderProducts(response.payload.products);
windows.FastSimonSDK.event({
eventName: windows.FastSimonEventName.SmartCollectionPreformed,
data: {
categoryID: category_id,
narrowBy: this.narrowBy,
sortBy: this.sortBy,
products: response.payload.products.map(({id}) => id).toString(),
rescount: response.payload.totalResults,
pagenum: Math.ceil(response.payload.totalResults / 48)
}
});
}
});

Notice that the callback function can be fired once or twice depending whether the server completed the facets results. Here are the possible situations for you to prepare to;

response.action ValueDescription
“products”Render search results products in a grid.
“facet and products”Rending pages facets (filters).

Adding searchWithinSearch to the Search Page

Enhance your search page with the searchWithinSearch feature, allowing users to refine results directly on the search results page.

Expected UI Flow

  1. Initial Search: Users perform a full-text search, and results are displayed with relevant facets and products.
  2. Search Bar Within Results: A search bar is added to the page for refining results using the searchWithinSearch parameter.

Code Example

// Function to handle search requests and render results
function loadSearchResults({ searchWithinSearch = "" } = {}) {
window.FastSimonSDK.fullTextSearch({
term: term,
page: this.page,
productsPerPage: 48,
narrowBy: this.narrowBy,
sortBy: this.sortBy,
searchWithinSearch, // Pass the search query if available
onFacetsLoaded: (response) => {
this.renderFacets(response.payload.facets);
},
onProductsLoaded: (response) => {
this.renderProducts(response.payload.products);
window.FastSimonSDK.event({
eventName: searchWithinSearch
? window.FastSimonEventName.SearchWithinPerformed
: window.FastSimonEventName.FullTextSearchPerformed,
data: {
term: term,
narrowBy: this.narrowBy,
sortBy: this.sortBy,
searchWithinSearch,
products: response.payload.products.map(({ id }) => id).toString(),
rescount: response.payload.totalResults,
pagenum: Math.ceil(response.payload.totalResults / 48),
},
});
},
});
}

// Initial search load
loadSearchResults();

// Search Within Results
const searchBar = document.getElementById("search-within-results-bar");
searchBar.addEventListener("input", (event) => {
const searchQuery = event.target.value;
loadSearchResults({ searchWithinSearch: searchQuery });
});

Rendering Search Results in a Product Grid

A product grid is a layout or display format used to present products. It is a structured arrangement of product thumbnails or tiles, organized in a grid-like pattern.

The product grid is designed to provide users with an overview of available products and data allowing them to browse and compare items quickly.

What data to include in the product grid

With Fast Simon SDK you can create a product grid that displays the following product properties:

 interface Product {
c: string // currency
d: string // description
f: number // product merch stuff
id: string // product id
iso: boolean // is sold out
l: string // product title
p: string // price
p_c: string // comapre price
p_max: string
p_max_c: string
p_min: string
p_min_c: string
p_spl: number
review: number // review score
reviews_count: number // review count
s: string // sku (shopify foramt)
sku: string // sku
skus: string[] // skus
t: string // main image
t2: string // fallback image
u: string // url
v_c: number // varaint count
vra: Variant[] //product variants
vrc: object
att?: Attribute[] // product attribiutes
alt?: AlternativeProduct[] // alternative (sibiling) products
}

type Variant = [string, VariantData[]]
type VariantData = [string, string[]]

type Attribute = [string, AttributeData[]]
type AttributeData = [string, string[]]

export type AlternativeProduct = [AlternativeProductName, AlternativeProductURL, productID?]
type AlternativeProductName = string
type AlternativeProductURL = string
type productID = number

The product grid options:

OptionTypeDescription
cstringProduct currency
dstringProduct description
fnumberProduct merch stuff
idstringProduct ID
isobooleanProduct is sold out or not
lstringProduct main title
pstringProduct price
p_cstringProduct compare price in case of sale
p_maxstringVariant max price range
p_max_cstringCompare variant max price range
p_minstringVariant min price range
p_min_cstringCompare variant min price range
p_splnumber· 1 if the product has variants · 0 in case of no variants
p_spl_idstringThe ID of the product with variants
reviewnumberReview number out of score rate between 0 – 100
review_countnumberThe number of people reviewed the product
sstringSKU Shopify format codes that you can use internally to track your inventory and report on your sales.
skustringSKU regular format
skusstringList of variant skus related to product.
tstringURL product main image
t2stringURL fall back generic image presented only when the main URL is not accessible.
ustringProduct location URL
v_cnumberVariants count number
vraVariant[]Product variants list
vrcobjectDefined attributes for variant list.
att?Attribute[]Product attributes such as tags custom defined per customer.
alt?AlternativeProduct[]Alternative (sibling) products linked to the main product as viewed alternative selections.

In addition, you can incorporate various features and interactions within the product grid, such as sorting options, filtering capabilities, and pagination, to enhance the browsing experience and help users find desired products efficiently. To implement product grid characteristics Use the data in response.payload.products.product.vra The 'vra' property comprises a list of product variants, with each variant containing information about its specific options (e.g., Size and Color).

For example:

{
"vra": [
[39746014183484, [["Barcode", ["WFTOP391-1-XS"]], ["Price", ["USD:44.99"]], ["Product-sku", ["WFTOP391-1-XS"]], ["Sellable", [true]], ["Size", ["XS"]], ["Weight", ["130"]]]],
[39746014216252, [["Barcode", ["WFTOP391-1-S"]], ["Price", ["USD:44.99"]], ["Product-sku", ["WFTOP391-1-S"]], ["Sellable", [true]], ["Size", ["S"]], ["Weight", ["130"]]]],
[39746014249020, [["Barcode", ["WFTOP391-1-M"]], ["Price", ["USD:44.99"]], ["Product-sku", ["WFTOP391-1-M"]], ["Sellable", [true]], ["Size", ["M"]], ["Weight", ["130"]]]],
[39746014281788, [["Barcode", ["WFTOP391-1-L"]], ["Price", ["USD:44.99"]], ["Product-sku", ["WFTOP391-1-L"]], ["Sellable", [true]], ["Size", ["L"]], ["Weight", ["130"]]]],
[39746014314556, [["Barcode", ["WFTOP391-1-XL"]], ["Price", ["USD:44.99"]], ["Product-sku", ["WFTOP391-1-XL"]], ["Sellable", [false]], ["Size", ["XL"]], ["Weight", ["130"]]]]]
}

Implementation Examples

The full example of implementation you can find in the Fast Simon GitHub: Fast-Simon-Sample-JavaScript-SDK

HTML:

<div id="productGrid"></div>

JavaScript:

// Render product grid
renderProductGrid(response.payload.products);

function renderProductGrid(products) {
productGrid.innerHTML = ''; //remove previous results
products.forEach((product) => {
// Render product card
const productCard= document.createElement('div');
productCard.setAttribute('id', product.id);*// product id*
const title = document.createElement('div');
title.innerText = product.l; *// product title*
const image= document.createElement('img');
image.src = product.l; *// main image*
const price = document.createElement('span');
title.innerText = product.p; *// price*
productCard.appendChild(image);
productCard.appendChild(title);
productCard.appendChild(price);
productGrid.appendChild(productCard);
});
}

Implementing a Routing Manager

A routing manager handles navigation and routing within an ecommerce website. It plays an important role in processing incoming requests and user interactions, ensuring they are directed to the appropriate URL destinations.

A routing manager is used to manage the navigation between different pages or views. It updates the URLs when filters or pagination options are selected. This results in URLs that contain the necessary data to easily select the desired page and apply specific filters whenever needed.

By implementing routing manager, the website's URLs become consistent for given queries and filters. This allows users to conveniently revisit previous search results or specific filtered views by simply accessing the saved URL (or shared by shoppers for other people).

Suggested structure:

  • Listener to the URL changes.
  • URL Parser that can get the URL and build the query, filters, pagination, sortBy values.
  • URL Generator which should build the URL every time a user uses a query, filters, pagination, or sortBy.

Rendering Search Results Filters

Fast Simon SDK provides the ability to present filters for shoppers per a given query. Facets are versatile filtering options that allow them to refine their search results based on specific attributes of the search results.

Facets are typically displayed as a set of options that shoppers can interact with to narrow down their search results and find the most relevant information or products.

With Fast Simon SDK you can retrieve the data to implement the following facet types:

Facet TypeIllusration
Checkbox
Price slider
Color swatches
Customers Rating
Note: The Product Reviews filter is unique.
Like on any major ecommerce site, it includes results
with the selected review score and higher.
For example, selecting products with a 4-star review
will also display products with a 5-star review score.

Working with Facets

Render filters: You can render the search term facets found in the response.payload.facets.

Narrow results: Perform a search after the shopper selects a facet option and performs a Full Text Search method with the narrowBy: parameter.

Implementation Examples

The full example of implementation you can find in the Fast Simon GitHub: Fast-Simon-Sample-JavaScript-SDK

HTML:

<div id="filters"></div>

JavaScript:

renderFilters(response.payload.facets);
function renderFilters(facets) {
const filtersContainer = document.getElementById("filters");
filtersContainer.innerHTML = ''; // Clear previous filters
const filterContainer = document.createElement("div"); // Create a container div for the filter
filterContainer.classList.add('fs_filter_container');

const labelElement = document.createElement("label"); // Create a label element for the filter
labelElement.classList.add('fs_label_element');
labelElement.setAttribute("name", `${facet[0]}`);
labelElement.textContent = facet[2]; //you can change this name in the dashboard

for (let j = 0; j < facet[1].length; j++) { // Create checkboxes for each filter option
const option = facet[1][j][0]; // value of the checkbox
const count = facet[1][j][1]; //number of products matching this filter
const checkboxWrap = document.createElement("div");
const checkboxCount = document.createElement("span");
checkboxCount.innerText = `(${count})`;
const checkboxElement = document.createElement("input");
checkboxElement.type = "checkbox";
checkboxElement.value = option;
checkboxElement.setAttribute("key", `${facet[0]}`);
checkboxElement.setAttribute("name", `${facet[2]}`);
// Add event listener to handle checkbox selection
checkboxElement.addEventListener("change", () => handleCheckboxSelection(checkboxElement));

const optionLabel = document.createElement("label");
optionLabel.textContent = option;
optionLabel.textContent = option; //for categories use:facet[1][j] [2];

checkboxWrap.appendChild(checkboxElement);
checkboxWrap.appendChild(optionLabel);
checkboxWrap.appendChild(checkboxCount);
filterContainer.appendChild(checkboxWrap);
}
}

Sorting Results

A sortBy function allows to organize the products on a page according to different parameters, which enables finding what the shoppers are looking for faster and easier.

By providing a simple and easy-to-use sorting capability, businesses can enhance user experience and potentially increase sales.

Here are the possible sorting options (notice they first need to be turned on in the Fast Simon Dashboard in the Search Results Configuration)

const FastSimonSortBy = {
PriceHighToLow: "price_max_to_min",
PriceLowToHigh: "price_min_to_max",
NewFirst: "creation_date",
OldFirst: "creation_date_oldest",
Popularity: "popularity",
Reviews: "reviews",
AtoZ: "a_to_z",
ZtoA: "z_to_a",
relevancy: "relevency"
};

Fast Simon provides the following sorting options:

OptionValueDescription
PriceHighToLow"price_max_to_min"Sorts results by product price from high to low.
PriceLowToHigh"price_min_to_max"Sorts results by product price from low to high.
NewFirst"creation_date"Sorts results by latest product insertion by date.
OldFirst"creation_date_oldest"Sorts results by oldest product insertion by date.
Popularity"popularity"Sorts results by product popularity calculated by number of clicks, visits, and sells.
Reviews"reviews"Reviews number out of score rate between 0 – 100.
AtoZ"a_to_z"Sorts results by product name in an ascending order.
ZtoA"z_to_a"Sorts results by product name in a descending order.
relevancy"relevency"When the URL returns without the sortBy value, the default result page is displayed. Note: The word relevency in the code appears with a typo.

Related Categories

An array of related categories that can be used to show a top wheel of related collections.

Implementation examples

HTML:

    <div class="related-categories">
<div class="related-categories-container" id="relatedCategoriesContainer"></div>
</div>

JavaScript:

window.FastSimonSDK.fullTextSearch({
term: term,
page: this.page,
productsPerPage: 48,
narrowBy: this.narrowBy,
sortBy: this.sortBy,
onFacetsLoaded: (response) => {
this.renderFacets(response.payload.facets);
},
onProductsLoaded: (response) => {
this.renderProducts(response.payload.products);
if(response.payload.relatedCategories?.length) {
// Render product grid
const container = document.getElementById("relatedCategoriesContainer");

relatedCategories.forEach(category => {
const categoryItem = document.createElement("div");
categoryItem.className = "category-item";
categoryItem.innerHTML = `
<a href="${category.url}">
<img src="${category.image}" alt="${category.title}">
<div class="category-item-title">${category.title}</div>
</a>
`;
container.appendChild(categoryItem);
});
}
windows.FastSimonSDK.event({
eventName: windows.FastSimonEventName.SmartCollectionPreformed,
data: {
categoryID: category_id,
narrowBy: this.narrowBy,
sortBy: this.sortBy,
products: response.payload.products.map(({id}) => id).toString(),
rescount: response.payload.totalResults,
pagenum: Math.ceil(response.payload.totalResults / 48)
}
});
}
});


export interface RelatedCategory {
id: string
title: string
image: string
url: string
}

const relatedCategories: RelatedCategory[] = [
{
id: "1",
title: "Dresses",
image: "https://example.com/image1.jpg",
url: "https://example.com/category1"
},
{
id: "2",
title: "Top Shirt",
image: "https://example.com/image2.jpg",
url: "https://example.com/category2"
}
];

Pagination

Pagination helps improve user experience by making large amounts of data more manageable and navigable. The following pagination options are available:

  • Dividing search results into pages, which can then be navigated using controls usually found at the bottom of the page.

  • Using an infinite scroll, where search results are automatically loaded and added to the bottom of the page when the user reaches the end.

Fast Simon SDK automatically identifies the browser behavior for displaying search products either through separate pages with their related URLs or through an infinite scroll on a single page. In the case of infinite scroll, the URL is updated every time a page of products is loaded.

Reporting Shopper Activity

Every time performed a search query, and the fullTextSearch is called rendering and products an event type searchPerformed is sent to keep Fast Simon dashboard statistics and relevancy up to date.

window.FastSimonSDK.event({
eventName: window.FastSimonEventName.SearchPerformed,
data: {
kl_id: this.klaviyoID,
query: term,
narrowBy: this.narrowBy,
sortBy: this.sortBy,
products: response.payload.products.map(({id}) => id).toString(),
rescount: response.payload.totalResults,
pagenum: Math.ceil(response.payload.totalResults / 48)
}
)};

Event type searchPerformed mandatory options:

OptionValueDescription
kl_idstring(Optional) application output ID number i.e.: klaviyoID
querytermDetermines the desired search results
narrowBynarrowBySet of filters sent
sortBysortBySort method selected
productsstringList of product IDs
rescountstringNumber of total results matches in the current event search
pagenumnumber Default: 1The current page number

Product Click Event

Every click on a product in the search results page, an event type SerpProductClicked created send update statistics to the admin dashboard.

window.FastSimonSDK.event({
eventName: window.FastSimonEventName.SerpProductClicked,
data: {
query: "dog", // (Required)
productID: "11223344", // (Required)
position: 5, // counting starting at 1
imageID: "asdfsdfsf" // If Image Optimization is used
}
)};

SerpProductClicked options:

OptionValueDescription
querystringQuery string used
productIDnumberProduct identification ID
positionnumberPosition of the product from the beginning of the presented products from the search result
imageIDnumberOptimizations usage send ID in the response back

Quick View Event

Shopper clicked on product in quick view link and redirected to product page, this creates event type QuickViewProductClicked.

window.FastSimonSDK.event({
eventName: window.FastSimonEventName.QuickViewProductClicked,
data: {
productID: "11223344", // (Required)
originalProduct: "2342432" , // Required)
position: 7 // counting starting at 1
}
)};

QuickViewProductClicked options:

OptionValueDescription
productIDnumberProduct identification ID
originalProductnumberInternal ID
positionnumberPosition of the product from the beginning of the presented products from the search result