@elevateab/sdk 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +278 -391
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @elevateab/sdk
2
2
 
3
- Elevate AB Testing SDK for Shopify Hydrogen and Next.js with built-in analytics tracking and cart attribute tagging.
3
+ A/B Testing SDK for Shopify Hydrogen and Next.js stores.
4
4
 
5
5
  ## Installation
6
6
 
@@ -9,523 +9,410 @@ npm install @elevateab/sdk
9
9
  ```
10
10
 
11
11
  **Peer Dependencies:**
12
+ - `react` >= 18.0.0 or >= 19.0.0
13
+ - `@shopify/hydrogen` >= 2023.10.0 (Hydrogen only)
14
+ - `next` >= 13.0.0 (Next.js only)
12
15
 
13
- - `react` >= 18.0.0
14
- - `@shopify/hydrogen` >= 2023.10.0 (optional - only for Hydrogen)
16
+ ---
15
17
 
16
- ## Framework Support
18
+ ## Hydrogen Setup
17
19
 
18
- | Framework | Support | Analytics Mode |
19
- | -------------------- | ------- | ------------------------------ |
20
- | **Shopify Hydrogen** | ✅ Full | Automatic via `useAnalytics()` |
21
- | **Next.js** | ✅ Full | Manual tracking functions |
22
- | **Remix** | ✅ Full | Manual tracking functions |
23
- | **Other React** | ✅ Full | Manual tracking functions |
20
+ Hydrogen uses automatic analytics tracking via Shopify's `useAnalytics()` hook.
24
21
 
25
- ## Quick Start
22
+ ### 1. Add the Provider
26
23
 
27
- ### 1. Setup ElevateProvider
28
-
29
- Wrap your app with `ElevateProvider` - it handles everything (config fetching, analytics tracking, and event sending):
30
-
31
- ```typescript
32
- import { ElevateProvider } from "@elevateab/sdk";
24
+ ```tsx
25
+ // app/root.tsx
26
+ import { ElevateProvider, ElevateAnalytics } from "@elevateab/sdk";
27
+ import { Analytics } from "@shopify/hydrogen";
33
28
 
34
29
  export default function Root() {
35
30
  const data = useLoaderData<typeof loader>();
36
31
 
37
32
  return (
38
- <ElevateProvider
39
- storeId="mystore.myshopify.com"
40
- cart={data.cart}
41
- shop={data.shop}
42
- consent={data.consent}
43
- storefrontUrl={data.shop.primaryDomain.url}
44
- >
45
- <Outlet />
46
- </ElevateProvider>
33
+ <Analytics.Provider cart={data.cart} shop={data.shop} consent={data.consent}>
34
+ <ElevateProvider
35
+ storeId="mystore.myshopify.com"
36
+ storefrontAccessToken={env.PUBLIC_STOREFRONT_API_TOKEN}
37
+ >
38
+ <ElevateAnalytics />
39
+ <Outlet />
40
+ </ElevateProvider>
41
+ </Analytics.Provider>
47
42
  );
48
43
  }
49
44
  ```
50
45
 
51
- **That's it!** The `ElevateProvider` automatically:
46
+ That's it. Analytics events are tracked automatically when users view pages, products, add to cart, etc.
52
47
 
53
- - Fetches test configurations from CDN
54
- - ✅ Sets up Shopify Analytics tracking
55
- - ✅ Tracks all analytics events with A/B test data
56
- - ✅ Sends events to CloudFlare Worker
57
- - ✅ Manages visitor IDs and session tracking
48
+ ### 2. Add Anti-Flicker (Recommended)
58
49
 
