Custom Events
Fast Simon PLP dispatching custom events for any use like analytics and more. This way you are able to targeting important events in the moment they fired.
Getting Started
PLP custom events
- Register an event listener using a script tag located in the
<head> - Each time an event is fired within the PLP, we will dispatch the custom event including all the relevant data.
Register a new custom event listener & run a callback once fired
<script>
function productAddedToCartCallback(productData) {
// ...code here
}
window.addEventListener('fs-custom-events-product-added-to-cart', (e) => {
productAddedToCartCallback(e.detail);
});
</script>
Available Events To Register
| Event Name | Description | Event Data |
|---|---|---|
| "fs-custom-events-product-added-to-cart" | Event is fired each time product added to the cart | productData: Product |
| "fs-custom-events-pagination-change" | Event is fired on each pagination change | {prevPage: number , currentPage: number} |
| "fs-custom-events-filter-clicked" | Event is fired on each filter click | {filterName: string , value: {min: number, max: number} } OR {filterName: string , value: string} |
| "fs-custom-events-product-on-hover" | Event is fired when hovering a product element | productData: Product |
| "fs-custom-events-product-swatch-on-hover" | Event is fired when hovering a swatch element | {alt: AlternativeProduct[], image: string, sku: string, redirectURL: string, title: string, swatchElement: Element, variants: Variants } |
| "fs-custom-events-product-clicked" | Event is fired on product click | {productData: Product, productClickedEvent: () => Promise\<void>} |
| "fs-custom-events-add-to-cart-response" | Event is fired when getting Shopify AddToCart response | {cart: AddToCartResponse} |
| "fs-custom-events-quick-view-btn-clicked" | Event is fired when clicking on quickview button | {productId: string, productURL: string } |
| "fs-custom-events-product-quick-add-clicked" | Event is fired when clicking on variant elemnt option | productData: Product |
| "fs-custom-events-product-swatch-on-click" | Event is fired when clicking on color swatch option button | {alt: AlternativeProduct[], image: string, sku: string, redirectURL: string, title: string} |
| "fs-custom-events-filter-search-box-changed" | Event is fired when search term in filter search box changed | {query: string} |
| "fs_wishlist_custom_add" | Event is fired when a product is added to the wishlist (when defaultStoreWishlist is enabled) | {productID: string, variantID: string, event: Event, WishlistButtonElement: Element, productURL: string} |
| "fs_wishlist_custom_remove" | Event is fired when a product is removed from the wishlist (when defaultStoreWishlist is enabled) | {productID: string, variantID: string, event: Event, WishlistButtonElement: Element, productURL: string} |
| "fs_wishlist_custom_check" | Event is fired to check if a product is in the wishlist (when defaultStoreWishlist is enabled) | {productID: string, variantID: string, callback: (result: boolean) => void} |
| "fs-custom-events-results-rendered" | Event is fired each time a new results/filters payload is published (initial load, filter, sort, pagination, search). The recommended way to react to fresh data instead of polling on an interval. version increases monotonically - compare it to detect changes cheaply without stringifying the payload. | {version: number, ...results} - the results payload; version is the stable cross-widget field. |
Fired Registered Event
<script>
window.dispatchEvent(new CustomEvent('change-number-of-products-per-row', {
detail: {
numberOfColumns: 4
}
}))
document.dispatchEvent(new CustomEvent('send-fast-simon-params', {
detail: {
narrow: {"Tag": new Set(chooseTagArray),"Price_from_to":new Set(PriceRange)}
}
}));
</script>
Wishlist Custom Events Example
When the Default Store Wishlist option is enabled in the no-code editor, the following custom events are used instead of the default wishlist operations:
<script>
// Listen for wishlist check event
window.addEventListener('fs_wishlist_custom_check', (e) => {
const { productID, variantID, callback } = e.detail;
// Check if product is in wishlist (example implementation)
const isInWishlist = checkIfProductInWishlist(productID, variantID);
// Call the callback with the result
callback(isInWishlist);
});
// Listen for wishlist add event
window.addEventListener('fs_wishlist_custom_add', (e) => {
const { productID, variantID, productURL } = e.detail;
// Add product to wishlist (example implementation)
addProductToWishlist(productID, variantID, productURL);
});
// Listen for wishlist remove event
window.addEventListener('fs_wishlist_custom_remove', (e) => {
const { productID, variantID } = e.detail;
// Remove product from wishlist (example implementation)
removeProductFromWishlist(productID, variantID);
});
// Example implementation functions (replace with your actual implementation)
function checkIfProductInWishlist(productID, variantID) {
// Your implementation to check if product is in wishlist
return false;
}
function addProductToWishlist(productID, variantID, productURL) {
// Your implementation to add product to wishlist
console.log(`Added product ${productID} to wishlist`);
}
function removeProductFromWishlist(productID, variantID) {
// Your implementation to remove product from wishlist
console.log(`Removed product ${productID} from wishlist`);
}
</script>
Results Rendered Event
Fires whenever a new results/filters payload is published (initial load, filter, sort, pagination, search) — the recommended way to react to fresh data instead of polling window.fastSimonSerpCurrentResults on an interval. The version field increases monotonically, so you can skip duplicate work by comparing a number rather than stringifying the whole results object.
<script>
let lastResultsVersion = -1;
window.addEventListener('fs-custom-events-results-rendered', (e) => {
const { version } = e.detail;
// Skip if this payload was already handled — cheap numeric compare, no stringify.
if (version === lastResultsVersion) return;
lastResultsVersion = version;
// The payload is on e.detail and also mirrored to the window results object
// (window.fastSimonSerpCurrentResults, carrying __fsResultsVersion).
// React to the fresh results/filters here — e.g. repopulate custom dropdowns.
});
</script>
Register Events On App Level
| Event Name | Description | Event Data |
|---|---|---|
| "change-number-of-products-per-row" | Event to change grid number of products per row | detail : {numberOfColumns: int} |
| "send-fast-simon-params" | Narrow Events | detail : {filterName: Set(Facets)} |
| "fs-custom-events-navigate-to-category" | Fires after a successful window.SerpOptions.navigateToCategory() call | detail : {from: string, to: string, reason?: string} |
| "fs-custom-events-navigate-to-category-skipped" | Fires when a guard rejects a navigateToCategory() call (debugging aid). The guard field tells you which guard tripped (e.g. "cooldown", "search-mode", "max-per-page"). See Logic / SerpOptions Methods for the full list. | detail : {error: string, guard: string, reason?: string} |
type references: Typescript Types