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

@thg-altitude/analytics

v0.1.8

Published

Analytics package for Astro, Next.js, and React Native

Downloads

2,975

Readme

A cross-platform analytics package for Astro, Next.js, and React Native applications.

Features

  • 🔄 Cross-Platform: Works with Astro, Next.js, and React Native
  • 🔍 Type-Safe: Built with TypeScript for robust type checking
  • Schema Validation: Uses Zod for runtime schema validation
  • 🌐 Client & Server: Supports both client-side and server-side tracking
  • 📊 Google Analytics Events: Pre-defined schemas for common GA4 events

Installation

# Install the package
npm install @thg-altitude/analytics
# or
yarn add @thg-altitude/analytics
# or
pnpm add @thg-altitude/analytics

Usage

Next.js

// _app.tsx or layout.tsx
import { ThgAnalyticsScript } from '@thg-altitude/analytics/next';

// For App Router (in layout.tsx)
export default function RootLayout({ children }) {
  return (
    <html>
      <head>
        <ThgAnalyticsScript />
      </head>
      <body>{children}</body>
    </html>
  );
}

// For Pages Router (in _app.tsx)
function MyApp({ Component, pageProps }) {
  return (
    <>
      <ThgAnalyticsScript />
      <Component {...pageProps} />
    </>
  );
}

// Using the SDK on the client side
import { createThgAnalytics } from '@thg-altitude/analytics/next';

// In a component or page
useEffect(() => {
  createThgAnalytics({
    debug: true,
    server: {
      // Optional server-side endpoint
      endpoint: 'https://analytics-api.example.com/collect'
    }
  });
  
  // Track page view
  window.thgAnalytics.instance.userDetails({
    visitorLoginState: getCustomerName() ? 'LOGGED_IN' : 'LOGGED_OUT',
    visitorId: getCustomerId() || 'unknown',
    visitorEmailAddress: getCustomerEmail() || 'unknown'
  });
}, []);

Astro

// astro.config.mjs
import { defineConfig } from 'astro/config';
import thgAnalytics from '@thg-altitude/analytics/astro';

export default defineConfig({
  integrations: [
    thgAnalytics({
      debug: true
    })
  ]
});
<!-- In an Astro component such as the Layout or ClientInit file -->
<script>
  import {
        createClientAnalytics,
        processStoredEvents
  } from '@thg-altitude/analytics/astro';

  // Initialize analytics SDK on the window object
  createClientAnalytics();
  
  window.thgAnalytics.instance.userDetails({
    visitorLoginState: getCustomerName() ? 'LOGGED_IN' : 'LOGGED_OUT',
    visitorId: getCustomerId() || 'unknown',
    visitorEmailAddress: getCustomerEmail() || 'unknown'
  });

  // Proccess stored events that were sent before the SDK was initialized
  processStoredEvents();
</script>

Race Conditions

On Astro pages SDK functions aren't initialized on the window.thgAnalytics.instance before the page tries to invoke them. To handle this race condition, add events events to window.thgAltitude.eventStore. These stored events are then processed when the SDK is fully initialized using processStoredEvents().

window?.thgAnalytics?.instance?.viewItem({
            currency: window.sessionSettings.currency,
            value: price * quantity,
            items: [
                {
                    item_id,
                    item_name,
                    item_brand,
                    price,
                    quantity,
                    item_category,
                    discount
                }
            ]
        }) ||
            window.thgAnalytics.eventStore.push({
                name: 'viewItem',
                event: {
                    currency: window.sessionSettings.currency,
                    value: price * quantity,
                    items: [
                        {
                            item_id,
                            item_name,
                            item_brand,
                            price,
                            quantity,
                            item_category,
                            discount
                        }
                    ]
                }
            });

Those events stored in the event store will then be handled by the processStoredEvents function called in the Layout/ClientInit file ensuring no events are lost during page load, even if they're triggered before the SDK is fully initialized.

React Native

// App.tsx
import { createThgAnalytics } from '@thg-altitude/analytics/react-native';

// Initialize analytics
const analytics = createThgAnalytics({
  debug: true,
  server: {
    endpoint: 'https://analytics-api.example.com/collect'
  }
});

// Track events
analytics.userDetails({
    visitorLoginState: getCustomerName() ? 'LOGGED_IN' : 'LOGGED_OUT',
    visitorId: getCustomerId() || 'unknown',
    visitorEmailAddress: getCustomerEmail() || 'unknown'
  });

Available Events

THG Analytics provides typed methods for common Google Analytics 4 events, the schemas for events can be found here.

E-commerce Events

  • viewItem: Track product views
  • viewItemList: Track product list views
  • selectItem: Track item selection from a list
  • addToCart: Track add to cart events
  • removeFromCart: Track remove from cart events
  • beginCheckout: Track checkout initiation
  • addToWishlist: Track wishlist additions
  • wishlistRemoved: Track wishlist removals
  • applyCouponSuccess: Track successful coupon applications
  • applyCouponFail: Track failed coupon applications
  • selectFreeGift: Track free gift selection
  • removeFreeGift: Track free gift removals
  • viewFreeGift: Track free gift views
  • viewPromotion: Track promotion views
  • selectPromotion: Track promotion clicks
  • filterAdded: Track filter applications
  • readMoreClick: Track read more interactions
  • userDetails: Track user state changes
  • logout: Track user logouts
  • signUp: Track user registrations
  • pageNotFound: Track 404 errors
  • search: Track search events
  • reviewCreated: Track product review creations
  • reviewViewed : Track product review views
  • reviewVoted: Track votes on product reviews
  • reviewReported: Track reports on product reviews

Schema Validation

THG Analytics uses Zod for schema validation, providing helpful warnings when event data doesn't match the expected schema:

// This will work and send the event
analytics.userDetails({
    visitorLoginState: getCustomerName() ? 'LOGGED_IN' : 'LOGGED_OUT',
    visitorId: getCustomerId() || 'unknown',
    visitorEmailAddress: getCustomerEmail() || 'unknown'
  });

// This will log a warning and not send the event
analytics.userDetails({
    visitorLoginState: getCustomerName() ? 'LOGGED_IN' : 'LOGGED_OUT',
    visitorId: getCustomerId() || 'unknown',
    // visitorEmailAddress missing - will not send event
  });

License

MIT