---
title: Install Personizely on Shopify Hydrogen
slug: install-shopify-hydrogen
description: Install Personizely on a Shopify Hydrogen storefront with @personizely/shopify-hydrogen: provider setup, cart and checkout hooks, page context and limits.
docTags: 
createdAt: 2026-10-16T19:34:03.899Z
---

On a Shopify Hydrogen storefront, you install Personizely with the `@personizely/shopify-hydrogen` npm package. Its `PersonizelyProvider` component connects the snippet to Hydrogen's cart and loads it in the browser. Hooks let your product forms and checkout button fire Personizely's add-to-cart and checkout triggers. You also install the Personizely Shopify app on the store, so orders are tracked server-side.

**Available on:** Shopify Hydrogen v2 with React Router v7 and React 18.

## Before you start

You need:

- **The Personizely Shopify app installed on the store**, so products sync and orders are recorded and attributed. Follow the first section of [Install Personizely on Shopify](docId\:KKBkXcEXtFXCVJdjXvQ74). You don't need the theme app embed, because Hydrogen doesn't use your Online Store theme.
- **Your website key.** It's the part of the snippet URL after `https://static.personizely.net/` and before `.js`. Find the snippet in **Settings → Website**.
- **A Storefront API access token**, which Hydrogen projects usually already have as `PUBLIC_STOREFRONT_API_TOKEN`.

## Install the package

```bash
npm install @personizely/shopify-hydrogen
```

## Set up the provider

1. Return the Storefront credentials from your root loader in `app/root.tsx`. The provider also reads `cart` from the root loader's data, which the standard Hydrogen template already returns.

```typescript
export async function loader(args: Route.LoaderArgs) {
  const { env } = args.context

  return {
    // ...your existing data, including cart
    personizely: {
      storefrontAccessToken: env.PUBLIC_STOREFRONT_API_TOKEN,
      shopDomain: env.PUBLIC_STORE_DOMAIN,
    },
  }
}
```

2. Wrap your app in `PersonizelyProvider`:

```typescript
import { PersonizelyProvider } from '@personizely/shopify-hydrogen'

export default function App() {
  const data = useRouteLoaderData<RootLoader>('root')
  if (!data) return <Outlet />

  return (
    <PersonizelyProvider
      websiteApiKey="YOUR_WEBSITE_KEY"
      storefrontAccessToken={data.personizely.storefrontAccessToken}
      shopDomain={data.personizely.shopDomain}
      locale="en-US"
    >
      <Outlet />
    </PersonizelyProvider>
  )
}
```

