Skip to main content

Store OS Bindings

The Store OS Bindings feature allows developers to integrate their extension functions directly into Store OS through an embedded web view. With these customizations, merchants can tailor the UI to meet their specific needs for functions beyond the core capabilities of the Store OS application. Bindings are essential for making extensions accessible within the Store OS UI. It configures how and where an extension will appear.

This guide gives step-by-step instructions for creating bindings and testing your extension in the Store OS app. It helps you set up, customize, handle events, test, and ensure a smooth integration with the Store OS ecosystem.

Prerequisites

  • Make sure you have created an extension before you start Store OS binding. Refer to Get Started for a step-by-step guide.

Types of Bindings

  1. Connected App
  2. Page Specific

1. Connected App Bindings

Accessed via a dedicated navigation tab and occupies the entire screen.

Steps

Do the following steps to create a Connected App Bindings

  1. Go to the Fynd Partner panel.
  2. In the left pane, click Extensions and open the extension.
  3. Go to Extension Setup and ensure the extension URL and permissions are correct.
  4. In the Bindings section, click Manage.
  5. In the upper-right of the window, click Add to create a new binding.
  6. Select Store OS in the Interface Area dropdown.
  7. Select Connected App from the Binding Type dropdown.
  8. Enter a name for the binding and specify the target URL where it is hosted.
  9. Click Add.

The binding will appear in the Extension tab as shown in the image below:

Connected APP Bindings

2. Page Specific Bindings

Page Specific Bindings can be accessed from contextual menus, such as "More Actions" or dropdowns in Store OS.

Steps

Do the following steps to create Page Specific Bindings

  1. Go to the Fynd Partner panel.
  2. In the left pane, click Extensions and open the extension.
  3. Go to Extension Setup and ensure the extension URL and permissions are correct.
  4. In the Bindings section, click Manage.
  5. In the upper-right of the window, click Add to create a new binding.
  6. Select Store OS in the Interface Area dropdown.
  7. Select Page Specific from the Binding Type dropdown.
  8. Enter a name for the binding.
  9. Specify the target URL where the binding is hosted.
  10. In the Allowed Pages dropdown, select pages where the extension will be available as an entry point.
  11. In the User Interaction dropdown, specify how the user will interact with the screen.
    The user can interact in two formats:
    • Modal: Opens as a side drawer on tablets or as a bottom sheet on mobile.
    • Full page: Opens as a dedicated full-screen page on both tablets and mobile.
  12. Click Add.

Fynd Store OS Interface (FSI)

FSI is a communication and state‑management layer between a host application (Store OS) and an embedded extension (rendered in an iframe/webview). It enables both sides to:

  • Emit and listen to events
  • Share and react to state changes

FSI standardizes how extensions communicate with Store OS. Both the host and the extension load the FSI script. The extension must initialize in extension mode, after which it can start sending and receiving events and state updates.

FSI uses postMessage under the hood for cross‑context messaging. When loaded, it is attached to the global object and is available as window.FSI.

Steps to Initialize FSI

Load the FSI script in your extension and then initialize the extension (run inside an async context):

const loadScript = (src) => {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = src;
script.async = true;
script.onload = () => resolve();
script.onerror = () => reject(new Error(`Failed to load script: ${src}`));
document.body.appendChild(script);
});
};

// Use the environment-appropriate URL for the FSI library
const fsiLibraryPath =
"https://storeos.fynd.com/fynd-store-os-extensions/v3/fsi.js";
await loadScript(fsiLibraryPath);

window.FSI.initExtensionApplication();

// Announce readiness so the host can begin sending state/events
window.FSI.event.emit("ext.ready", { isReady: true });

As soon as your extension loads, it should emit ext.ready.

note

Any state or event transfer is available only after the extension emits ext.ready.
The initExtensionApplication call is mandatory to ensure FSI runs in extension mode.

States

A state refers to shared data objects that can change over time and need to be synchronized between Store OS and the extension. This includes dynamic information, such as cart contents, product details, and user selections. When you subscribe to a state, your extension receives updates when new state data is published.

Default URL Parameters

When an extension is launched within Store OS, the platform automatically adds authentication tokens and context parameters to the extension URL. This allows the extension to securely access relevant data and user context without requiring a separate login. These parameters are appended as query strings and are available inside the extension.

Below are the default parameters provided to every extension:

