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

@uniqueweb/shopify-analytics

v0.0.3

Published

Nuxt module — Shopify Analytics integration via Monorail

Downloads

82

Readme

@uniqueweb/shopify-analytics

npm version npm downloads License Nuxt

Nuxt module for tracking Shopify analytics events via the Monorail API, inspired by Shopify's Hydrogen framework.

Features

  • Page view tracking — automatic and manual page view events
  • Product view tracking — track product impressions
  • Collection view tracking — track collection page views
  • Search tracking — track search queries
  • Cart tracking — auto-tracking via useCartAnalytics + manual cart view events
  • Cookie management — manages _shopify_y / _shopify_s session cookies
  • Pub/Sub system — subscribe to any analytics event
  • Monorail API — sends data to Shopify's analytics endpoint

Setup

npm install @uniqueweb/shopify-analytics

Add the module to nuxt.config.ts:

export default defineNuxtConfig({
  modules: ['@uniqueweb/shopify-analytics'],
})

Configuration

Environment Variables

NUXT_PUBLIC_SHOPIFY_ANALYTICS_DOMAIN=your-store.myshopify.com
NUXT_PUBLIC_SHOPIFY_ANALYTICS_SHOP_ID=gid://shopify/Shop/12345678
NUXT_PUBLIC_SHOPIFY_ANALYTICS_CHECKOUT_DOMAIN=checkout.your-store.com
NUXT_PUBLIC_SHOPIFY_ANALYTICS_HYDROGEN_SUBCHANNEL_ID=your-subchannel-id