59
- ### 2. Use A/B Tests in Your Components
60
-
61
- ```typescript
62
- import { useExperiment } from "@elevateab/sdk";
63
-
64
- function ProductPage() {
65
- const { variant, isLoading } = useExperiment("test-price-1");
66
-
67
- if (isLoading) return <div>Loading...</div>;
50
+ Prevents content flash while tests load. Add this script to `<head>` before any other scripts:
68
51
 
52
+ ```tsx
53
+ // app/root.tsx
54
+ export default function Root() {
69
55
  return (
70
- <div>
71
- {variant?.isControl ? <Price amount={99.99} /> : <Price amount={89.99} />}
72
- </div>
56
+ <html>
57
+ <head>
58
+ <script
59
+ dangerouslySetInnerHTML={{
60
+ __html: `(function(){var d=document.documentElement;d.style.opacity='0';d.style.transition='opacity 0.2s';window.__eabReveal=function(){d.style.opacity='1'};setTimeout(window.__eabReveal,2000)})();`,
61
+ }}
62
+ />
63
+ {/* other head elements */}
64
+ </head>
65
+ <body>{/* ... */}</body>
66
+ </html>
73
67
  );
74
68
  }
75
69
  ```
76
70
 
77
- ## How It Works
78
-
79
- ### Automatic Analytics Tracking
80
-
81
- The `ElevateProvider` automatically tracks the following Shopify analytics events and enriches them with A/B test data:
82
-
83
- - `page_viewed` - Page views with test assignments
84
- - `product_viewed` - Product views
85
- - `product_added_to_cart` - Add to cart events
86
- - `product_removed_from_cart` - Remove from cart events
87
- - `cart_viewed` - Cart page views
88
-
89
- ### Event Data Structure
90
-
91
- Events are sent to CloudFlare Worker with:
92
-
93
- - **Test Assignments** (`ab_test_assignments`) - All tests the user is assigned to
94
- - **Test Views** (`ab_test_views`) - Tests the user has actually viewed
95
- - **UTM Parameters** - Campaign tracking data
96
- - **Device/Browser Info** - User agent, device type, OS
97
- - **Referrer Source** - Traffic source (Google, Facebook, Direct, etc.)
98
- - **Product/Cart Data** - Product IDs, prices, quantities
99
-
100
- **No additional setup needed** - just use `ElevateProvider` and everything works automatically!
71
+ Then pass `preventFlickering` to the provider:
101
72
 
102
- ## Cart Attribute Tagging
103
-
104
- Carts are **automatically tagged** with A/B test data for order attribution.
105
-
106
- ### For Hydrogen Stores
107
-
108
- Cart attributes are automatically updated when `product_added_to_cart` event fires, **if you provide the `storefrontAccessToken`**:
109
-
110
- ```typescript
73
+ ```tsx
111
74
  <ElevateProvider
112
75
  storeId="mystore.myshopify.com"
113
- cart={data.cart}
114
- shop={data.shop}
115
- consent={data.consent}
116
- storefrontAccessToken={env.PUBLIC_STOREFRONT_API_TOKEN} // ← Add this!
76
+ storefrontAccessToken={env.PUBLIC_STOREFRONT_API_TOKEN}
77
+ preventFlickering={true}
117
78
  >
118
- <Outlet />
119
- </ElevateProvider>
120
79
  ```
121
80
 
122
- **That's it!** When users add items to cart, we automatically:
123
-
124
- 1. Track the `product_added_to_cart` event
125
- 2. Update cart attributes with A/B test data
126
-
127
- ### For Next.js / Other Stores
81
+ ---
128
82
 
129
- Pass `cartId` and `storefrontAccessToken` to `trackAddToCart()`:
83
+ ## Next.js Setup
130
84
 
131
- ```typescript
132
- await trackAddToCart({
133
- storeId: "mystore.myshopify.com",
134
- productId: "123456789",
135
- variantId: "987654321",
136
- productPrice: 99.99,
137
- productQuantity: 1,
138
- currency: "USD",
139
- // Add these to auto-update cart attributes:
140
- cartId: cart.id,
141
- storefrontAccessToken: process.env.NEXT_PUBLIC_STOREFRONT_TOKEN,
142
- });
143
- ```
85
+ Next.js requires manual tracking since it doesn't have Shopify's analytics system.
144
86
 
145
- ### Manual Cart Tagging (If Needed)
87
+ ### 1. Add the Provider
146
88
 
