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/reactimport { 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:
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.
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
- Attribute orders back to conversations.
- Add to your cart in more detail.
Last updated on