Query ParameterDescription
company_idUnique identifier for the selected company.
application_idUnique identifier for the selected sales channel (application) within the company.
store_idUnique identifier for the selected store.
platform_user_idUnique identifier of the currently logged-in user on the platform.

State Structure Reference

The following table outlines the structure of each state object you can subscribe to.
For instance, when you subscribe to the product state, you will receive an object containing the keys listed below.
Refer to the table below to understand the data available for each state and how to access it in your extension:

  1. Order/Shipment Detail State
  2. Cart State
  3. Product State

1. Order/Shipment Detail State

State: orderDetail

KeyTypeDescription
order_idstringOrder ID for the selected order
shipment_idstringShipment ID for the selected shipment

Usage Example

window.FSI.state.orderDetail.subscribe(function(data){
console.log("FSI.state.orderDetail.subscribe:", JSON.stringify(data));
})

JSON Schema

{
"$schema":"https://json-schema.org/draft/2020-12/schema",
"type":"object",
"properties":{
"order_id":{"type":"string"},
"shipment_id":{
"type":"string",
"description":"shipemnt id only available for shipment level bindings"
}
},
}

Example for Order Detail

{ 
"order_id": "order-123",
"shipment_id": "null",
}
note

Shipment ID will be null in case of order detail.

Example for Shipment Detail

{ 
"order_id": "order-123",
"shipment_id": "shipment-123",
}

2. Cart State

State: cart

KeyTypeDescription
cart_idstringCurrent active cart ID
user_idstringUser ID associated with the cart
address_idstringAddress ID linked to the cart
order_typestringType of order ("HomeDelivery", "PickAtStore")

Usage Example

window.FSI.state.cart.subscribe(function(data){
console.log("FSI.state.cart.subscribe:", JSON.stringify(data));
})

JSON Schema

{
"$schema":"https://json-schema.org/draft/2020-12/schema",
"type":"object",
"properties":{
"cart_id":{"type":"string"},
"user_id":{"type":"string"},
"address_id":{"type":"string"},
"order_type":{"type":"string","enum":["HomeDelivery","PickAtStore"]}
},
}

Example

{ "cart_id": "123456789",
"user_id": "user_abc123",
"address_id": "addr_123",
"order_type": "HomeDelivery"
}

3. Product State

State: product

KeyTypeDescription
product_slugstringUnique slug identifier for the product
product_uidstringUnique product UID
seller_identifierstringSeller UID
store_idstringStore UID
product_sizestringCurrently selected size of the product
quantitynumberSelected quantity
cart_idstringAssociated cart ID
locationobjectLocation details (varies by country; e.g., India includes state and pincode, UAE includes area)

Usage Example

window.FSI.state.product.subscribe(function(data){
console.log("FSI.state.product.subscribe:", JSON.stringify(data));
})

JSON Schema

{  "$schema":"https://json-schema.org/draft/2020-12/schema",
"type":"object",
"properties":{
"product_slug":{"type":"string"},
"product_uid":{"type":"integer"},
"seller_identifier":{"type":"string"},
"product_size":{"type":"string"},
"store_id":{"type":"integer"},
"quantity":{"type":"integer","minimum":1},
"cart_id":{"type":"string"},
"fulfilment_slug":{"type":"string"},
"location":{"type":"object", // This is India location
"properties":{
"country_iso_code":{"type":"string"},
"pincode":{"type":"string"}
},
}
},
}

Example

{ 
"product_slug": "product-123",
"product_uid": 12345,
"seller_identifier": "seller_xyz",
"produt_size": "size_xyz",
"store_id": 1234,
"quantity": 2,
"cart_id": "123456789",
"fulfilment_slug":"standard-delivery",
"location": {
"country_iso_code":"IN",
"pincode":"400067"
}
}

Syncing State Data

1. Subscribe

To receive updates when cart data changes (such as when items are added or removed), subscribe to the cart state. For example, if the extension is open and a user adds an item to the cart, your extension will automatically receive the updated cart information. This allows your extension to always reflect the latest cart contents by listening for changes to the cart's ID or other properties.

note

Always use a named function (not an anonymous function) for subscribing to a state because the unsubscribe method requires the same function reference that was used during subscription. Always store and use the named function reference for both subscribing.

Example

function onCartChange(data) {
const cartId = data?.cart_id;
}
window.FSI.state.cart.subscribe(onCartChange);