147
- You can also manually update cart attributes:
89
+ ```tsx
90
+ // app/layout.tsx
91
+ import { ElevateNextProvider } from "@elevateab/sdk/next";
148
92
 
149
- ```typescript
150
- import { updateCartAttributes } from "@elevateab/sdk";
151
-
152
- await updateCartAttributes(cart.id, {
153
- storefrontAccessToken: process.env.NEXT_PUBLIC_STOREFRONT_TOKEN,
154
- });
93
+ export default function RootLayout({ children }) {
94
+ return (
95
+ <html>
96
+ <head>
97
+ {/* Anti-flicker script (optional but recommended) */}
98
+ <script
99
+ dangerouslySetInnerHTML={{
100
+ __html: `(function(){var d=document.documentElement;d.style.opacity='0';d.style.transition='opacity 0.2s';window.__eabReveal=function(){d.style.opacity='1'};setTimeout(window.__eabReveal,2000)})();`,
101
+ }}
102
+ />
103
+ </head>
104
+ <body>
105
+ <ElevateNextProvider
106
+ storeId="mystore.myshopify.com"
107
+ storefrontAccessToken={process.env.NEXT_PUBLIC_STOREFRONT_TOKEN}
108
+ preventFlickering={true}
109
+ >
110
+ {children}
111
+ </ElevateNextProvider>
112
+ </body>
113
+ </html>
114
+ );
115
+ }
155
116
  ```
156
117
 
157
- > ✅ **The Storefront Access Token is SAFE to use client-side!**
158
- > It's a PUBLIC token that Shopify designed for browser use. It can only read products and manage carts - it cannot do anything destructive.
118
+ The `ElevateNextProvider` automatically:
119
+ - Tracks page views on route changes
120
+ - Initializes analytics globally
121
+ - Handles anti-flicker reveal
159
122
 
160
- ### Cart Attributes GraphQL Mutation
123
+ ### 2. Track Product Views
161
124
 
162
- If you want to handle cart attributes in your own GraphQL calls:
125
+ ```tsx
126
+ // app/product/[handle]/page.tsx
127
+ import { ProductViewTracker } from "@elevateab/sdk/next";
163
128
 
164
- ```typescript
165
- import {
166
- CART_ATTRIBUTES_UPDATE_MUTATION,
167
- getCartAttributesPayload,
168
- } from "@elevateab/sdk";
169
-
170
- const attributes = getCartAttributesPayload();
129
+ export default function ProductPage({ product }) {
130
+ return (
131
+ <>
132
+ <ProductViewTracker
133
+ productId={product.id}
134
+ productVendor={product.vendor}
135
+ productPrice={parseFloat(product.priceRange.minVariantPrice.amount)}
136
+ currency={product.priceRange.minVariantPrice.currencyCode}
137
+ />
138
+ {/* Product content */}
139
+ </>
140
+ );
141
+ }
142
+ ```
171
143
 
172
- // Use in your GraphQL mutation
173
- const result = await storefrontClient.mutate({
174
- mutation: CART_ATTRIBUTES_UPDATE_MUTATION,
175
- variables: {
176
- cartId: "gid://shopify/Cart/...",
177
- attributes,
178
- },
179
- });
144
+ ### 3. Track Add to Cart
145
+
146
+ ```tsx
147
+ import { trackAddToCart } from "@elevateab/sdk";
148
+
149
+ async function handleAddToCart() {
150
+ // Shopify GIDs are automatically converted to numeric IDs
151
+ await trackAddToCart({
152
+ productId: product.id, // "gid://shopify/Product/123" works
153
+ variantId: variant.id, // "gid://shopify/ProductVariant/456" works
154
+ productPrice: 99.99,
155
+ productQuantity: 1,
156
+ currency: "USD",
157
+ cartId: cart.id, // For cart attribute tagging
158
+ });
159
+ }
180
160
  ```
181
161
 
182
- ## Usage Examples
162
+ ---
183
163
 
184
- ### Using the Hook
164
+ ## Using A/B Tests
185
165
 
