npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@getcontextual/shopify-sdk

v1.1.4

Published

Easy integration for tracking on headless Shopify sites

Readme

@getcontextual/shopify-sdk

A comprehensive tracking SDK for headless Shopify stores. Works with vanilla JavaScript, React, and any SSR framework. Features SSR-safe tracking, and automatic GTM integration.

Features

  • 🚀 Framework Agnostic: Works with vanilla JS, React, and SSR frameworks like Next.js
  • 🔒 SSR-Safe: All tracking methods gracefully handle server-side rendering
  • 📦 Automatic GTM: Zero-configuration Google Tag Manager integration
  • 📊 Comprehensive Events: Product views, collections, cart, checkout, search, and more
  • 🎨 TypeScript: Full TypeScript support with Shopify type definitions
  • Auto-Flush: Automatic event batching for optimal performance
  • 🔄 React Safe: Handles React Strict Mode and SSR correctly

Installation

npm install @getcontextual/shopify-sdk
# or
pnpm add @getcontextual/shopify-sdk
# or
yarn add @getcontextual/shopify-sdk

Peer Dependencies: React (≥16.8.0) is optional and only needed if using React components.

Quick Start

Vanilla JavaScript

import { init, trackProductView } from "@getcontextual/shopify-sdk/vanilla";

// Initialize once
init({
  merchantId: "your-store.myshopify.com",
  autoTrackPageView: true,
  gtmContainerId: "GTM-XXXXXXX", // Optional
});

// Track events
trackProductView(productVariant);

React

import { TrackerProvider, useTracker } from "@getcontextual/shopify-sdk/react";

function App() {
  return (
    <TrackerProvider config={{ merchantId: "your-store.myshopify.com" }}>
      <ProductPage product={product} />
    </TrackerProvider>
  );
}

function ProductPage({ product }) {
  const { trackProductView } = useTracker();

  useEffect(() => {
    trackProductView(product.variant);
  }, [product.variant, trackProductView]);

  return <div>{product.title}</div>;
}

Vanilla JavaScript API

Perfect for static sites, Vue.js, Svelte, or any framework without React.

Initialization

import { init } from "@getcontextual/shopify-sdk/vanilla";

init({
  merchantId: "your-store.myshopify.com", // Required
  autoTrackPageView: true, // Automatically track page views
  gtmContainerId: "GTM-XXXXXXX", // Optional: GTM container ID
  autoFlush: true, // Auto-flush events (default: true)
  flushInterval: 100, // Flush interval in ms (default: 100)
});

Tracking Events

import {
  trackPageView,
  trackProductView,
  trackCollectionView,
  trackAddToCart,
  trackCheckoutStarted,
  trackCheckoutCompleted,
  trackSearch,
  identify,
} from "@getcontextual/shopify-sdk/vanilla";

// Track page view
trackPageView();

// Track product view
trackProductView(productVariant);

// Track collection view
trackCollectionView(collection);

// Track add to cart
trackAddToCart(cartLine);
// Track checkout
trackCheckoutStarted(checkout);
trackCheckoutCompleted(checkout);

// Track search
trackSearch(query, searchResults);

// Identify user
identify({
  email: "[email protected]",
  phone: "+1234567890",
  firstName: "John",
  lastName: "Doe",
});

React API

Uses React Context for dependency injection, making it easy to access tracking functions throughout your app.

Setup

import { TrackerProvider } from "@getcontextual/shopify-sdk/react";

function App() {
  return (
    <TrackerProvider
      config={{
        merchantId: "your-store.myshopify.com",
        gtmContainerId: "GTM-XXXXXXX", // Optional
        autoFlush: true,
        flushInterval: 100,
      }}
    >
      <YourApp />
    </TrackerProvider>
  );
}

Using Hooks

import { useTracker } from "@getcontextual/shopify-sdk/react";

