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

nextjs-trackkit

v1.1.1

Published

Simple GTM dataLayer tracking for Next.js components using typed helpers and data attributes.

Readme

nextjs-trackkit

Simple GTM tracking for Next.js projects.

This package helps teams track component views, clicks, controls, videos, and completion events with a consistent window.dataLayer schema. For most components, developers can either use ready-made React helpers or add data-track-* attributes.

Install

npm install nextjs-trackkit

Choose Your Tracking Method

TrackKit supports two easy ways to track events. Both send the same consistent window.dataLayer event schema, so you can choose the style that fits your app.

Way 1: React Components And Hooks

Best for most Next.js apps and design systems.

  • Define tracking context once with TrackKitSection
  • Use TrackKitLink and TrackKitButton for reusable CTAs
  • Use useTrackKitCta() when you already have your own button, link, or card component
  • Best when you want less repeated data-track-* markup

Way 2: Data Attributes

Best when you want tracking directly in markup.

  • Add data-track-view for viewport events
  • Add data-track-click for click and control events
  • Put shared content details on a parent section with data-track-context
  • Best when you want tracking without importing React tracking components

Manual helper functions are also available for advanced cases such as videos, completion events, and fully custom events.

Next.js Setup

Wrap your app in the client provider.

// app/providers.tsx
"use client";

import { GtmTrackingProvider } from "nextjs-trackkit/react";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <GtmTrackingProvider gtmId={process.env.NEXT_PUBLIC_GTM_ID}>
      {children}
    </GtmTrackingProvider>
  );
}

Use it in your root layout.

// app/layout.tsx
import { Providers } from "./providers";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

The provider:

  • creates window.dataLayer
  • sets default GTM consent to denied
  • loads GTM when gtmId is provided
  • enables data-attribute click and viewport tracking

Way 1: React Components And Hooks

Use the React API when you want less boilerplate in reusable components. Define shared content context once at the section level, then use tracked buttons and links inside it.

"use client";

import {
  TrackKitButton,
  TrackKitLink,
  TrackKitSection,
} from "nextjs-trackkit/react";

export function Hero() {
  return (
    <TrackKitSection
      view
      content={{
        name: "Hero",
        type: "Content",
        variant: "Primary",
        media: "Image",
      }}
      customParameters={{
        campaign_id: "launch",
      }}
    >
      <h1>Modern tracking for Next.js</h1>

      <TrackKitLink href="/setup" cta={{ type: "Button" }}>
        Start setup
      </TrackKitLink>

      <TrackKitButton cta={{ type: "Button" }} eventType="control">
        Open preview
      </TrackKitButton>
    </TrackKitSection>
  );
}

TrackKitSection provides inherited content, customParameters, and details to child CTAs. The view prop adds the same viewport tracking attributes used by the declarative API, so the existing observer fires content_in_viewport when the section enters the viewport.

TrackKitLink pushes content_cta_click. TrackKitButton pushes content_control_interaction by default, and can push content_cta_click with eventType="cta".

Component-Level CTA Hook

Use useTrackKitCta() when your design system already owns the rendered button, card, or link element.

"use client";

import { useTrackKitCta } from "nextjs-trackkit/react";

export function ProductCardLink() {
  const { track, trackingProps } = useTrackKitCta({
    cta: {
      type: "Card",
      text: "View product",
    },
    href: "/products/trackkit",
  });

  return (
    <a
      href="/products/trackkit"
      {...trackingProps}
      onClick={() => track("View product")}
    >
      View product
    </a>
  );
}

The hook reads inherited context from TrackKitSection or TrackKitProvider.defaults. It returns:

  • track(label) to push the event manually
  • trackingProps with useful data-track-* metadata for inspection or optional declarative fallback

Set enableDeclarativeFallback: true only when you want the returned props to include data-track-click. Do not call track() and enable declarative fallback for the same interaction unless you intentionally want two events.

Provider Defaults

Use provider defaults for values shared across the whole app.