186
- ```typescript
187
- import { useExperiment } from "@elevateab/sdk";
166
+ ### useExperiment Hook
188
167
 
189
- function PriceTest() {
190
- const { variant, isLoading } = useExperiment("test-price-1");
168
+ ```tsx
169
+ import { useExperiment } from "@elevateab/sdk";
191
170
 
192
- if (isLoading) return <div>Loading...</div>;
171
+ function PricingSection() {
172
+ const { variant, isLoading } = useExperiment("pricing-test");
193
173
 
194
- // Use convenience flags
195
- if (variant?.isA) return <Price amount={99.99} label="Original" />;
196
- if (variant?.isB) return <Price amount={89.99} label="Sale Price" />;
174
+ if (isLoading) return <LoadingSkeleton />;
197
175
 
198
- return null;
176
+ if (variant?.isControl) {
177
+ return <Price amount={99.99} />;
178
+ }
179
+
180
+ return <Price amount={79.99} />;
199
181
  }
200
182
  ```
201
183
 
202
- ### Conditional Rendering
184
+ ### Variant Properties
203
185
 
204
- ```typescript
205
- function ContentTest() {
206
- const { variant } = useExperiment("test-headline-1");
186
+ ```tsx
187
+ const { variant } = useExperiment("test-id");
207
188
 
208
- return (
209
- <div>
210
- {variant?.isControl ? (
211
- <h1>Buy Now and Save!</h1>
212
- ) : (
213
- <h1>Limited Time Offer - 20% Off</h1>
214
- )}
215
- </div>
216
- );
217
- }
189
+ variant?.isControl // true if control group
190
+ variant?.isA // true if variant A
191
+ variant?.isB // true if variant B
192
+ variant?.isC // true if variant C
193
+ variant?.isD // true if variant D
194
+ variant?.id // variant ID
195
+ variant?.name // variant name
218
196
  ```
219
197
 
220
- ### Multiple Variations
198
+ ### Multiple Variants
221
199
 
222
- ```typescript
223
- function MultiVariantTest() {
224
- const { variant } = useExperiment("test-layout-1");
200
+ ```tsx
201
+ function LayoutTest() {
202
+ const { variant } = useExperiment("layout-test");
225
203
 
226
204
  if (variant?.isA) return <LayoutA />;
227
205
  if (variant?.isB) return <LayoutB />;
228
206
  if (variant?.isC) return <LayoutC />;
229
- if (variant?.isD) return <LayoutD />;
230
207
 
231
- return <LayoutDefault />;
208
+ return <DefaultLayout />;
232
209
  }
233
210
  ```
234
211
 
235
- ## Advanced Usage
236
-
237
- ### Cookie & Storage Management
238
-
239
- The SDK uses cookies and session storage for state management:
212
+ ---
240
213
 
241
- **Cookies (1 year expiration):**
214
+ ## Preview Mode
242
215
 
243
- - `eabUserId` - Persistent visitor ID
244
- - `ABTL` - Test assignments (which variant each test is assigned to)
245
- - `ABAU` - Unique test views (which tests have been viewed)
246
- - `_shopify_y` - Shopify client ID (read-only)
216
+ Test specific variants without affecting live traffic. Add URL parameters:
247
217
 
248
- **Session Storage:**
249
-
250
- - `eabSessionId` - Session identifier
251
- - `ABAV` - Session test views
252
- - `eabReferrer` - Entry referrer
253
- - `eabEntry` - Entry page URL
254
-
255
- ### Utility Functions
256
-
257
- ```typescript
258
- import {
259
- assignVariant,
260
- getTestList,
261
- getVisitorId,
262
- getSessionId,
263
- parseAddViewData,
264
- } from "@elevateab/sdk";
265
-
266
- // Get current test assignments
267
- const assignments = getTestList(); // { "test-1": "variant-a", "test-2": "control" }
268
-
269
- // Get visitor ID
270
- const visitorId = getVisitorId(); // "uuid-v4"
271
-
272
- // Get session ID
273
- const sessionId = getSessionId(); // "uuid-v4"
274
-
275
- // Parse analytics data
276
- const analyticsData = parseAddViewData({
277
- referrer: document.referrer,
278
- entryPage: window.location.href,
279
- userAgent: navigator.userAgent,
280
- });
281
- // Returns: UTM params, device type, browser info, referrer source, etc.
282
218
  ```
283
-
284
- ### Device & Traffic Detection
285
-
286
- ```typescript
287
- import {
288
- getDeviceType,
289
- getTrafficSource,
290
- checkFacebookBrowser,
291
- checkInstagramBrowser,
292
- } from "@elevateab/sdk";
293
-
294
- const device = getDeviceType(); // "desktop" | "tablet" | "mobile"
295
- const source = getTrafficSource(); // "facebook" | "google" | "direct" | etc.
296
- const isFB = checkFacebookBrowser(); // boolean
297
- const isIG = checkInstagramBrowser(); // boolean
219
+ https://yourstore.com/?eabUserPreview=true&abtid=<test-id>&eab_tests=<short-id>_<variant-id>
298
220
  ```
299
221
 
300
- ### Custom Event Tracking
301
-
302
- For advanced use cases, access the analytics utilities directly:
303
-
304
- ```typescript
305
- import {
306
- extractProductId,
307
- extractProductVariantId,
308
- cleanCartToken,
309
- sanitizeString,
310
- roundToTwo,
311
- } from "@elevateab/sdk";
312
-
313
- // Extract IDs from Shopify GIDs
314
- const productId = extractProductId("gid://shopify/Product/123456");
315
- // Returns: "123456"
316
-
317
- const variantId = extractProductVariantId(
318
- "gid://shopify/ProductVariant/789012"
319
- );
320
- // Returns: "789012"
321
-
322
- // Clean and sanitize data
323
- const cleanToken = cleanCartToken("token?param=value");
324
- const safeString = sanitizeString(userInput);
325
- const price = roundToTwo(99.999); // 100.00
222
+ Example:
223
+ ```
224
+ https://yourstore.com/products/shirt?eabUserPreview=true&abtid=abc123&eab_tests=c123_12345
326
225
  ```
327
226
 
328
- ## Test Types Support
329
-
330
- The SDK provides infrastructure for multiple test types:
331
-
332
- - **Split URL Tests** - Redirect tests between different URLs
333
- - **Price Tests** - A/B test different pricing strategies
334
- - **Content Tests** - Test different copy, headlines, CTAs
335
- - **Custom Code Tests** - Run custom JavaScript for advanced tests
336
-
337
- ### Example: Split URL Test
338
-
339
- ```typescript
340
- function SplitURLTest() {
341
- const { variant } = useExperiment("test-split-url-1");
227
+ Check if in preview mode:
342
228
 
343
- useEffect(() => {
344
- if (
345
- variant?.handle &&
346
- window.location.pathname !== `/products/${variant.handle}`
347
- ) {
348
- window.location.href = `/products/${variant.handle}`;
349
- }
350
- }, [variant]);
229
+ ```tsx
230
+ import { isPreviewMode } from "@elevateab/sdk";
351
231
 
352
- return null;
232
+ if (isPreviewMode()) {
233
+ // Show preview indicator
353
234
  }
354
235
  ```
355
236
 
356
- ### Example: Price Test
237
+ ---
357
238
 
358
- ```typescript
359
- function PriceTest({ originalPrice }: { originalPrice: number }) {
360
- const { variant } = useExperiment("test-price-1");
239
+ ## Geo-Targeting
361
240
 
362
- const displayPrice = variant?.price
363
- ? parseFloat(variant.price)
364
- : originalPrice;
241
+ Get user's country for location-based tests:
365
242
 
366
- return <Price amount={displayPrice} />;
367
- }
243
+ ```tsx
244
+ import { getUserCountry } from "@elevateab/sdk";
245
+
246
+ const country = getUserCountry(); // "US", "CA", "GB", etc.
368
247
  ```
369
248
 
370
- ## API Reference
249
+ Country is detected from:
250
+ 1. `localization` cookie (set by Shopify)
251
+ 2. Cloudflare `CF-IPCountry` header
252
+ 3. Falls back to `null` if unavailable
371
253
 
372
- ### Components
254
+ ---
373
255
 
374
- #### `<ElevateProvider>`
256
+ ## Cart Attribute Tagging
375
257
 
376
- The main component that handles everything - config fetching, analytics tracking, and event sending.
258
+ Orders are attributed to A/B tests via cart attributes. This happens automatically when you provide `storefrontAccessToken` and `cartId`.
377
259
 
378
- ```typescript
379
- interface ElevateProviderProps {
380
- storeId: string; // Your Shopify store ID (required)
381
- cart?: any; // Cart object from Shopify (Hydrogen only)
382
- shop?: any; // Shop object from Shopify (Hydrogen only)
383
- consent?: any; // Consent object from Shopify (Hydrogen only)
384
- hasLocalizedPaths?: boolean; // Set true if homepage is at /en-us/, /fr-ca/, etc.
385
- workerUrl?: string; // Custom CloudFlare Worker endpoint
386
- ordersWorkerUrl?: string; // Custom orders endpoint for checkout_completed
387
- children: React.ReactNode;
388
- }
389
- ```
260
+ ### Automatic (Recommended)
390
261
 
391
- **Basic Usage:**
262
+ For Hydrogen, pass `storefrontAccessToken` to the provider:
392
263
 
393
- ```typescript
264
+ ```tsx
394
265
  <ElevateProvider
395
266
  storeId="mystore.myshopify.com"
396
- cart={data.cart}
397
- shop={data.shop}
398
- consent={data.consent}
399
- >
400
- <Outlet />
401
- </ElevateProvider>
267
+ storefrontAccessToken={env.PUBLIC_STOREFRONT_API_TOKEN}
268
+ />
402
269
  ```
403
270
 
404
- **With Localized Paths:**
271
+ For Next.js, pass `cartId` to `trackAddToCart`:
405
272
 
406
- ```typescript
407
- <ElevateProvider
408
- storeId="mystore.myshopify.com"
409
- cart={data.cart}
410
- shop={data.shop}
411
- consent={data.consent}
412
- hasLocalizedPaths={true} // Only if homepage is at /en-us/, /fr-ca/, etc.
413
- >
414
- <Outlet />
415
- </ElevateProvider>
273
+ ```tsx
274
+ trackAddToCart({
275
+ productId: "123",
276
+ variantId: "456",
277
+ cartId: cart.id,
278
+ // ...
279
+ });
416
280
  ```
417
281
 
418
- ### Hooks
282
+ ### Manual (If Needed)
419
283
 
420
- #### `useExperiment(testId: string)`
284
+ ```tsx
285
+ import { updateCartAttributes } from "@elevateab/sdk";
421
286
 
422
- Get assigned variant for a test.
287
+ await updateCartAttributes(cartId, {
288
+ storefrontAccessToken: process.env.NEXT_PUBLIC_STOREFRONT_TOKEN,
289
+ });
290
+ ```
423
291
 
424
- ```typescript
425
- const { variant, isLoading } = useExperiment("test-id");
292
+ The Storefront Access Token is safe to use client-side. It's a public token designed for browser use.
426
293
 
427
- // variant properties:
428
- // - id: string - Variant ID
429
- // - name: string - Variant name
430
- // - weight: number - Traffic percentage
431
- // - isControl: boolean - Is this the control variant
432
- // - isA, isB, isC, isD: boolean - Position flags
433
- // - handle?: string - Product handle (for product tests)
434
- // - price?: string - Price override (for price tests)
435
- ```
294
+ ---
295
+
296
+ ## Utility Functions
297
+
298
+ ### Shopify ID Helpers
436
299
 
437
- #### `useElevateConfig()`
300
+ ```tsx
301
+ import { extractShopifyId, isShopifyGid } from "@elevateab/sdk";
438
302
 
439
- Access the full configuration context.
303
+ // Extract numeric ID from GID
304
+ extractShopifyId("gid://shopify/Product/123456"); // "123456"
305
+ extractShopifyId("123456"); // "123456"
440
306
 
441
- ```typescript
442
- const { config } = useElevateConfig();
443
- // config.tests: Test[] - All active tests
307
+ // Check if string is a GID
308
+ isShopifyGid("gid://shopify/Product/123"); // true
309
+ isShopifyGid("123456"); // false
444
310
  ```
445
311
 
446
- ### Functions
312
+ Note: Tracking functions automatically extract IDs, so you rarely need these directly.
447
313
 
448
- #### Cart Attributes
314
+ ### Visitor & Session
449
315
 
450
- - `updateCartAttributes(cartId, options)` - Update cart with test data
451
- - `cleanupCartAttributes(cartId, options)` - Remove test data from cart
452
- - `getCartAttributesPayload()` - Get current test data as attributes array
316
+ ```tsx
317
+ import { getVisitorId, getSessionId, getTestList } from "@elevateab/sdk";
453
318
 
454
- #### Storage
319
+ getVisitorId(); // Persistent visitor UUID
320
+ getSessionId(); // Session UUID
321
+ getTestList(); // { "test-1": "variant-a", "test-2": "control" }
322
+ ```
455
323
 
456
- - `getVisitorId()` - Get or create visitor ID
457
- - `getSessionId()` - Get or create session ID
458
- - `getTestList()` - Get current test assignments
459
- - `setCookie(name, value)` - Set a cookie (1 year expiration)
460
- - `getCookie(name)` - Get a cookie value
324
+ ### Device & Traffic Detection
461
325
 
462
- #### Analytics
326
+ ```tsx
327
+ import { getDeviceType, getTrafficSource } from "@elevateab/sdk";
463
328
 
464
- - `parseAddViewData(params)` - Parse UTM params, device info, referrer
465
- - `getPageTypeFromPathname(path)` - Detect page type
466
- - `extractProductId(gid)` - Extract product ID from Shopify GID
467
- - `extractProductVariantId(gid)` - Extract variant ID from Shopify GID
329
+ getDeviceType(); // "desktop" | "tablet" | "mobile"
330
+ getTrafficSource(); // "facebook" | "google" | "instagram" | "direct" | "other"
331
+ ```
468
332
 
469
- ## Features
333
+ ---
470
334
 
471
- - **TypeScript** - Full type safety with zero config
472
- - ✅ **React Server Components** - Compatible with RSC
473
- - ✅ **Analytics Tracking** - Automatic event tracking via @shopify/hydrogen
474
- - ✅ **Cart Tagging** - Attribute orders to A/B tests
475
- - ✅ **Device Detection** - Mobile, tablet, desktop detection
476
- - ✅ **Traffic Source Detection** - Facebook, Instagram, Google, etc.
477
- - ✅ **UTM Parameter Tracking** - Campaign attribution
478
- - ✅ **ESM & CJS** - Dual format for maximum compatibility
479
- - ✅ **Tree-shakeable** - Import only what you need
480
- - ✅ **Minified** - Optimized bundle size
335
+ ## Analytics Events
481
336
 
482
- ## Compatibility
337
+ The SDK tracks these events:
483
338
 
484
- - **Shopify Hydrogen**: Full support (2023.10.0+) - Automatic analytics
485
- - **Next.js**: ✅ Full support (13+, 14+, 15+) - Manual tracking ([See guide](./NEXTJS_EXAMPLE.md))
486
- - **Remix**: Full support - Manual tracking
487
- - **React**: 18.0.0+
488
- - **TypeScript**: 5.0.0+
489
- - **Node.js**: 18.0.0+
339
+ | Event | Hydrogen | Next.js |
340
+ |-------|----------|---------|
341
+ | `page_viewed` | Automatic | Automatic (via provider) |
342
+ | `product_viewed` | Automatic | `ProductViewTracker` or `trackProductView()` |
343
+ | `product_added_to_cart` | Automatic | `trackAddToCart()` |
344
+ | `product_removed_from_cart` | Automatic | `trackRemoveFromCart()` |
345
+ | `cart_viewed` | Automatic | `trackCartView()` |
346
+ | `search_submitted` | Automatic | `trackSearchSubmitted()` |
347
+ | `checkout_started` | Automatic | `trackCheckoutStarted()` |
348
+ | `checkout_completed` | Automatic | `trackCheckoutCompleted()` |
490
349
 
491
- ## Quick Start Guides
350
+ ---
492
351
 
493
- - **Hydrogen**: See below for automatic analytics setup
494
- - **Next.js**: See [Next.js Example](./NEXTJS_EXAMPLE.md) for manual tracking
352
+ ## API Reference
495
353
 
496
- ## 🧪 Sandbox Stores for Testing
354
+ ### ElevateProvider Props
497
355
 
498
- We've set up complete sandbox Shopify stores to help you test the Elevate SDK:
356
+ ```tsx
357
+ interface ElevateProviderProps {
358
+ storeId: string; // Required: your-store.myshopify.com
359
+ storefrontAccessToken?: string; // For cart attribute tagging
360
+ preventFlickering?: boolean; // Enable anti-flicker (default: false)
361
+ hasLocalizedPaths?: boolean; // True if homepage is at /en-us/, /fr-ca/, etc.
362
+ workerUrl?: string; // Custom analytics endpoint
363
+ children: React.ReactNode;
364
+ }
365
+ ```
499
366
 
500
- ### Hydrogen Sandbox Store
367
+ ### Tracking Functions (Next.js)
501
368
 
502
- **Location:** `hydrogen-shopify-sandbox/`
369
+ All tracking functions accept Shopify GIDs directly - they're converted automatically.
503
370
 
504
- A fully functional Shopify Hydrogen storefront with Elevate SDK integration.
371
+ ```tsx
372
+ // Page view (auto-tracked by ElevateNextProvider)
373
+ trackPageView();
505
374
 
506
- **Quick Start:**
375
+ // Product view
376
+ trackProductView({
377
+ productId: "gid://shopify/Product/123",
378
+ productPrice: 99.99,
379
+ currency: "USD",
380
+ });
507
381
 
508
- ```bash
509
- cd hydrogen-shopify-sandbox
510
- npm install
511
- npm run dev
382
+ // Add to cart
383
+ trackAddToCart({
384
+ productId: "123",
385
+ variantId: "456",
386
+ productPrice: 99.99,
387
+ productQuantity: 1,
388
+ currency: "USD",
389
+ cartId: "gid://shopify/Cart/abc", // Optional: enables cart tagging
390
+ });
391
+
392
+ // Other events
393
+ trackRemoveFromCart({ productId, variantId, ... });
394
+ trackCartView({ cartTotalPrice, cartItems, ... });
395
+ trackSearchSubmitted({ searchQuery });
396
+ trackCheckoutStarted({ cartTotalPrice, cartItems, ... });
397
+ trackCheckoutCompleted({ orderId, cartTotalPrice, cartItems, ... });
512
398
  ```
513
399
 
514
- **Features:**
515
- - ✅ Complete ElevateProvider integration
516
- - ✅ Automatic analytics tracking
517
- - ✅ Cart attribute tagging
518
- - ✅ Multiple A/B test examples
519
- - ✅ Real Shopify products and cart
400
+ ---
520
401
 
521
- [View Hydrogen Sandbox Documentation →](./hydrogen-shopify-sandbox/README.md)
402
+ ## Cookies & Storage
522
403
 
523
- [View Complete Sandbox Setup Guide →](./SANDBOX_SETUP.md)
404
+ **Cookies (1 year):**
405
+ - `eabUserId` - Visitor ID
406
+ - `ABTL` - Test assignments
407
+ - `ABAU` - Unique test views
408
+ - `eabUserPreview` - Preview mode flag
524
409
 
525
- ## License
410
+ **Session Storage:**
411
+ - `eabSessionId` - Session ID
412
+ - `ABAV` - Session test views
526
413
 
527
- MIT
414
+ ---
528
415
 
529
- ## Support
416
+ ## License
530
417
 
531
- For issues and questions, please visit [GitHub Issues](https://github.com/abshop/headless-npm/issues).
418
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevateab/sdk",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Elevate AB Testing SDK for Hydrogen and Remix frameworks",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",