umami-analytics-react
TypeScript icon, indicating that this package has built-in type declarations

1.0.3 • Public • Published

umami-analytics-react

Integrate Umami analytics in React easily: Use UmamiProvider for setup and useUmami for custom events/session identification. Page view tracking works automatically by default, or leverage the useUmamiView hook for precise control.

NPM lang license

Features

This library wraps Umami's tracking functionality in a React-friendly API, with support for:

  • ✅ Script loading via UmamiProvider

  • 🎯 Custom event tracking and session identification with useUmami

  • 📈 Flexible page view tracking options (automatic or hook-based useUmamiView)

  • 🧠 Enhanced identity payloads (timezone, theme, etc.)

  • 🕒 Queueing events before the script is ready

Installation

npm

In your project, install using NPM:

npm install umami-analytics-react

Usage

1. Setup Provider

Wrap your application (or the relevant part of it) with UmamiProvider. You must provide your websiteId. You can optionally provide the scriptSrc if you are self-hosting Umami at a non-standard location.

// src/main.tsx or src/index.tsx
import ReactDOM from "react-dom/client";
import App from "./App";
import { UmamiProvider } from "umami-analytics-react";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <UmamiProvider
    websiteId="YOUR_UMAMI_WEBSITE_ID"
    // # Optional: If self-hosting or using a different endpoint
    // scriptSrc="https://your-umami-instance.com/script.js"
    // # Optional: Add extra attributes to the script tag
    // scriptAttributes={{ "data-tag": "eu", "data-domains": "example.com,example2.com" }}
  >
    <App />
  </UmamiProvider>
);

2. Tracking Page Views

Umami offers built-in automatic page view tracking. However, for more precise control, especially within Single Page Applications (SPAs), this library provides the useUmamiView hook. Choose the method that best suits your needs.

Method 1: Automatic (via Umami script)

This is the default behavior if you do not disable it. The standard Umami tracker script.js automatically tracks page views based on browser history changes (using the History API).

Details
  • Pros: No extra code needed beyond the UmamiProvider setup. Works well for traditional multi-page websites.
  • Cons: None, unless incompatible with your SPA's routing approach.
  • How to use: Simply use the <UmamiProvider> without setting data-auto-track to false.
// Uses Umami's built-in automatic tracking
<UmamiProvider websiteId="YOUR_UMAMI_WEBSITE_ID">
  <App />
</UmamiProvider>

Method 2: Custom - Automatic via Hook (e.g. using a router)

This method gives you fine-grained control over _when_ a page view is tracked, suitable for SPAs using libraries like React Router. It requires **disabling** the default Umami script auto-tracking.

Details
  • Pros: Reliable tracking aligned with your application's routing logic. Tracks views exactly when your components signal a navigation change. Can track custom event data alongside the view.
  • Cons: Requires adding the useUmamiView hook in your code.
  • How to use:
    1. Disable default tracking by adding scriptAttributes={{ "data-auto-track": false }} to your <UmamiProvider>.
    2. Call useUmamiView in a component that renders across all routes (like your main App or a layout component).
    3. Pass values that change with navigation (e.g., location.pathname, location.search) to its dependency array (viewDependencies).
    4. (Optional) Provide a payload (object or mapper function) as the second argument to track specific event data when the dependencies change. If no payload is provided, it defaults to tracking a standard page view.
// Example using React Router
import { useLocation, BrowserRouter, Routes, Route } from "react-router-dom";
import { useUmamiView, UmamiProvider } from "umami-analytics-react";

// A component rendered within the Router context that has access to location
function LocationTracker() {
  const location = useLocation();

  // Track view whenever pathname or search params change
  useUmamiView([location.pathname, location.search]);

  // Or track only when pathname changes
  // useUmamiView([location.pathname]);

  // Or track a specific event with data when the pathname changes
  // useUmamiView(
  //   [location.pathname], // Dependencies
  //   (props) => ({ ...props, title: "Overwrite title" })
  // );

  // This component doesn't need to render anything itself,
  // or it could be part of your main layout.
  return null;
}

// Your page components
const HomePage = () => <div>Home</div>;
const AboutPage = () => <div>About</div>;