<TrackKitProvider
  gtmId={process.env.NEXT_PUBLIC_GTM_ID}
  defaults={{
    content: {
      type: "Content",
      media: "Text",
    },
    customParameters: {
      site_area: "marketing",
    },
  }}
>
  {children}
</TrackKitProvider>

Way 2: Data Attributes

The original data-track-* API is still fully supported. Use it when you want tracking without importing React components into each UI file.

Track Component Views With Data Attributes

Add data-track-view to the component wrapper. The event fires once by default when the element enters the viewport.

<section
  data-track-view
  data-track-content-name="Hero"
  data-track-content-type="Content"
  data-track-content-variant="Primary"
  data-track-content-media="Image"
>
  <h1>Welcome</h1>
</section>

This pushes:

{
  event: "content_in_viewport",
  parameters: {
    content: {
      name: "Hero",
      type: "Content",
      variant: "Primary",
      media: "Image",
      page: "/current-page"
    }
  }
}

Track Clicks With Data Attributes

Add data-track-click to links, buttons, or CTAs.

<a
  href="/products"
  data-track-click
  data-track-label="Explore products"
  data-track-cta-type="Button"
>
  Explore products
</a>

This pushes content_cta_click.

Inherit Context From Parent Data Attributes

Put shared tracking values on the organism or section. Child atoms only need the click trigger and label.

<section
  data-track-context
  data-track-view
  data-track-content-name="Bento Grid"
  data-track-content-type="Content"
  data-track-content-variant="Featured"
  data-track-content-media="Image"
  data-track-position="2"
  data-track-cardinality="4"
>
  <a
    href="/learn-more"
    data-track-click
    data-track-label="Learn more"
    data-track-cta-type="Button"
  >
    Learn more
  </a>
</section>

Track Controls With Data Attributes

Use data-track-event-type="control" for tabs, accordions, filters, carousel controls, toggles, radio buttons, and similar UI controls.

<button
  data-track-click
  data-track-event-type="control"
  data-track-cta-type="Button"
  data-track-label="Overview"
  data-track-position="1"
>
  Overview
</button>

This pushes content_control_interaction.

Control events use this action shape:

{
  event: "content_control_interaction",
  parameters: {
    content: {
      name: "Tracking Console",
      type: "Content",
      variant: "Diagnostics",
      media: "Text",
      page: "/"
    },
    action: {
      type: "Button",
      text: "Overview"
    }
  }
}

action.text is always the visible button/link/card label, or data-track-label when provided. action.type should describe the CTA surface: Button, Text, or Card.

action.target is only sent for download CTAs. Its value is always Download, and download CTAs also force content.media to File.

<a
  href="/files/annual-report.pdf"
  download
  data-track-click
  data-track-event-type="control"
  data-track-cta-type="Button"
  data-track-cta-target="Download"
  data-track-label="Download annual report"
>
  Download annual report
</a>

This pushes:

{
  event: "content_control_interaction",
  parameters: {
    content: {
      name: "Tracking Console",
      type: "Content",
      variant: "Diagnostics",
      media: "File",
      page: "/"
    },
    action: {
      type: "Button",
      text: "Download annual report",
      target: "Download"
    }
  }
}

Data Attribute Reference

Use these on wrapper components:

  • data-track-context
  • data-track-content-name
  • data-track-content-type
  • data-track-content-variant
  • data-track-content-layout
  • data-track-content-label
  • data-track-content-media
  • data-track-content-page
  • data-track-content-region
  • data-track-content-display
  • data-track-position
  • data-track-cardinality

Use these on tracked elements:

  • data-track-view
  • data-track-click
  • data-track-event-type="cta"
  • data-track-event-type="control"
  • data-track-label
  • data-track-destination
  • data-track-target="_self"
  • data-track-target="_blank"
  • data-track-once="true"
  • data-track-once="false"
  • data-track-threshold="0.3"

CTA-specific attributes:

  • data-track-cta-type
  • data-track-cta-media
  • data-track-cta-target="Download"

For content_control_interaction, use data-track-cta-type for action.type and data-track-label for action.text.