function ProductPage({ product }) {
  const { trackProductView } = useTracker();

  useEffect(() => {
    trackProductView(product.variant);
  }, [product.variant, trackProductView]);

  return <div>{product.title}</div>;
}

function AddToCartButton({ cartLine }) {
  const { trackAddToCart } = useTracker();

  const handleClick = () => {
    // Your add to cart logic
    trackAddToCart(cartLine);
  };

  return <button onClick={handleClick}>Add to Cart</button>;
}

Using Components

For automatic tracking when components mount:

import {
  ProductTracking,
  CollectionTracking,
  AddToCartTracking,
  CheckoutStartedTracking,
  CheckoutCompletedTracking,
  IdentifyTracking,
  PageViewTracker,
} from "@getcontextual/shopify-sdk/react";

function ProductPage({ product }) {
  return (
    <>
      <ProductTracking productVariant={product.variant} />
      <h1>{product.title}</h1>
    </>
  );
}

function CheckoutPage({ checkout }) {
  return (
    <>
      <CheckoutStartedTracking checkout={checkout} />
      {/* Your checkout UI */}
    </>
  );
}

Nextjs/Server-Side Rendering (SSR) Guide

All tracking methods are SSR-safe and will gracefully no-op on the server-side:

  • ✅ Safe to call tracking methods during SSR
  • ✅ No errors or warnings on the server
  • ✅ Events only tracked on the client-side after hydration
  • ✅ Works with Next.js, Remix, and other SSR frameworks

Initialize Tracker

Create a client component to initialize the tracker:

"use client";

import { useEffect, useContext, createContext } from "react";
import {
  init,
  trackPageView,
  trackProductView,
  trackCollectionView,
  trackAddToCart,
  trackCheckoutStarted,
  trackCheckoutCompleted,
  trackSearch,
  identify,
} from "@getcontextual/shopify-sdk/vanilla";

import type { HeadlessShopifyConfig } from "../tracker";

interface TrackerContextValue {
  trackPageView: typeof trackPageView;
  trackProductView: typeof trackProductView;
  trackCollectionView: typeof trackCollectionView;
  trackAddToCart: typeof trackAddToCart;
  trackCheckoutStarted: typeof trackCheckoutStarted;
  trackCheckoutCompleted: typeof trackCheckoutCompleted;
  trackSearch: typeof trackSearch;
  identify: typeof identify;
}

const TrackerContext = createContext<TrackerContextValue | null>(null);

export function TrackerProvider({
  merchantId: string,
}: {
  merchantId: string;
}) {
  useEffect(() => {
    init({ merchantId, autoTrackPageView: false });
  }, [config]);

  const value: TrackerContextValue = {
    trackPageView,
    trackProductView,
    trackCollectionView,
    trackAddToCart,
    trackSearch,
    trackCheckoutStarted,
    trackCheckoutCompleted,
    identify,
  };

  return (
    <TrackerContext.Provider value={value}>{children}</TrackerContext.Provider>
  );
}

export function useTracker() {
  const context = useContext(TrackerContext);
  if (!context) {
    throw new Error("useTracker must be used within a TrackerProvider");
  }
  return context;
}

Automatic Page View Tracker

With Page Router

// components/page-view-tracker.tsx
"use client";

import { useEffect } from "react";
import { useRouter } from "next/router";
// contextual sdk is global singleton so can be accessed like this
import { trackPageView } from "@getcontextual/shopify-sdk/vanilla";

export function PageViewTracker() {
  const router = useRouter();

  useEffect(() => {
    const handleRouteChange = () => {
      void trackPageView();
    };

    router.events.on("routeChangeComplete", handleRouteChange);

    return () => {
      router.events.off("routeChangeComplete", handleRouteChange);
    };
  }, [router.events]);

  return null;
}

With App Router

"use client";
// contextual sdk is global singleton so can be accessed like this
import { useEffect, Suspense } from "react";
import { usePathname, useSearchParams } from "next/navigation";
import { useTracker } from "./tracker-provider";

