ShopAssist
Install

Shopify Hydrogen

Install ShopAssist on a headless Shopify storefront built with Hydrogen.

Hydrogen is a custom storefront, so it uses this package rather than the Shopify app. The Shopify theme app extension only runs inside a Shopify-hosted theme and cannot load on Hydrogen.

Your shop identifier is the *.myshopify.com domain, not your public Hydrogen URL. Using the public domain gives a shop that ShopAssist cannot find.

Install

npm i @shopassist/js @shopassist/react
app/root.tsx
import { ShopAssistProvider } from "@shopassist/react";

export default function App() {
  return (
    <html lang="en">
      <body>
        <ShopAssistProvider config={{ shopDomain: "your-shop.myshopify.com" }}>
          <Outlet />
        </ShopAssistProvider>
      </body>
    </html>
  );
}

Content Security Policy

Hydrogen sends a Content Security Policy with a nonce on every response. The widget loads from another origin, so add it to the policy:

app/entry.server.tsx
const { nonce, header, NonceProvider } = createContentSecurityPolicy({
  scriptSrc: ["'self'", "https://widget.getshopassist.com"],
  connectSrc: ["'self'", "https://api.getshopassist.com"],
  imgSrc: ["'self'", "https://cdn.shopify.com", "data:"],
});

Without this the browser blocks the widget and the console shows a CSP violation, not a ShopAssist error.

If you load the script yourself

If you prefer Hydrogen's <Script> component to the package, the widget modifies the DOM, so it must wait for hydration:

import { Script } from "@shopify/hydrogen";

<Script waitForHydration src="https://widget.getshopassist.com/shop-assist.js" />;

waitForHydration and the CSP nonce are mutually exclusive, so with this approach the CSP entry above is required rather than optional.

The package handles hydration timing for you, so prefer ShopAssistProvider unless you have a reason not to.

Adding to the Hydrogen cart

Hydrogen carries its own cart, so give the widget a bridge to it. Line-item attributes are what carry attribution onto the order.

app/components/ShopAssist.tsx
import { ShopAssistProvider } from "@shopassist/react";
import { useFetcher } from "@remix-run/react";

export function ShopAssist({ children }: { children: React.ReactNode }) {
  const fetcher = useFetcher();

  return (
    <ShopAssistProvider
      config={{
        shopDomain: "your-shop.myshopify.com",
        cart: {
          add(variantId, quantity, properties) {
            fetcher.submit(
              {
                cartAction: "ADD_TO_CART",
                lines: JSON.stringify([
                  {
                    merchandiseId: variantId,
                    quantity,
                    attributes: Object.entries(properties ?? {}).map(
                      ([key, value]) => ({ key, value }),
                    ),
                  },
                ]),
              },
              { method: "post", action: "/cart" },
            );
          },
        },
      }}
    >
      {children}
    </ShopAssistProvider>
  );
}

variantId is a Shopify variant GID, for example gid://shopify/ProductVariant/42, which is what Hydrogen's cart expects.

Product URLs

Hydrogen's default product route is /products/<handle>, which is what the widget assumes, so most stores need no routing configuration. If you localize routes, set a prefix:

config={{
  shopDomain: "your-shop.myshopify.com",
  custom: {
    currency: "EUR",
    language: "de",
    country: "DE",
    routePrefix: "/de-de",
  },
}}

Next steps

Last updated on

On this page