@giof/react-umami
v2.6.12
Published
Lightweight Umami Analytics component for React (~2.6kB) with dry-run testing and debug features
Maintainers
Readme
@giof/react-umami – Umami Analytics for React
A React component for Umami Analytics with built-in dry-run testing, debug logging, and SSR safety.
🧪 Features dry-run mode for clean development - test your tracking without polluting production data!
📦 Bundle Size
- Your bundle impact: ~2.6 kB (minified + gzipped)
- npm package size: 26.8 kB (includes documentation - not bundled into your app)
🚀 Installation
Install the package via pnpm, npm, or yarn:
pnpm add @giof/react-umami
# or
npm install @giof/react-umami
# or
yarn add @giof/react-umami📊 Usage
Add the component to your React application:
// In your main app component or layout
import { UmamiAnalytics } from '@giof/react-umami';
export default function App() {
return (
<div>
{/* Your app content */}
<UmamiAnalytics />
</div>
);
}Next.js Usage
App Router (Recommended)
⚠️ Important for Next.js + App Router: You MUST use a client wrapper component to avoid build errors caused by mixing server and client components. See the complete Next.js example for details.
For Next.js 13+ with App Router, you need to create a client wrapper component to avoid SSR/client-side mixing issues:
Step 1: Create a client wrapper component
// components/ClientUmamiAnalytics.tsx
'use client';
import dynamic from 'next/dynamic';
// Dynamically import UmamiAnalytics with SSR disabled
const UmamiAnalytics = dynamic(
() => import('@giof/react-umami').then((mod) => ({ default: mod.UmamiAnalytics })),
{
ssr: false,
loading: () => null
}
);
interface ClientUmamiAnalyticsProps {
websiteId?: string;
src?: string;
domains?: string[];
autoTrack?: boolean;
dryRun?: boolean;
debug?: boolean;
}
export default function ClientUmamiAnalytics(props: ClientUmamiAnalyticsProps) {
return <UmamiAnalytics {...props} />;
}Step 2: Use the wrapper in your layout
// app/layout.tsx
import ClientUmamiAnalytics from '@/components/ClientUmamiAnalytics';
export default function RootLayout({
children
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head />
<body>
{children}
<ClientUmamiAnalytics
dryRun={process.env.NODE_ENV === 'development'}
debug={process.env.NODE_ENV === 'development'}
/>
</body>
</html>
);
}Pages Router (Legacy)
For Next.js Pages Router, you can use the component directly:
// pages/_app.tsx
import { UmamiAnalytics } from '@giof/react-umami';
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<UmamiAnalytics />
</>
);
}Create React App / Vite Usage
// src/App.tsx
import { UmamiAnalytics } from '@giof/react-umami';
function App() {
return (
<div className="App">
{/* Your app content */}
<UmamiAnalytics />
</div>
);
}
export default App;⚙️ Configuration
Environment Variables
Configure your Umami analytics through environment variables:
# Universal (works with all frameworks - server-side and build-time)
UMAMI_WEBSITE_ID=your-website-id-here
UMAMI_SCRIPT_URL=https://your-umami-instance.com/script.jsFramework-specific client-side variables (required for browser access):
# Next.js (client-side access requires NEXT_PUBLIC_ prefix)
NEXT_PUBLIC_UMAMI_WEBSITE_ID=your-website-id-here
NEXT_PUBLIC_UMAMI_SCRIPT_URL=https://your-umami-instance.com/script.js
# Create React App (client-side access requires REACT_APP_ prefix)
REACT_APP_UMAMI_WEBSITE_ID=your-website-id-here
REACT_APP_UMAMI_SCRIPT_URL=https://your-umami-instance.com/script.js💡 Pro Tip: For Next.js, you can use both! Use UMAMI_* for server-side and NEXT_PUBLIC_UMAMI_* for client-side access.
The component will check environment variables in this order:
Website ID:
UMAMI_WEBSITE_ID(recommended - works everywhere)NEXT_PUBLIC_UMAMI_WEBSITE_ID(Next.js)REACT_APP_UMAMI_WEBSITE_ID(Create React App)
Script URL:
UMAMI_SCRIPT_URL(recommended - works everywhere)NEXT_PUBLIC_UMAMI_SCRIPT_URL(Next.js)REACT_APP_UMAMI_SCRIPT_URL(Create React App)https://cloud.umami.is/script.js(default fallback)
Props
You can also configure the component through props:
<UmamiAnalytics
websiteId="your-website-id"
src="https://your-umami-instance.com/script.js"
domains={['example.com', 'www.example.com']}
autoTrack={false}
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| websiteId | string | process.env.UMAMI_WEBSITE_ID | Your Umami website ID |
| src | string | process.env.UMAMI_SCRIPT_URL or https://cloud.umami.is/script.js | The URL of your Umami script |
| domains | string[] | undefined | Restrict tracking to specific domains |
| autoTrack | boolean | true | Whether to automatically track page views |
| dryRun | boolean | false | 🧪 Enable dry run mode - no real events sent to Umami |
| debug | boolean | false | 🔍 Enable debug logging - detailed console output |
Note: The component checks multiple environment variable names for maximum compatibility across frameworks.
🧪 Dry Run Mode
Built-in dry-run testing for clean development!
What is Dry Run Mode?
When dryRun={true}, the component:
- 🚫 Never loads external scripts - no network requests to Umami servers
- 🎭 Creates a mock tracker - your app works exactly the same
- 📝 Logs all events to console - see exactly what would be tracked
- 🛡️ Protects your data - no test/dev events pollute production analytics
Perfect for Development
// Environment-aware setup
<UmamiAnalytics
websiteId="your-website-id"
dryRun={process.env.NODE_ENV === 'development'}
debug={process.env.NODE_ENV === 'development'}
/>What you'll see in console:
UmamiAnalytics [DRY RUN]: Would track event: button_click {
button: "signup",
location: "header",
userId: "123"
}Testing Made Easy
// Test your analytics without external dependencies
describe('Analytics Integration', () => {
it('tracks user signup', () => {
render(<App />);
fireEvent.click(screen.getByText('Sign Up'));
// Verify tracking calls in dry run mode
expect(console.log).toHaveBeenCalledWith(
'UmamiAnalytics [DRY RUN]: Would track event:',
'signup',
{ source: 'header' }
);
});
});Privacy & Compliance
// Respect user consent while maintaining functionality
<UmamiAnalytics
websiteId="your-website-id"
dryRun={!userConsent.analytics}
debug={!userConsent.analytics}
/>Why This Matters
❌ Other libraries force you to choose:
- Pollute production data with test events
- Complex mocking setup for testing
- No visibility into what's being tracked
✅ With dry run mode:
- Clean production data guaranteed
- Zero-config testing
- Full transparency of tracking behavior
- Same API in development and production
🚀 Advanced Usage Examples
Development & Testing
// Perfect for development - see everything that's happening
<UmamiAnalytics
websiteId="your-website-id"
debug={true}
dryRun={true} // No real events sent in development
/>Event Tracking with Utilities
import { UmamiAnalytics, trackEvent, trackPageView } from '@giof/react-umami';
// Track custom events
const handleButtonClick = () => {
trackEvent('button_click', {
button: 'signup',
location: 'header'
});
};
// Track page views manually
const handleNavigation = (path: string) => {
trackPageView(path, 'Custom Page Title');
};Advanced Hook Usage
import { useUmami } from '@giof/react-umami';
import { useEffect } from 'react';
function MyComponent() {
const { track, trackPage, isLoaded, updateConfig } = useUmami();
// Override configuration at runtime
useEffect(() => {
if (process.env.NODE_ENV === 'development') {
updateConfig({ dryRun: true, debug: true });
}
}, [updateConfig]);
const handleClick = () => {
track('user_action', { component: 'MyComponent' });
};
return <button onClick={handleClick}>Track Me</button>;
}Self-Hosted Umami Configuration
// Using environment variables for self-hosted Umami
<UmamiAnalytics
domains={['yoursite.com', 'www.yoursite.com']}
/># .env file
UMAMI_WEBSITE_ID=your-website-id-here
UMAMI_SCRIPT_URL=https://analytics.yourcompany.com/script.jsProduction Configuration
// Perfect for production - minimal setup, maximum reliability
<UmamiAnalytics
domains={['yoursite.com', 'www.yoursite.com']}
autoTrack={true}
/>✨ Features
🧪 Dry Run Mode
Test analytics integration without sending real events. Perfect for development, testing, and respecting user privacy.
🔍 Debug Logging
Detailed console output for development and troubleshooting. See exactly what's happening under the hood.
🛡️ SSR Safety
Built-in server-side rendering protection for Next.js, Remix, and other SSR frameworks. Includes Next.js App Router integration guide.
⚙️ Runtime Configuration
Override settings dynamically with the useUmami hook. Perfect for consent management.
🎯 Event Tracking Helpers
Simple trackEvent() and trackPageView() utilities for custom analytics.
🌐 Framework Agnostic
Works seamlessly with Next.js, Create React App, Vite, Remix, and any React setup.
🔧 Environment Variables
Universal UMAMI_WEBSITE_ID with automatic framework fallbacks for maximum compatibility.
📘 Full TypeScript Support
Complete type definitions included. IntelliSense and type safety out of the box.
📦 Zero Dependencies
No external dependencies. Lightweight and fast.
🧹 Auto Cleanup
Automatic script removal on component unmount. No memory leaks.
🚫 Duplicate Prevention
Smart script injection prevents conflicts and duplicate loading.
🏠 Domain Restrictions
Limit tracking to specific domains for enhanced security.
🛠️ Development
Clone and set up the project:
# Clone repository
git clone https://github.com/giof-se/umami.git
cd umami
# Install dependencies
pnpm install
# Run tests
pnpm test
# Format code
pnpm fmt
# Lint code
pnpm lint🧪 Testing
Run tests with:
# Run tests once
pnpm test
# Run tests in watch mode
pnpm test:watch
# Run tests with coverage
pnpm test:coverage🚢 Releasing
This project uses automated versioning and changelog generation:
Automated Workflow
- Push your changes to the
mainbranch - Version is automatically bumped based on commit message types:
feat:orfeature:for minor version bumpBREAKING CHANGE:ormajor:for major version bump- All other changes result in patch version bump
- Changelog is automatically generated from commit messages
- New version is tagged and published to GitHub Packages
Commit Message Format
For best results with autoversioning, follow the Conventional Commits format:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]Example commit messages:
feat: add domain restriction support(triggers minor version bump)fix: correct data attribute handling(triggers patch version bump)feat: add XYZ with BREAKING CHANGE: requires new config(triggers major version bump)
Improved CI/CD Pipeline
The CI/CD pipeline follows these steps:
- The Autoversion workflow runs when changes are pushed to the main branch
- It automatically increments the version based on commit messages
- The Publish workflow creates a GitHub release and publishes the package
The workflow has been enhanced to handle different trigger methods:
- Direct tag pushes
- Manual workflow dispatch with version input
- Automated workflow runs from the autoversion workflow
Comparison
| Feature | @giof/react-umami | Other Libraries | |---------|----------------------|-----------------| | Dry Run Testing | ✅ | ❌ | | Debug Logging | ✅ | Limited | | SSR Safety | ✅ | Manual setup | | Runtime Config | ✅ | Static only | | Framework Support | Universal | Framework-specific | | TypeScript | Full support | Varies | | Dependencies | Zero | Varies |
Support
- 🐛 Bug Reports: Open an issue
- 💡 Feature Requests: Open an issue
- 📖 Contributing: See CONTRIBUTING.md
- 💬 Questions: GitHub Discussions
License
MIT © giof-se