function PageViewHandler() {
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const { trackPageView } = useTracker();

  useEffect(() => {
    trackPageView();
  }, [pathname, searchParams, trackPageView]);

  return null;
}

export function AppRouterPageViewTracker() {
  return (
    <Suspense fallback={null}>
      <PageViewHandler />
    </Suspense>
  );
}
// app/layout.tsx

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <TrackerProvider config={{ merchantId: "my-store.myshopify.com" }}>
          <AppRouterPageViewTracker />
          {children}
        </TrackerProvider>
      </body>
    </html>
  );
}

Using Components

"use client";

import { trackProductView } from "@getcontextual/shopify-sdk/vanilla";

export function ProductTracking({
  productVariant,
}: {
  productVariant: ShopifyProductVariant;
}) {
  const hasTracked = useRef(false);

  useEffect(() => {
    if (!hasTracked.current && productVariant) {
      hasTracked.current = true;
      void trackProductView(productVariant);
    }
  }, [productVariant]);

  return null;
}

Using Hooks

// pages/products/[id].tsx

import { useEffect } from "react";
import { trackProductView } from "@getcontextual/shopify-sdk/vanilla";

export default function ProductPage({ product }) {
  useEffect(() => {
    if (product?.variant) {
      void trackProductView(product.variant);
    }
  }, [product]);

  return <div>{product.title}</div>;
}

##W Key Points

  1. Always use 'use client': Any file that imports from @getcontextual/shopify-sdk must have 'use client' at the top
  2. SSR-safe: All tracking functions are SSR-safe and will no-op on the server
  3. Initialize once: Call init() only once, typically in a provider component
  4. Track in useEffect: Always track events inside useEffect to ensure they run on the client-side
  5. Page views: Track page views when route changes (App Router: usePathname/useSearchParams, Pages Router: router.events)

Configuration

HeadlessShopifyConfig

interface HeadlessShopifyConfig {
  merchantId: string; // Required: Your Shopify store domain (e.g., 'store.myshopify.com')
  version?: string; // Optional: SDK version (default: '1.0.0')
  autoFlush?: boolean; // Optional: Auto-flush events (default: true)
  flushInterval?: number; // Optional: Flush interval in milliseconds (default: 100)
  gtmContainerId?: string; // Optional: Google Tag Manager container ID
}

VanillaShopifyConfig

Extends HeadlessShopifyConfig with:

interface VanillaShopifyConfig extends HeadlessShopifyConfig {
  autoTrackPageView: boolean; // Automatically track page views on init
}

TypeScript Support

The package is fully typed. All Shopify types are based on @shopify/web-pixels-extension for consistency.

import type {
  ShopifyProductVariant,
  ShopifyCartLine,
  ShopifyCheckout,
  ShopifyCollection,
  ShopifySearchResult,
  HeadlessShopifyConfig,
} from "@getcontextual/shopify-sdk";

Google Tag Manager Integration

Setup

init({
  merchantId: "your-store.myshopify.com",
  gtmContainerId: "GTM-XXXXXXX", // Your GTM container ID
});

How It Works

  1. Automatic Loading: GTM script loads automatically on tracker initialization
  2. Event Pushing: All events are pushed to window.dataLayer
  3. Event Format: Events follow standard GTM data layer format

Event Structure

Events are pushed to dataLayer as:

{
  event: 'product_viewed',
  event_data: {
    merchant_id: 'your-store.myshopify.com',
    event_id: 'unique-event-id',
    // ... product data, user data, etc.
  }
}

Note: If you don't provide a gtmContainerId, the SDK works perfectly without GTM. Events will only be sent to the Contextual backend.

No additional configuration required - it works out of the box!

API Reference

Vanilla JavaScript Functions

