Skip to main content

Implementing an eCommerce Collection Products Page

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

Using the Fast Simon JavaScript SDK, you can easily implement the following collection products page capabilities:

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

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

  • Navigating through collection results: Support collection results 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 collection results relevancy.

Getting Collection Results

The smartCollections method allows you to get the collection results for a given collection.

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

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

window.FastSimonSDK.smartCollections({
categoryID: category_id,
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)
}
});
},
inventoryCallback: (response) => {
if (response.payload.productsInventory.length > 0) {
this.renderInventorySection(response.payload.productsInventory);
}
}
});

The smartCollections method options:

OptionTypeDescription
categoryIDstring (required)collection ID.
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. example of Sorting Results
narrowBynarrowBy Default: []Determines what filters are used to narrow the results. example of narrowBy
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.
inventoryCallbackresponse voidCallback to handler the inventory results.
withProductTypesboolean Default: falseDetermines whether to include Product Types in the response.
searchWithinSearchstring (required)Search bar within the filters menu to refine results.

Getting Collection Results and Reporting Shopper Activity

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

window.FastSimonSDK.smartCollections({
categoryID: category_id,
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.bannerHTML) {
this.renderBanner(response.payload.bannerHTML)
}
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 collection results products in a grid.
“facet and products”Rending pages facets (filters).

Getting Collection Results with searchWithinSearch and Reporting Shopper Activity

Rendering fast collection results is key to enhancing user experience and driving conversions. The searchWithinSearch feature allows users to refine their results further by entering a query in a search bar available within the collection page.

Expected UI Flow:

  1. Initial Load: The collection page is rendered with the full set of products based on the initial parameters.
  2. Search Bar Within Collection: A search bar appears on the collection page, allowing users to perform a secondary search to filter the displayed results further.

Code Example:

// Function to handle collection requests and render results
function loadCollection({ searchWithinSearch = "" } = {}) {
window.FastSimonSDK.smartCollections({
categoryID: category_id,
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);
if (response.payload.bannerHTML) {
this.renderBanner(response.payload.bannerHTML);
}
window.FastSimonSDK.event({
eventName: searchWithinSearch
? window.FastSimonEventName.SearchWithinPerformed
: window.FastSimonEventName.SmartCollectionPreformed,
data: {
categoryID: category_id,
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 collection load
loadCollection();

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


# Rendering collection 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 shoppers with the 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:

```javascript
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 shoppers 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 shoppers to conveniently revisit previous collection 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.

What data you get in inventory callback response

With Fast Simon SDK you can create a product grid that displays the inventory details:

    interface InventoryResponse {
action: "products inventory"
payload: {
productsInventory: {
id: string;
totalInventory: number;
}[];
}
}

Rendering Collection Results Filters

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

Facets are typically displayed as a set of options that shoppers can interact with to narrow down their collection 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

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 collection request with the narrowBy: parameter.

Implementation examples

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

The following are simple implementation examples.

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
// Create checkboxes for each filter option
for (let j = 0; j < facet[1].length; j++) {
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 collection 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.smartCollections({
categoryID: category_id,
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)
}
});
},
inventoryCallback: (response) => {
if (response.payload.productsInventory.length > 0) {
this.renderInventorySection(response.payload.productsInventory);
}
}
});

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 collection results into pages, which can then be navigated using controls usually found at the bottom of the page.

  • Using an infinite scroll, where collection 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 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 a shopper visits a collection page, and the smartCollections method was called an event type smartCollectionPerformed should be fired to make sure Fast Simon dashboard statistics and relevancy keeps being up to date.

window.FastSimonSDK.event({
eventName: window.FastSimonEventName.SmartCollectionPreformed,
data: {
categoryID: this.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)
}
)};

Event type smartCollectionPerformed mandatory options:

OptionValueDescription
categoryIDstring(Required) The viewed category ID
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 collection products page, an event type CollectionProductClicked created send update statistics to the admin dashboard.

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

CollectionProductClicked options:

OptionValueDescription
collectionIDstringQuery string used
productIDnumberProduct identification ID
positionnumberPosition of the product from the beginning of the presented products from the collection results
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 collection results