3. If your storefront has a Content Security Policy (Hydrogen's `createContentSecurityPolicy`), allow Personizely's hosts. See [Content Security Policy (CSP)](docId\:kHb2SYuGO9A2ulTVoNa_J).

### Provider props

| Prop                       | What it does                                                                                                                          | Values / default     |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `websiteApiKey`            | Your Personizely website key                                                                                                          | Required             |
| `storefrontAccessToken`    | Storefront API token, used to read and update the cart and products                                                                   | Required             |
| `shopDomain`               | Your shop domain, for example `myshop.myshopify.com`                                                                                  | Required             |
| `locale`                   | Shop locale, used for formatting                                                                                                      | `'en-US'`            |
| `currency`                 | `{ rate, active, base }`: conversion rate from your base currency, the active currency and the base currency                          | Base currency only   |
| `market`                   | Market handle, for [Targets](docId\:tWNdHNIcvVf9rNerxrynw)                                                                            | None                 |
| `apiVersion`               | Storefront API version                                                                                                                | `'2024-01'`          |
| `methods.formatMoney`      | `(amountInCents, includeDecimals) => string`, to format prices like your storefront                                                   | Built-in formatting  |
| `methods.builtProductPath` | `({ handle }) => string`, to build product URLs if yours aren't `/products/<handle>`                                                  | `/products/<handle>` |
| `customer`                 | The logged-in customer (`id`, `email`, `phone`, `firstName`, `lastName`, `displayName`, `hasAccount`, `tags`), for customer targeting | `null`               |

Define `currency` and `market` outside your component, or memoize them, so they keep a stable reference between renders.

## Fire add-to-cart and checkout triggers

Hydrogen handles add to cart and checkout in your own components, so you tell Personizely when they happen. Both hooks return `true` if a widget was shown, so you can hold the action while an upsell or offer is displayed.

```typescript
import { useCartAdd, useCheckout } from '@personizely/shopify-hydrogen'

const triggerCartAdd = useCartAdd()
const widgetShown = await triggerCartAdd({
  id: product.id,
  variantId: selectedVariant.id,
  price: parseFloat(selectedVariant.price.amount), // in major units, e.g. 19.99
  quantity: 1,
  handle: product.handle,
})
if (!widgetShown) {
  // add to cart as usual
}

const triggerCheckout = useCheckout()
if (!(await triggerCheckout())) {
  window.location.href = checkoutUrl
}
```

## Set the page context

Call `usePageContext` in route components so product, collection, home and cart page rules and filters work:

```typescript
import { usePageContext } from '@personizely/shopify-hydrogen'

usePageContext({
  pageType: 'product',
  product: { id: 1234567890, handle: product.handle, tags: product.tags }, // numeric ID
})

usePageContext({ pageType: 'collection', collection: { id: 9876543210 } })
usePageContext({ pageType: 'home' })
usePageContext({ pageType: 'cart' })
```

`usePersonizely()` returns `{ cart, adapter, websiteApiKey }` if you need the cart or formatting helpers directly.

## Verify it works

1. Run your storefront and open it in a normal browser window.
2. In the developer console, look for `Personizely initialized. Startup time: <n>ms`.
3. Navigate to another route. With `?ply_debug=1` in the first URL, the console logs `Page change detected` on each route change.
4. Create a test popup with the **Add to cart** trigger, start it, and add a product to the cart. The popup should appear and `useCartAdd` should return `true`.
5. Place a test order and check that it appears in reports for the Purchase goal.

## Behavior details and limitations

- **The snippet loads in the browser after hydration.** Server-rendered HTML is shown first, so [Content A/B testing with the visual editor](docId\:sRIV2YbnueXGJTEWlxZl8) can change the page a moment after it appears. For flicker-free tests of server-rendered content, use [Full-stack experiments and feature flags](docId\:OVRIbT_8RdOHkPkqg1u1S) and render the variation in your own code.
- **Theme and template tests don't apply.** They rely on Online Store themes. Price tests are documented for the Shopify Online Store; for a Hydrogen storefront, contact support. Content, split URL and full-stack campaigns, and all widgets, work.
- **Commerce elements work.** The [Products (cross-sell and upsell)](docId\:cmXGzOOKynsYjyXy79rUf) element, [Cart progress (free shipping bar)](docId:58OPYGqAeYmpHTup4IzHm), unique discount codes and [Coupon and discount codes](docId\:QXkBRk16fS8GFWjEqbW2q) auto-apply work on Hydrogen.
- **Route changes are detected automatically** and count as new page views.
- **Orders come from Shopify.** Purchases are recorded server-side from Shopify order data through the Personizely app, so the app must stay installed.
- **Consent.** Consent follows your Shopify customer privacy settings. See [Cookies and consent](docId:-HA6dgPmpYmb7x6UZQ_t2).

## Troubleshooting

- **Nothing in the console** → check that `PersonizelyProvider` wraps your routes and that your CSP allows Personizely's hosts.
- **Add-to-cart widgets never show** → your product form isn't calling the function returned by `useCartAdd`.
- **Product page rules don't match** → `usePageContext` isn't called on that route, or the product ID is a GID instead of the numeric ID.
- **Prices in widgets look wrong** → pass `currency` and `methods.formatMoney` to match your storefront's formatting.

## Related

- [Install Personizely on Shopify](docId\:KKBkXcEXtFXCVJdjXvQ74)
- [Full-stack experiments and feature flags](docId\:OVRIbT_8RdOHkPkqg1u1S)
- [Performance and flicker](docId\:sgD1BsYNMvpjqHqp_qcdi)
- [Widget triggers](docId:2xConiUT5V1g5SuzgMAuW)
- [Content Security Policy (CSP)](docId\:kHb2SYuGO9A2ulTVoNa_J)
- [JavaScript API (window.ply)](docId\:d64TegyOiwNA2GFG1eXPm)
