A lightweight, privacy-focused React component for integrating Umami Analytics into your website. Umami is an open-source, privacy-friendly alternative to Google Analytics that helps you understand your website's traffic without compromising user privacy.
- 🚀 Easy integration with props or environment variables
- 🔒 Privacy-focused analytics
- ⚡ Lazy loading support
- 🐛 Debug mode for development
- 📦 Zero runtime dependencies
- 🔍 Full TypeScript support
- 🎯 Custom event tracking hook
- 📊 Manual pageview tracking with UTM support
- 🔄 Async UTM parameter fetching
- 🌐 Custom domain support
- ⚙️ Configurable script attributes
- ⚛️ React 18 & 19 Support - Compatible with both React 18.2+ and React 19
- React: 18.2+ or 19.0+
- Node.js: 16.0+
The package is available on both NPM and GitHub Packages:
pnpm add @danielgtmn/umami-react# First, configure npm to use GitHub Packages for @danielgtmn scopeecho"@danielgtmn:registry=https://npm.pkg.github.com">> .npmrc
# Then install
pnpm add @danielgtmn/umami-reactimportUmamiAnalyticsfrom'@danielgtmn/umami-react';functionApp(){return(<div><UmamiAnalyticsurl="https://analytics.example.com"websiteId="your-website-id"/>{/* Your app content */}</div>);}Create a .env file:
UMAMI_URL=https://analytics.example.comUMAMI_ID=your-website-idUMAMI_DEBUG=falseUMAMI_LAZY_LOAD=trueThen use the component:
importUmamiAnalyticsfrom'@danielgtmn/umami-react';functionApp(){return(<div><UmamiAnalytics/>{/* Your app content */}</div>);}| Prop | Type | Description | Default |
|---|---|---|---|
url | string | Your Umami instance URL | UMAMI_URL env var |
websiteId | string | Your website tracking ID | UMAMI_ID env var |
debug | boolean | Enable debug logging | false |
lazyLoad | boolean | Enable lazy loading | false |
onlyInProduction | boolean | Only load in production | true |
domains | string[] | Custom domains for tracking | undefined |
scriptAttributes | Record<string, string> | Additional script attributes | undefined |
| Variable | Type | Description | Default |
|---|---|---|---|
UMAMI_URL | string | Your Umami instance URL | "" |
UMAMI_ID | string | Your website tracking ID | "" |
UMAMI_DEBUG | string | Enable debug logging | "false" |
UMAMI_LAZY_LOAD | string | Enable lazy loading | "false" |
Enable lazy loading to improve initial page load performance:
<UmamiAnalyticsurl="https://analytics.example.com"websiteId="your-website-id"lazyLoad={true}/>Enable debug mode for development:
<UmamiAnalyticsurl="https://analytics.example.com"websiteId="your-website-id"debug={true}/>Track only specific domains:
<UmamiAnalyticsurl="https://analytics.example.com"websiteId="your-website-id"domains={['example.com','app.example.com']}/>Add custom attributes to the script tag:
<UmamiAnalyticsurl="https://analytics.example.com"websiteId="your-website-id"scriptAttributes={{'data-cache': 'true','data-host-url': 'https://custom-host.com'}}/>Use the useUmami hook for custom event tracking:
import{useUmami}from'@danielgtmn/umami-react';functionMyComponent(){const{ track }=useUmami();consthandleClick=()=>{track('button-click',{button: 'header-cta'});};return(<buttononClick={handleClick}>
Click me!
</button>);}The useUmami hook provides comprehensive pageview tracking capabilities, perfect for scenarios where you need to disable auto-tracking and manually control pageview events with custom UTM parameters.
Note: This library correctly integrates with Umami's official tracking API. Pageviews are tracked using Umami's standard
umami.track()method without custom event names.
import{useUmami}from'@danielgtmn/umami-react';functionMyComponent(){const{ trackPageview }=useUmami();consthandlePageview=()=>{trackPageview({url: '/custom-page',title: 'Custom Page Title',referrer: document.referrer,});};return(<buttononClick={handlePageview}>
Track Pageview
</button>);}import{useUmami}from'@danielgtmn/umami-react';functionMyComponent(){const{ trackPageviewWithUTM }=useUmami();consthandleUTMPageview=()=>{trackPageviewWithUTM({utm_source: 'newsletter',utm_medium: 'email',utm_campaign: 'spring-sale',utm_term: 'discount',utm_content: 'header-link',});};return(<buttononClick={handleUTMPageview}>
Track UTM Pageview
</button>);}For scenarios where you need to fetch UTM parameters from your backend using a unique ID:
import{useUmami,UTMFetcher}from'@danielgtmn/umami-react';functionMyComponent(){const{ trackPageviewAsync }=useUmami();// Define your UTM fetcher functionconstfetchUTMData: UTMFetcher=async(utmId: string)=>{constresponse=awaitfetch(`/api/utm/${utmId}`);constdata=awaitresponse.json();return{utm_source: data.source,utm_medium: data.medium,utm_campaign: data.campaign,utm_term: data.term,utm_content: data.content,};};consthandleAsyncPageview=async()=>{// This will fetch UTM data from your backend and track the pageviewawaittrackPageviewAsync('unique-utm-id-123',fetchUTMData,{// Optional additional datacustom_property: 'custom_value',});};return(<buttononClick={handleAsyncPageview}>
Track Async UTM Pageview
</button>);}The useUmami hook provides the following methods:
const{
track,// Original event tracking
trackPageview,// Manual pageview tracking
trackPageviewWithUTM,// Pageview with UTM parameters
trackPageviewAsync // Async UTM fetching + pageview}=useUmami();import{PageviewData,UTMFetcher}from'@danielgtmn/umami-react';// PageviewData interfaceconstpageviewData: PageviewData={url: '/custom-page',title: 'Page Title',referrer: 'https://example.com',utm_source: 'google',utm_medium: 'cpc',utm_campaign: 'summer-sale',utm_term: 'shoes',utm_content: 'ad-1',utm_id: 'unique-id-123',// Any additional custom propertiescustom_field: 'custom_value',};// UTMFetcher function typeconstmyUTMFetcher: UTMFetcher=async(utmId: string)=>{// Your implementationreturn{utm_source: 'backend-source',utm_medium: 'backend-medium',// ... other UTM parameters};};When using manual pageview tracking, you might want to disable Umami's automatic pageview tracking by adding the data-auto-track="false" attribute:
<UmamiAnalyticsurl="https://analytics.example.com"websiteId="your-website-id"scriptAttributes={{'data-auto-track': 'false'}}/>The async UTM fetching includes built-in error handling. If the UTM fetcher fails, it will:
- Log an error to the console (in debug mode)
- Fall back to basic pageview tracking with the provided
utm_id - Include any additional data you provided
// This will gracefully handle network errorsawaittrackPageviewAsync('utm-id',failingFetcher,{fallback_source: 'direct',});The package includes full TypeScript support with exported interfaces:
importUmamiAnalytics,{UmamiAnalyticsProps,UmamiConfig}from'@danielgtmn/umami-react';constconfig: UmamiAnalyticsProps={url: 'https://analytics.example.com',websiteId: 'your-website-id',debug: true,lazyLoad: true,};<UmamiAnalytics{...config}/>// pages/_app.tsx or app/layout.tsximportUmamiAnalyticsfrom'@danielgtmn/umami-react';exportdefaultfunctionApp({ Component, pageProps }){return(<><UmamiAnalyticsurl="https://analytics.example.com"websiteId="your-website-id"/><Component{...pageProps}/></>);}// src/App.tsximportUmamiAnalyticsfrom'@danielgtmn/umami-react';functionApp(){return(<divclassName="App"><UmamiAnalyticsurl="https://analytics.example.com"websiteId="your-website-id"/>{/* Your app content */}</div>);}# Install dependencies
pnpm install
# Start development mode
pnpm dev
# Run linting
pnpm lint
# Auto-fix linting issues
pnpm lint:fix
# Format code
pnpm format
# Type check
pnpm type-check
# Run tests
pnpm test# Run tests once
pnpm test:run
# Run tests with coverage
pnpm test:coverage
# Run tests in watch mode
pnpm test:watch
# Check bundle size
pnpm size
# Analyze bundle
pnpm analyze
# Build for production
pnpm build
# Clean build artifacts
pnpm cleanThis project uses modern development tools to ensure code quality:
Git hooks automatically run quality checks before commits:
- Pre-commit: TypeScript check, linting, and tests
- Commit-msg: Validates commit message format
Commits follow Conventional Commits format:
type(scope): description
# Examples:
feat: add new tracking feature
fix: resolve lazy loading bug
docs: update README
test: add component testsAllowed types: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test
This project uses Vitest for testing with React Testing Library.
# Run tests
pnpm test# Run tests with coverage
pnpm test:coverage
# Run tests in watch mode
pnpm test:watchThis project uses GitHub Actions for continuous integration and deployment:
CI Pipeline (
.github/workflows/ci.yml): Runs on every push/PR to main- Tests across multiple Node.js versions (18.x, 20.x, 22.x)
- Linting and type checking
- Bundle size monitoring
- Test coverage reporting
Release Pipeline (
.github/workflows/publish.yml): Runs on releases- Runs full test suite before publishing
- Publishes to NPM with public access
The project includes bundle size monitoring and analysis:
# Check current bundle sizes
pnpm size
# Analyze bundle composition
pnpm analyzeBundle size limits:
- ESM: ≤ 3 KB (gzipped)
- CJS: ≤ 3.5 KB (gzipped)
Contributions are welcome! Please ensure:
- Follow commit conventions: Use Conventional Commits format
- Quality checks: Git hooks automatically run:
- TypeScript type checking
- ESLint linting
- Test execution
- Commit message validation
- Manual verification:
- All tests pass:
pnpm test:run - Code is linted:
pnpm lint - Bundle size is within limits:
pnpm size - TypeScript types are correct:
pnpm type-check
- All tests pass:
# Install dependencies
pnpm install
# Git hooks are automatically set up via prepare script# If needed manually: pnpm preparePlease feel free to submit a Pull Request!