| Variable | Required | Description | |---|---|---| | NUXT_PUBLIC_SHOPIFY_ANALYTICS_DOMAIN | Yes | Shopify store domain (without https://), used for the Monorail endpoint | | NUXT_PUBLIC_SHOPIFY_ANALYTICS_SHOP_ID | Yes | Shopify shop GID (gid://shopify/Shop/...) | | NUXT_PUBLIC_SHOPIFY_ANALYTICS_CHECKOUT_DOMAIN | No | Checkout domain — used to calculate the common parent domain for cookie sharing between storefront and checkout | | NUXT_PUBLIC_SHOPIFY_ANALYTICS_HYDROGEN_SUBCHANNEL_ID | No | Hydrogen subchannel ID |

Initialization

The module is split into three parts:

1. Plugin (automatic) — runs on app start, registers all Monorail event handlers via subscribe().

2. app.vue — called once after localization is available. Sets cookies and shop context via watchEffect so changes to consent or locale are reactive. Also wires up cart auto-tracking.

<!-- app.vue -->
<script setup lang="ts">
const shopifyShopStore = useShopifyShopStore()
const shopifyCartStore = useShopifyCartStore()

await shopifyShopStore.getLocalization()

if (import.meta.client) {
  const { setShop } = useShopifyAnalytics()
  const { public: { shopifyAnalytics } } = useRuntimeConfig()

  watchEffect(() => {
    // TODO: replace with reactive consent value from your CMP
    const hasConsent = true

    useShopifyCookies({
      hasUserConsent: hasConsent,
      checkoutDomain: shopifyAnalytics.checkoutDomain,
    })

    if (hasConsent) {
      setShop({
        shopId: shopifyAnalytics.shopId,
        currency: shopifyShopStore.buyerCurrencyCode ?? 'EUR',
        acceptedLanguage: shopifyShopStore.buyerLanguageCode ?? 'DE',
        hydrogenSubchannelId: shopifyAnalytics.hydrogenSubchannelId,
      })
    }
    else {
      setShop(null)
    }
  })

  useCartAnalytics(shopifyCartStore)
}
</script>

setShop() and useShopifyCookies() are wrapped in watchEffect so they react to consent changes and locale updates automatically. useCartAnalytics() is called once — it sets up an internal watch on the cart store.

Usage

In all publish() calls, pass shop: getShop() instead of a hardcoded shop object:

<script setup lang="ts">
const { publish, AnalyticsEvent, getShop } = useShopifyAnalytics()

publish(AnalyticsEvent.PAGE_VIEWED, {
  url: window.location.href,
  shop: getShop(),
})
</script>

Product View Tracking

<script setup lang="ts">
const { publish, AnalyticsEvent, getShop } = useShopifyAnalytics()

onMounted(() => {
  publish(AnalyticsEvent.PRODUCT_VIEWED, {
    url: window.location.href,
    shop: getShop(),
    products: [
      {
        id: product.value.id,
        variantId: variant.value.id,
        title: product.value.title,
        variantTitle: variant.value.title,
        vendor: product.value.vendor,
        price: variant.value.price.amount,
        quantity: 1,
      },
    ],
  })
})
</script>

Collection View Tracking

<script setup lang="ts">
const { publish, AnalyticsEvent, getShop } = useShopifyAnalytics()

onMounted(() => {
  publish(AnalyticsEvent.COLLECTION_VIEWED, {
    url: window.location.href,
    shop: getShop(),
    collection: {
      id: collection.value.id,
      handle: collection.value.handle,
    },
  })
})
</script>

Search Tracking

<script setup lang="ts">
const { publish, AnalyticsEvent, getShop } = useShopifyAnalytics()

function handleSearch(searchTerm: string) {
  publish(AnalyticsEvent.SEARCH_VIEWED, {
    url: window.location.href,
    shop: getShop(),
    searchTerm,
  })
}
</script>

Cart View Tracking

Publish manually when the cart is opened (e.g. in an aside/drawer component):

<script setup lang="ts">
const { publish, AnalyticsEvent, getShop } = useShopifyAnalytics()
const shopifyCartStore = useShopifyCartStore()

publish(AnalyticsEvent.CART_VIEWED, {
  url: window.location.href,
  shop: getShop(),
  cart: shopifyCartStore.cart ?? null,
})
</script>

Add to Cart / Remove from Cart Tracking

These events are tracked automatically by useCartAnalytics() (initialized in app.vue). It watches the cart store and compares lines between updates to detect additions and removals — including quantity changes.

No manual publish() call is needed for cart line events.

Custom Event Subscribers

// plugins/custom-analytics.client.ts
export default defineNuxtPlugin(() => {
  const { subscribe, AnalyticsEvent } = useShopifyAnalytics()

  subscribe(AnalyticsEvent.PRODUCT_VIEWED, (payload) => {
    if (window.gtag) {
      window.gtag('event', 'view_item', {
        items: payload.products.map((p) => ({
          item_id: p.id,
          item_name: p.title,
          price: p.price,
        })),
      })
    }
  })

  subscribe(AnalyticsEvent.PRODUCT_ADD_TO_CART, (payload) => {
    if (window.fbq) {
      window.fbq('track', 'AddToCart', {
        content_ids: [payload.currentLine.merchandise.id],
        content_type: 'product',
      })
    }
  })
})

API Reference

useShopifyAnalytics()

  • publish<T>(event, payload) — Publish an analytics event
  • subscribe<T>(event, callback) — Subscribe to an event (returns an unsubscribe function)
  • setShop(shop | null) — Set or clear shop configuration (call in app.vue)
  • getShop() — Get current shop configuration (use in publish() calls)
  • canTrack() — Check if tracking is allowed
  • AnalyticsEvent — Enum of all event names

All methods are no-ops on the server (SSR-safe).

useCartAnalytics(cartStore)

Watches a Pinia cart store for changes and automatically publishes PRODUCT_ADD_TO_CART / PRODUCT_REMOVED_FROM_CART events. Uses localStorage to deduplicate events across page reloads.

// Call once in app.vue, client-only
useCartAnalytics(shopifyCartStore)

useShopifyCookies(options?)

Manages _shopify_y (1-year user token) and _shopify_s (30-min session token) cookies required by Shopify's Live View and analytics.

useShopifyCookies({
  hasUserConsent: true,        // removes cookies if false
  domain: 'example.com',       // optional, defaults to window.location.host
  checkoutDomain: 'checkout.example.com', // optional, without https://
})

checkoutDomain calculates the common parent domain between the storefront and the checkout subdomain and sets the cookie there, so it is accessible on both. Example:

| window.location.host | checkoutDomain | Cookie domain | |---|---|---| | store.com | checkout.store.com | .store.com | | localhost:3000 | checkout.store.com | (no domain attr) |

Event Types

| Event | Trigger | |---|---| | AnalyticsEvent.PAGE_VIEWED | Manual — call on every page | | AnalyticsEvent.PRODUCT_VIEWED | Manual — call on product page | | AnalyticsEvent.COLLECTION_VIEWED | Manual — call on collection page | | AnalyticsEvent.SEARCH_VIEWED | Manual — call on search | | AnalyticsEvent.CART_VIEWED | Manual — call when cart opens | | AnalyticsEvent.PRODUCT_ADD_TO_CART | Automatic via useCartAnalytics | | AnalyticsEvent.PRODUCT_REMOVED_FROM_CART | Automatic via useCartAnalytics |

How It Works

  1. Plugin registers all Monorail event handlers via subscribe() and marks the analytics system as ready
  2. useShopifyCookies() sets _shopify_y / _shopify_s cookies, wrapped in watchEffect for consent reactivity
  3. setShop() provides shop context (id, currency, language) used in every event payload, also inside watchEffect
  4. useCartAnalytics() watches the cart store; on each update it diffs the cart lines and publishes add/remove events
  5. Pub/Sub queues events until the plugin is ready, then flushes automatically
  6. Monorail events are sent to https://{domain}/.well-known/shopify/monorail/unstable/produce_batch

Local development

# Install dependencies
npm install

# Generate type stubs
npm run dev:prepare

# Develop with the playground
npm run dev

# Build the playground
npm run dev:build

# Run ESLint
npm run lint

# Release new version
npm run release

Credits

Inspired by and based on the shopify-analytics module from pixelastronauts/nitrogen. Adapted and modified for this project — thank you for the inspiration!

License

MIT