2. Unsubscribe

To unsubscribe from updates when you no longer need notifications, call the unsubscribe method with the same function reference you used to subscribe.

note

Always use a named function (not an anonymous function) for unsubscribing to a state because the unsubscribe method requires the same function reference that was used during subscription. Using anonymous functions will not work for unsubscription, as there is no way to reference the original function.

Example

Suppose you previously subscribed to cart updates and now want to stop receiving notifications (for example, when your extension is being closed or the cart is no longer relevant). To do this, simply call unsubscribe with the same named function reference you used for subscribing:

window.FSI.state.cart.unsubscribe(onCartChange);

Entry Points

Store OS provides several entry points where your extension can appear. Each entry point determines where and how your extension is accessible within the Store OS UI. Below, you'll find a developer-friendly summary of each entry point, including where it appears, display name in the bindings UI, typical use cases, and supported UI formats.

  1. Cart → More Cart Actions
    • Binding Name: "Cart - More Actions"
    • Use case: Apply coupons
    • User Interaction: FullPage, Modal
Cart Action
  1. Cart → Cart Action Card
    • Binding Name: "Cart - Primary Action Card"
    • Use case: Add custom attributes to customers or to cart/item-level metadata
    • User Interaction: FullPage, Modal
Cart Action Card
  1. Product Details Page (PDP) → More Actions
    • Binding Name: "Product Details"
    • Use case: Show similar products
    • User Interaction: Modal
PDP
  1. Orders → Order Details
    • Binding Name: "Order Details"
    • Use case: Add metadata at the order level
    • User Interaction: Modal
Order Details
  1. Orders → Shipment Details
    • Binding Name: "Shipment Details"
    • Use case: Unlock a shipment extension in Swadesh
    • User Interaction: Modal
Shipment Details
Cart Action
  1. Analytics
    • Binding Name: "Analytics"
    • Use case: Show additional reports
    • User Interaction: FullPage (In-Built)
