Elevate AB Testing SDK for Hydrogen and Remix frameworks
npm install @elevateab/sdkA/B Testing SDK for Shopify Hydrogen and Next.js stores.
``bash`
npm install @elevateab/sdk
Peer Dependencies:
- react >= 18.0.0 or >= 19.0.0@shopify/hydrogen
- >= 2023.10.0 (Hydrogen only)next
- >= 13.0.0 (Next.js only)
---
`ts
// vite.config.ts
import {elevate} from '@elevateab/sdk/vite';
export default defineConfig({
plugins: [hydrogen(), oxygen(), elevate(), reactRouter(), tsconfigPaths()],
// ...
});
`
The elevate() plugin configures Vite's SSR bundling so the SDK works correctly with Hydrogen's analytics during development (HMR). This is required for Hydrogen stores.
Hydrogen uses automatic analytics tracking via Shopify's useAnalytics() hook.
`tsx
// app/root.tsx
import { ElevateProvider, ElevateAnalytics } from "@elevateab/sdk";
import { Analytics, useNonce } from "@shopify/hydrogen";
export default function Root() {
const data = useLoaderData
const nonce = useNonce(); // Required for CSP compliance
return (
shop={data.shop}
consent={data.consent}
>
storefrontAccessToken={env.PUBLIC_STOREFRONT_API_TOKEN}
preventFlickering={true}
nonce={nonce}
>
);
}
`
That's it! Analytics events are tracked automatically when users view pages, products, add to cart, etc.
The preventFlickering={true} prop prevents content flash while tests load.
For Hydrogen stores: Add Elevate CDN domains to your CSP in app/entry.server.tsx:
`tsx
// app/entry.server.tsx
export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
reactRouterContext: EntryContext,
context: HydrogenRouterContextProvider,
) {
const {nonce, header, NonceProvider} = createContentSecurityPolicy({...});
// Add Elevate domains to CSP
let elevateCSP = header
.replace(
/script-src-elem\s+([^;]+)/,
script-src-elem $1 https://d19dz5bxptjmv5.cloudfront.netconnect-src $1 https://d19dz5bxptjmv5.cloudfront.net https://d339co84ntxcme.cloudfront.net https://configs.elevateab.com
)
.replace(
/connect-src\s+([^;]+)/,
);
responseHeaders.set('Content-Security-Policy', elevateCSP);
// ... rest of your code
}
`
For other frameworks (Next.js, Gatsby, etc.):
Add the following CSP header:
``
Content-Security-Policy: script-src 'self' https://d19dz5bxptjmv5.cloudfront.net; script-src-elem 'self' https://d19dz5bxptjmv5.cloudfront.net; connect-src 'self' https://d19dz5bxptjmv5.cloudfront.net https://d339co84ntxcme.cloudfront.net https://configs.elevateab.com
---
Next.js requires manual tracking since it doesn't have Shopify's analytics system.
`tsx
// app/layout.tsx
import { ElevateNextProvider } from "@elevateab/sdk/next";
export default function RootLayout({ children }) {
return (
The
ElevateNextProvider automatically:- Tracks page views on route changes
- Initializes analytics globally
- Prevents content flicker (when
preventFlickering={true})$3
`tsx
// app/product/[handle]/page.tsx
import { ProductViewTracker } from "@elevateab/sdk/next";export default function ProductPage({ product }) {
return (
<>
productId={product.id}
productVendor={product.vendor}
productPrice={parseFloat(product.priceRange.minVariantPrice.amount)}
currency={product.priceRange.minVariantPrice.currencyCode}
/>
{/ Product content /}
>
);
}
`$3
`tsx
import { trackAddToCart } from "@elevateab/sdk";async function handleAddToCart() {
// Shopify GIDs are automatically converted to numeric IDs
await trackAddToCart({
productId: product.id, // "gid://shopify/Product/123" works
variantId: variant.id, // "gid://shopify/ProductVariant/456" works
productPrice: 99.99,
productQuantity: 1,
currency: "USD",
cartId: cart.id, // For cart attribute tagging
});
}
`$3
`tsx
import {
trackRemoveFromCart,
trackCartView,
trackSearchSubmitted,
trackCheckoutStarted,
trackCheckoutCompleted,
} from "@elevateab/sdk";// Remove from cart
await trackRemoveFromCart({
productId: product.id,
variantId: variant.id,
productPrice: 99.99,
productQuantity: 1,
});
// Cart view
await trackCartView({
cartTotalPrice: 199.99,
cartTotalQuantity: 2,
currency: "USD",
cartItems: [
{ productId: "123", variantId: "456", productPrice: 99.99, productQuantity: 1 },
],
});
// Search
await trackSearchSubmitted({ searchQuery: "blue shirt" });
// Checkout started
await trackCheckoutStarted({
cartTotalPrice: 199.99,
currency: "USD",
cartItems: [...],
});
// Checkout completed (order placed)
await trackCheckoutCompleted({
orderId: "order_123",
cartTotalPrice: 199.99,
currency: "USD",
cartItems: [...],
});
`---
Using A/B Tests
$3
`tsx
import { useExperiment } from "@elevateab/sdk";function PricingSection() {
const { variant, isLoading } = useExperiment("pricing-test");
if (isLoading) return ;
if (variant?.isControl) {
return ;
}
return ;
}
`$3
`tsx
const { variant } = useExperiment("test-id");variant?.isControl; // true if control group
variant?.isA; // true if variant A
variant?.isB; // true if variant B
variant?.isC; // true if variant C
variant?.isD; // true if variant D
variant?.id; // variant ID
variant?.name; // variant name
`$3
`tsx
function LayoutTest() {
const { variant } = useExperiment("layout-test"); if (variant?.isA) return ;
if (variant?.isB) return ;
if (variant?.isC) return ;
return ;
}
`---
Preview Mode
Test specific variants without affecting live traffic. Add URL parameters:
`
https://yourstore.com/?eabUserPreview=true&abtid=&eab_tests=_
`Example:
`
https://yourstore.com/products/shirt?eabUserPreview=true&abtid=abc123&eab_tests=c123_12345
`Check if in preview mode:
`tsx
import { isPreviewMode } from "@elevateab/sdk";if (isPreviewMode()) {
// Show preview indicator
}
`---
Cart Attribute Tagging
Orders are attributed to A/B tests via cart attributes. This happens automatically when you provide
storefrontAccessToken and cartId.For Hydrogen, pass
storefrontAccessToken and nonce to the provider:`tsx
const nonce = useNonce(); storeId="mystore.myshopify.com"
storefrontAccessToken={env.PUBLIC_STOREFRONT_API_TOKEN}
nonce={nonce}
/>;
`For Next.js, pass
cartId to trackAddToCart:`tsx
trackAddToCart({
productId: "123",
variantId: "456",
cartId: cart.id,
// ...
});
`The Storefront Access Token is safe to use client-side - it's a public token designed for browser use.
---
Utility Functions
$3
`tsx
import { extractShopifyId, isShopifyGid } from "@elevateab/sdk";extractShopifyId("gid://shopify/Product/123456"); // "123456"
isShopifyGid("gid://shopify/Product/123"); // true
`Note: Tracking functions automatically extract IDs, so you rarely need these directly.
---
API Reference
$3
`tsx
interface ElevateProviderProps {
storeId: string; // Required: your-store.myshopify.com
storefrontAccessToken?: string; // For cart attribute tagging
preventFlickering?: boolean; // Prevent content flash during test load (recommended)
nonce?: string; // Only needed if you have strict CSP headers
children: React.ReactNode;
}
`$3
| Event | Hydrogen | Next.js |
| ------------------ | --------- | -------------------------- |
| Page view | Automatic | Automatic |
| Product view | Automatic |
ProductViewTracker |
| Add to cart | Automatic | trackAddToCart() |
| Remove from cart | Automatic | trackRemoveFromCart() |
| Cart view | Automatic | trackCartView() |
| Search | Automatic | trackSearchSubmitted() |
| Checkout started | Automatic | trackCheckoutStarted() |
| Checkout completed | Automatic | trackCheckoutCompleted()` |---
MIT