1. Visually Help Center
  2. Headless Integrations

Visually.io | Generic Headless (SPA/PWA/Hydrogen2) Integration

Welcome to our comprehensive tutorial on integrating Visually.io into your custom headless storefront. This guide will walk you through the process step by step.

Add Visually.io SDK

To get started, you need to include the Visually.io runtime dependencies in the <head> section of your index.html file. Be sure to place these script tags as close to the beginning of the <head> tag as possible. Replace ANALYTICS_KEY and STORE_ALIAS with the values provided to you by Visually.io.

<!--  index.html  -->
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/assets/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<script type="text/javascript" rel="preconnect prefetch"
<script type="text/javascript" rel="preconnect prefetch"
<script defer type="application/javascript" src="https://sdk.loomi-prod.xyz/v/visually-a-spa.js"></script>

<!-- ... -->

Notify our SDK on context changes:

To enable Visually.io to send analytics and track the user's journey throughout the session, you must set up the following hooks in your code:

declare global {
interface Window {
visually: {
onProductChanged: (productId: number, selectedVariantId: number, variantPrice: number) => void;
onCurrencyChanged: (currency: string) => void;
onPageTypeChanged: (pageType: 'home'|'product'|'catalog'|'other') => void;
onLocaleChanged: (locale: string) => void;
onCartChanged: (cart: CartBase) => void;
onUserIdChanged: (userId: string) => void;
visuallyConnect: (instrument: VisuallyInstrument) => void

For instance, when the currency changes, you should call:

window.visually.onCurrencyChanged(currentCurrency || "USD")

Create a Visually.io Instrument

To allow Visually.io to interact with various components on your storefront, you need to create an object that adheres to the following interface:

interface CartBase {
items: Array<{ variant_id: number, quantity: number, product_id: number, price: number }>
token: string
currency: string
attributes: Array<{ key: string, value: string }>
total_price: number
export interface VisuallyInstrument {
openCartDrawer: () => void;
closeCartDrawer: () => void;
// should create cart if none
addToCart: (variantId: string, quantity: number) => Promise<any>;
cartClear: () => void;
cartAddAttributes: (attributes: { attributes: Array<{ key: string, value: string }> }, cb: (cart: any) => void) => void; // used to add attributes to the cart, used for order attribution.
initialProductId: number;
pageType: string;
initialVariantId: number; // optional - only for PDP pages, current variant id
initialVariantPrice: number; // optional - only for PDP pages, current variant price
initialLocale: string; // optional - initial locale - 'en-US' by default
initialCurrency: string; // optional - initial currency - 'USD' by default
initialCart: CartBase; // initial cart if user has a cart, ( SEE CartBase interface )
customerTags: Array<string>; //OPTIONAL: SHPOIFY CUSTOMER TAGS

After defining your instrument, invoke our bootstrap method during the initial page load at the root of your application:

useEffect(() => {
}, []);

Here, instrumentationTool should implement the VisuallyInstrument interface. This ensures that Visually.io is properly integrated into your e-commerce SPA/PWA.

Allowed domains

If the SPA has a security mechanism that allows the website to run only on specific domains

We require to add the following domains to the domains 'allow list'

- visually.io

- loomi.me

- vsly.local:8000

For any further questions or assistance, please don't hesitate to reach out to us.