Cart Action
  1. Support → More Actions
    • Binding Name: "User Support"
    • Use case: Raise support tickets for non-software issues (sent to the brand's support module)
    • User Interaction: FullPage, Modal
Cart Action
  1. Account → Action List
    • Binding Name: "User Account"
    • Use case: Incentives
    • User Interaction: FullPage, Modal
Cart Action

Events

Used for emitting and listening to events between the host and the extension. Events are ideal for triggering actions (e.g., refresh, open a page, show a toast) and complement state updates, which are for shared data.

1. Subscribe Event

Events allow your extension to respond to user actions or system triggers in real time.

The event.on(eventName, handler) method allows your extension to listen for specific events and react in real time. When you subscribe to an event, the method returns an eventId that you should store if you plan to unsubscribe later.

Subscribing to events enables your extension to respond dynamically to user actions or system changes. Common use cases include:

  • Extension Close Event: Perform cleanup tasks or prompt the user to save changes before the extension closes by subscribing to the "close" event.
  • Cart Refresh Event: Automatically update your UI when the cart is refreshed by listening to the "cart.refresh" event.
  • Toast Error Event: Display error notifications to users by handling the "toast.error" event.
note

If you subscribe multiple times to the same event, each subscription gets a unique event ID.

Example

Subscribe to the "close" event to perform cleanup when the extension is closed. Suppose you want to save user data or show a confirmation dialog before the extension closes.

function onCloseExtension() {
// Perform cleanup actions here, such as saving data or showing a message
console.log("Extension is closing. Cleaning up resources...");
}
// Subscribe to the "close" event and store the eventId for later unsubscription if needed
const closeEventId = window.FSI.event.on("close", onCloseExtension);
note

Passing an anonymous function to on will prevent proper removal using off. Always use named functions for event handlers if you plan to unsubscribe them later.

2. Emit Event

Emitting an event is how your extension or the host notifies other parts of the system that something important has occurred. Any listeners (in the host or other extensions) that have subscribed to this event will react accordingly.
event.emit(eventName, data) automatically propagates across the extension/host boundary if needed.

When you emit an event, you're essentially saying: this thing just happened – anyone listening should respond.

Example 1

Suppose you want to refresh the cart when a user clicks a "Refresh Cart" button in your extension. Real-World Flow:

  1. User Action: User clicks the "refresh cart" button in the extension.
  2. Extension Emits: The extension calls emit("cart.refresh").
  3. Host Receives: The host application is subscribed to "cart.refresh" events.
  4. Host Responds: The host makes an API call to refresh the cart data.
  5. Host Publishes: The host publishes the updated cart state.
  6. Extensions Update: All subscribed extensions receive the new data and update their UI.
// When user clicks the refresh button in your extension
window.FSI.event.emit("cart.refresh", { action: "refresh_cart" });

Example 2

In this example, we indicate that the close action originated from the "pdp" (Product Detail Page). Emitting the "close" event from your extension. This notifies the host application that the extension should be closed. You can also pass additional data (like the source of the close action) as a second argument.

window.FSI.event.emit("close", { source: "pdp" });

3. Unsubscribe Event

Unsubscribing from an event means stopping your subscription to an event using the off method.

event.off(eventName, details, removeAll = false) removes a specific subscription or, when removeAll is true, removes all handlers for that event.

Syntax for Unsubscribing Event

Ensure that you have the event ID you saved while subscribing to an event. FSI needs both the function reference and the specific event ID to know exactly which subscription to remove.

note

To correctly remove a single handler, provide both name and eventId in the second parameter of off.

  1. name: This refers to the name of the function you originally passed to on.
  2. eventId: This is the ID returned when you subscribed to the event using on.
window.FSI.event.off(eventName, {
name: functionName,
eventId: storedEventId
});

Example

// Subscribe and store both values
let eventId = window.FSI.event.on("toast.error", myErrorHandler);
let functionName = myErrorHandler;

// Later, unsubscribe using both
window.FSI.event.off("toast.error", {
name: functionName,
eventId: eventId
});

FSI Supported Events

Store OS provides built-in support for a set of events (given below). When an extension emits any of the supported events, Store OS will automatically handle them and perform the corresponding action, such as sending a response.

  1. Event name: ext.ready
    Description: Emitted by the extension after initialization to signal readiness
    Example: window.FSI.event.emit("ext.ready")

  2. Event name: toast.success
    Description: Displays a success toast message
    Example: window.FSI.event.emit("toast.success", "Completed successfully")

  3. Event name: cart.refresh
    Description: Refreshes cart data in Store OS for the provided cart ID. When
    Example: window.FSI.event.emit("cart.refresh", cart_id)

  4. Event name: close
    Description: Closes the extension’s webview and returns to the previous screen
    Example: window.FSI.event.emit("close")

  5. Event name: toast.error
    Description: Displays an error toast message when the shipment detail is not found
    Example: window.FSI.event.emit("toast.error", "Shipment Details not Found")

  6. Event name: plp.open (show-plp)
    Description: Opens the Product Listing Page (PLP)
    Example: window.FSI.event.emit("plp.open")

  7. Event name: pdp.open (show-pdp)
    Description: Opens the PDP for the specified product slug
    Example: window.FSI.event.emit("pdp.open", "ginesys-test-7554433")

  8. Event name: collection.open
    Description: Opens a collection page by slug
    Example: window.FSI.event.emit("collection.open", "winter-collection")

  9. Event name: order_detail.open
    Description: Opens the Order Details screen for the given order ID
    Example: window.FSI.event.emit("order_detail.open", "FY650169700E054DA248")

  10. Event name: shipment_detail.open
    Description: Opens the Shipment Details screen for the given shipment ID
    Example: window.FSI.event.emit("shipment_detail.open", "12345677886544")

  11. Event name: order_detail.refresh
    Description: Refreshes Order and Shipment details
    Example: window.FSI.event.emit("order_detail.refresh")

Testing

To verify the functionality of the extension, use the Store OS application to open the development company where the extension is installed.

  1. Access Store OS on your preferred platform (available on iOS, Android, and web).
  2. Log in to the app.
  3. Select the development company where the extension is installed.
  4. Go to the page on which you created the binding.
  5. Select the binding that you want to test. This will launch your app in the Store OS app within the container.

Design Guidelines

Follow these design guidelines to ensure the Store OS UI is consistent across extensions.

  • UI Standard: Refer to the Store OS UI Kit↗ for UI elements, icons, and layout standards.
  • Responsiveness:
    • Extensions should adapt seamlessly between modal and full-page formats.
    • Ensure elements are adjusted for tablet and mobile displays.

Was this section helpful?