Advanced: Manual Tracking

Use manual helpers for components that already have custom logic, video events, completion events, or custom event needs that do not map to a simple CTA or viewport interaction.

import {
  trackActionCompletion,
  trackContentControlInteraction,
  trackContentCtaClick,
  trackContentInViewport,
  trackCustomEvent,
  trackVideoEngagement,
  trackVideoProgress,
} from "nextjs-trackkit";

trackContentCtaClick({
  content: {
    name: "Hero",
    type: "Content",
    variant: "Primary",
    media: "Image",
  },
  cta: {
    type: "Button",
    text: "Explore products",
  },
  navigateToUrl: "/products",
});

Available event helpers:

  • trackContentInViewport() pushes content_in_viewport
  • trackContentCtaClick() pushes content_cta_click
  • trackContentControlInteraction() pushes content_control_interaction
  • trackVideoEngagement() pushes video_engagement
  • trackVideoProgress() pushes video_progress
  • trackActionCompletion() pushes action_completion
  • trackCustomEvent() pushes any custom event name and parameters

Custom Events And Parameters

Use trackCustomEvent() when you need an event outside the predefined schema. The package sends your event name and parameters directly to window.dataLayer.

import { trackCustomEvent } from "nextjs-trackkit";

trackCustomEvent({
  event: "signup_step_completed",
  parameters: {
    flow_name: "Onboarding",
    step_name: "Choose plan",
    step_number: 2,
    plan_type: "Starter",
  },
});

This pushes:

{
  event: "signup_step_completed",
  parameters: {
    flow_name: "Onboarding",
    step_name: "Choose plan",
    step_number: 2,
    plan_type: "Starter"
  }
}

You can also add extra parameters to predefined event helpers with customParameters. Custom parameters are merged into the top-level parameters object. Predefined fields such as content, cta, action, details, video, and response keep priority if a custom key overlaps.

trackContentCtaClick({
  content: {
    name: "Pricing Hero",
    type: "Marketing Section",
    variant: "Primary",
    media: "Text",
  },
  cta: {
    type: "Button",
    text: "Start free trial",
  },
  navigateToUrl: "/signup",
  customParameters: {
    campaign_id: "summer_launch",
    audience_segment: "developers",
    experiment_id: "pricing_cta_v2",
  },
});

This pushes content_cta_click with the normal content and cta objects, plus:

{
  campaign_id: "summer_launch",
  audience_segment: "developers",
  experiment_id: "pricing_cta_v2"
}

GTM Setup

Create Custom Event triggers for:

  • content_in_viewport
  • content_cta_click
  • content_control_interaction
  • video_engagement
  • video_progress
  • action_completion
  • any custom event names you send with trackCustomEvent()

Create Data Layer Variables for the fields you need:

  • parameters.content.name
  • parameters.content.type
  • parameters.content.variant
  • parameters.content.media
  • parameters.content.page
  • parameters.content.region
  • parameters.cta.type
  • parameters.cta.text
  • parameters.cta.url
  • parameters.cta.destination
  • parameters.action.type
  • parameters.action.text
  • parameters.action.target
  • parameters.action.position
  • parameters.details.position
  • parameters.details.cardinality
  • parameters.video.action
  • parameters.video.title
  • parameters.videoProgress.percentage
  • parameters.response.status
  • any custom parameter keys you send, such as parameters.campaign_id

Map those variables into GA4 event parameters on the matching GTM tags.

Consent

By default the provider sets GTM consent to denied. After your consent manager gets approval, update consent:

import { updateGtmConsent } from "nextjs-trackkit";

updateGtmConsent({
  analytics_storage: "granted",
  ad_storage: "granted",
});

Avoid Duplicate Events

For one component interaction, use one tracking path only:

  • React components/hooks with manual track() calls
  • Data attributes with automatic delegated tracking
  • Manual helper functions

Do not combine multiple paths for the same click or view unless you intentionally want more than one event.


Made with ❤️ for Next.js developers.


👤 Author

Neetesh Keshari [AKQA]