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.
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
In your project, install using NPM:
npm install umami-analytics-react
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>
);
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.
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 settingdata-auto-track
tofalse
.
// Uses Umami's built-in automatic tracking
<UmamiProvider websiteId="YOUR_UMAMI_WEBSITE_ID">
<App />
</UmamiProvider>
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:
- Disable default tracking by adding
scriptAttributes={{ "data-auto-track": false }}
to your<UmamiProvider>
. - Call
useUmamiView
in a component that renders across all routes (like your mainApp
or a layout component). - Pass values that change with navigation (e.g.,
location.pathname
,location.search
) to its dependency array (viewDependencies
). - (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.
- Disable default tracking by adding
// 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>
);
}
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:
- Explicit Control: Track views precisely when specific components mount.
- Selective Tracking: Useful if you only want to track views for a small subset of pages/components.
- 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:
- Disable default tracking by adding
scriptAttributes={{ "data-auto-track": false }}
to your<UmamiProvider>
. - Call
useUmamiView
without any dependencies inside each component that represents a trackable page or view. - (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.
- Disable default tracking by adding
// 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.
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>
);
}
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
orfalse
- isTouchDevice:
true
orfalse
- zoomLevel: e.g.,
100
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>
);
}
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 tohttps://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 totrue
. -
children: React.ReactNode
: Your application components.
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 betrue
to add all enhanced data, or an array of specific keys ('timezone'
,'systemTheme'
, etc.). -
view: () => void
: Tracks a page view. Usually called automatically byuseUmamiView
. (Internally callstrack()
). -
register: (config?) => void
: Manually triggers the loading of the Umami script. Can optionally override provider config (websiteId
,scriptSrc
,scriptAttributes
). Only needed ifautoLoad={false}
. -
umamiRef: RefObject<Umami | null>
: A React ref containing the loadedwindow.umami
object, ornull
if not loaded yet. Use with caution.
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 andtrack(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).
- An event data object (e.g.,
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" })
Distributed under the ISC License. See LICENSE for more information.