All functions from @getcontextual/shopify-sdk/vanilla:

  • init(config: VanillaShopifyConfig) - Initialize tracker
  • getTracker() - Get tracker instance
  • trackPageView() - Track page view
  • trackProductView(productVariant) - Track product view
  • trackCollectionView(collection) - Track collection view
  • trackAddToCart(cartLine) - Track add to cart
  • trackCheckoutStarted(checkout) - Track checkout started
  • trackCheckoutCompleted(checkout) - Track checkout completed
  • trackSearch(query, results) - Track search
  • identify(userProperties) - Identify user

React Hooks

From @getcontextual/shopify-sdk/react:

  • useTracker() - Access all tracker functions from context

React Components

From @getcontextual/shopify-sdk/react:

  • <TrackerProvider config={config}> - Provider component
  • <ProductTracking productVariant={variant} /> - Track product views
  • <CollectionTracking collection={collection} /> - Track collection views
  • <AddToCartTracking cartLine={cartLine} /> - Track add to cart
  • <CheckoutStartedTracking checkout={checkout} /> - Track checkout started
  • <CheckoutCompletedTracking checkout={checkout} /> - Track checkout completed
  • <IdentifyTracking userProperties={props} /> - Identify user
  • <PageViewTracker pathname={pathname} /> - Track page views
  • <SearchTracking search={search}, searchResult={searchResult}> - Track search results

Examples

Complete Vanilla JS Example

import {
  init,
  trackProductView,
  trackAddToCart,
  identify,
} from "@getcontextual/shopify-sdk/vanilla";

// Initialize
init({
  merchantId: "my-store.myshopify.com",
  autoTrackPageView: true,
  gtmContainerId: "GTM-XXXXXXX",
});

// Product page
function onProductPageLoad(product) {
  trackProductView(product.variant);
}

// Add to cart button
function onAddToCart(cartLine) {
  trackAddToCart(cartLine);
}

// User login
function onUserLogin(user) {
  identify({
    email: user.email,
    firstName: user.firstName,
    lastName: user.lastName,
  });
}

Complete React Example

import {
  TrackerProvider,
  useTracker,
  ProductTracking,
} from "@getcontextual/shopify-sdk/react";

function App() {
  return (
    <TrackerProvider config={{ merchantId: "my-store.myshopify.com" }}>
      <Router>
        <Routes>
          <Route path="/products/:id" element={<ProductPage />} />
          <Route path="/cart" element={<CartPage />} />
        </Routes>
      </Router>
    </TrackerProvider>
  );
}

function ProductPage() {
  const { product } = useLoaderData();
  const { trackAddToCart } = useTracker();

  return (
    <>
      <ProductTracking productVariant={product.variant} />
      <div>
        <h1>{product.title}</h1>
        <button onClick={() => trackAddToCart(product.cartLine)}>
          Add to Cart
        </button>
      </div>
    </>
  );
}

Package Exports

  • @getcontextual/shopify-sdk - Core tracker class and types
  • @getcontextual/shopify-sdk/vanilla - Vanilla JavaScript API
  • @getcontextual/shopify-sdk/react - React hooks and components

Troubleshooting

Events Not Being Tracked

  1. Ensure init() or <TrackerProvider> is called before tracking
  2. Check browser console for initialization warnings
  3. Verify merchantId matches your Shopify store domain
  4. If using SSR, ensure tracking is called in useEffect or after hydration

GTM Events Not Appearing

  1. Verify gtmContainerId is correct
  2. Inspect window.dataLayer in browser console
  3. Use GTM preview mode to see if events are received
  4. Check Network tab for GTM script requests

TypeScript Errors

  1. Ensure TypeScript version is compatible (^5.9.2)
  2. Use the correct import path for your framework
  3. Types are automatically included - no additional setup needed

React Strict Mode

The SDK is React Strict Mode safe. You may see duplicate event tracking in development mode, but this won't happen in production.

License

Licensed under the Apache License, Version 2.0. See LICENSE for details.

Support

For issues, questions, or contributions, please open an issue on the repository.