function App() {
  return (
    // *** Disable default tracking ***
    <UmamiProvider
      websiteId="YOUR_UMAMI_WEBSITE_ID"
      scriptAttributes={{ "data-auto-track": false }} // <-- Important!
    >
      <BrowserRouter>
        {/* Place the tracker component inside the Router */}
        <LocationTracker />

        {/* Your usual Routes */}
        <Routes>
          <Route path="/" element={<HomePage />} />
          <Route path="/about" element={<AboutPage />} />
          {/* ... other routes */}
        </Routes>
      </BrowserRouter>
    </UmamiProvider>
  );
}

Method 3: Custom - Manual via Hook (Per Page / Component Mount)

This method allows you to explicitly trigger a page view track when a specific component mounts. It also requires **disabling** the default Umami script auto-tracking.

Details
  • Pros:
    1. Explicit Control: Track views precisely when specific components mount.
    2. Selective Tracking: Useful if you only want to track views for a small subset of pages/components.
    3. Flexible: Can track views/events for UI states not tied directly to route changes (e.g., opening a significant modal). Can include custom data.
  • Cons: Requires adding the useUmamiView hook to every component you want to track individually.
  • How to use:
    1. Disable default tracking by adding scriptAttributes={{ "data-auto-track": false }} to your <UmamiProvider>.
    2. Call useUmamiView without any dependencies inside each component that represents a trackable page or view.
    3. (Optional) Provide a payload (object or mapper function) as the second argument to track specific event data on mount. If no payload is provided, it defaults to tracking a standard page view.
// Example: src/components/ImportantModal.tsx
import { useUmamiView } from "umami-analytics-react";

function ImportantModal({ modalId }: { modalId: string }) {
  // Track view once when this modal component mounts, include modalId
  useUmamiView([], (props) => ({ ...props, eventName: "modal-view", modalId: modalId }));

  // Or track a standard page view on mount
  // useUmamiView();

  return <div>Modal Content...</div>;
}
export default ImportantModal;

// Make sure this component is rendered within the UmamiProvider
// context, and that the provider has data-auto-track set to false.

3. Tracking Custom Events

Use the useUmami hook to get access to the track function.

import { useUmami } from "umami-analytics-react";

function MyComponent() {
  const { track } = useUmami();

  const handleSignup = () => {
    // Track simple event by name
    track("signup-button-click");

    // Track event with a custom payload
    track("newsletter-subscribe", { plan: "premium" });
  };

  // Track using a function (useful for dynamic properties)
  const handleButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
    track((props) => ({
      ...props, // Includes default properties like url, referrer
      event: "button-click",
      buttonId: event.currentTarget.id,
    }));
  };

  return (
    <div>
      <button onClick={handleSignup}>Sign Up</button>
      <button id="main-cta" onClick={handleButtonClick}>
        Main CTA
      </button>
    </div>
  );
}

4. Identifying Sessions

Use the useUmami hook to get access to the identify function. This allows you to associate custom data with the current user"s session.

import { useUmami } from "umami-analytics-react";

function UserProfile() {
  const { identify } = useUmami();

  const handleLogin = (userId: string, role: string) => {
    // Identify the user with custom data
    identify({ userId, role });
  };

  const identifyWithEnhancedData = () => {
    // Identify with custom data AND automatically appended browser/device info
    // (timezone, theme, reduced motion preference, touch device, connection type)
    identify({ customData: "example" }, true);
  };

  const identifyWithSpecificEnhancedData = () => {
    // Identify with custom data AND only specific enhanced info
    identify({ customData: "example" }, ["timezone", "systemTheme"]);
  };

  return (
    <div>
      {/* ... login form ... */}
      <button onClick={() => handleLogin("user-123", "admin")}>Log In</button>
      <button onClick={identifyWithEnhancedData}>Identify (Enhanced)</button>
      <button onClick={identifyWithSpecificEnhancedData}>
        Identify (Specific Enhanced)
      </button>
    </div>
  );
}

Enhanced Identify Properties:

When appendEnhancedPayload is true or an array of keys (default: false), the following properties (if available) can be added:

  • timezone: e.g., "Europe/London"
  • timezoneOffset: e.g., 60
  • ect: Effective connection type, e.g., "4g" ( ? )
  • systemTheme: "light" or "dark"
  • prefersReducedMotion: true or false
  • isTouchDevice: true or false
  • zoomLevel: e.g., 100

5. Manual Script Loading

If you prefer to control exactly when the Umami script loads, set autoLoad={false} on the UmamiProvider and call the register function obtained from useUmami when ready.

import { UmamiProvider, useUmami } from "umami-analytics-react";
import { useState, useEffect } from "react";

function ManualLoadTrigger() {
  const { register } = useUmami();
  const [shouldLoad, setShouldLoad] = useState(false);

  useEffect(() => {
    if (shouldLoad) {
      console.log("Registering Umami script...");
      register(); // You can optionally pass config here too
    }
  }, [shouldLoad, register]);

  return (
    <button onClick={() => setShouldLoad(true)} disabled={shouldLoad}>
      Load Umami Analytics
    </button>
  );
}

function App() {
  return (
    <UmamiProvider websiteId="YOUR_UMAMI_WEBSITE_ID" autoLoad={false}>
      {/* ... rest of your app */}
      <ManualLoadTrigger />
    </UmamiProvider>
  );
}

API

<UmamiProvider />

The provider component that enables Umami tracking within its children.

Props:

  • websiteId: string: (Required) Your Umami website tracking ID.

  • scriptSrc?: string: URL of the Umami tracker script. Defaults to https://cloud.umami.is/script.js.

  • scriptAttributes?: object: Additional attributes to add to the script tag (e.g., data-tag, data-domains). See Umami Docs (tracker configuration). (data-website-id is handled internally).

  • autoLoad?: boolean: Whether to load the script automatically on mount. Defaults to true.

  • children: React.ReactNode: Your application components.

useUmami()

Hook to access the core Umami tracking functions and context. See Umami Docs (tracker functions). Must be used within an <UmamiProvider />.

Returns: object

  • track: (eventNameOrPayload, payload?) => void: Tracks a custom event.

  • identify: (payloadOrUniqueId, payload?) => void: Associates data with the current session. appendEnhancedPayload can be true to add all enhanced data, or an array of specific keys ('timezone', 'systemTheme', etc.).

  • view: () => void: Tracks a page view. Usually called automatically by useUmamiView. (Internally calls track()).

  • register: (config?) => void: Manually triggers the loading of the Umami script. Can optionally override provider config (websiteId, scriptSrc, scriptAttributes). Only needed if autoLoad={false}.

  • umamiRef: RefObject<Umami | null>: A React ref containing the loaded window.umami object, or null if not loaded yet. Use with caution.

useUmamiView(viewDependencies?, payload?)

Hook to simplify tracking events (typically page views) based on dependency changes or component mount. Essentially wraps a call to track() within a useEffect. Requires data-auto-track="false" on the provider if used for page view tracking to avoid duplicates.

Arguments:

  • viewDependencies: ReadonlyArray<unknown>: (Optional) A dependency array. When any value in this array changes, the effect runs and track(payload) is called. If omitted or empty ([]), the effect runs only once on component mount. Defaults to [].

  • payload?: (Optional) The payload to pass to the underlying track function when the effect runs. This can be:

    • An event data object (e.g., { eventName: 'signup', step: 1 }).
    • A mapper function that receives default properties and returns an event data object.
    • If omitted, a standard page view is tracked (equivalent to calling track() with no arguments).

generateEnhancedIdentity()

Helper function which generates some basic additional enhanced payload for the identify method. Has the ability to filter which values to include ('timezone', 'systemTheme', etc.). Example: identify("john@sampleemail.com", { ...generateEnhancedIdentity(), myOtherCustom: "blue" })

License

Distributed under the ISC License. See LICENSE for more information.

Package Sidebar

Install

npm i umami-analytics-react

Weekly Downloads

135

Version

1.0.3

License

ISC

Unpacked Size

29.3 kB

Total Files

33

Last publish

Collaborators

  • deswolf