Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,27 @@ name: Run tests on PR/PUSH on main branch

on:
push:
branches: [ "main" ]
branches: ["main"]
pull_request:
branches: [ "main" ]
branches: ["main"]

jobs:
cache-and-install-test:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
node-version: 24

- uses: pnpm/action-setup@v2
- uses: pnpm/action-setup@v4
name: Install pnpm
id: pnpm-install
with:
version: 7
run_install: false

- name: Get pnpm store directory
Expand All @@ -35,7 +34,7 @@ jobs:
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT

- uses: actions/cache@v3
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
Expand All @@ -47,4 +46,3 @@ jobs:
run: pnpm install
- name: Run tests
run: pnpm run test:ci

4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ coverage
*.njsproj
*.sln
*.sw?


# Build directories
dist
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v16.18.0
v24
82 changes: 82 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

This is `@lbrdan/react-umami` - a zero-dependency React library for integrating with Umami analytics. It provides a React Context + Hooks based approach without requiring the external Umami SDK to be loaded at runtime.

## Development Commands

```bash
# Install dependencies (uses pnpm)
pnpm install

# Build the library (outputs to dist/)
pnpm build

# Run tests in watch mode
pnpm test

# Run tests once (CI mode)
pnpm test:ci

# Generate coverage report
pnpm coverage
```

## Architecture

The library is structured around React Context for dependency injection:

### Core Files

- **src/provider.tsx** - `UmamiProvider` component that initializes the context with tracking configuration
- Handles Do Not Track detection via `doNotTrack()` utility
- Manages domain allowlisting
- Creates the `track()` function that posts to Umami API endpoint

- **src/context.ts** - Defines `UmamiContext` with default empty values

- **src/hooks.ts** - Two main hooks:
- `useUmamiEventTrack()` - Track custom events with optional data
- `useUmamiPageTrack()` - Track pageviews

- **src/utils.ts** - Core utilities:
- `doNotTrack()` - Cross-browser Do Not Track detection
- `post()` - HTTP request with fetch/XHR fallback
- `removeTrailingSlash()` - URL normalization

- **src/types.ts** - TypeScript interfaces for `UmamiContextValue`, `UmamiTrackEvent`, `UmamiTrackEventPayload`

- **src/components.tsx** - `PageTracker` component for automatic pageview tracking

- **src/const.ts** - Constants including Umami API path (`/api/send`), cache keys

### Data Flow

1. User wraps app in `UmamiProvider` with config (host URL, website ID, domains)
2. Provider computes common payload fields (hostname, screen size, language, etc.)
3. Hooks consume context to get `track()` function and payload fields
4. Events are POSTed to `{hostUrl}/api/send` with payload format matching Umami v2 API

### Build System

- **Vite** with `vite-plugin-dts` for TypeScript declaration generation
- Outputs ESM (`react-umami.js`), CJS (`react-umami.umd.cjs`), and UMD formats
- Entry point: `src/index.ts`
- React is externalized (peer dependency)

### Testing

- **Vitest** with jsdom environment
- **MSW (Mock Service Worker)** for API mocking in `src/test/msw.test.utils.ts`
- `@testing-library/react-hooks` for hook testing
- Test utilities in `src/test/` directory

## Important Constraints

- No external runtime dependencies - zero dependencies
- Side effects free (`sideEffect: false` in package.json)
- Supports SSR (checks for `typeof window == "undefined"`)
- Respects user privacy via Do Not Track and domain allowlisting
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ This lib is still WIP, no package is out on NPM yet. There is some work left to

## Background

I was trying to gather some analytics for my NextJS (v12 - `pages` folder) personal site, especially about the interactions with my resumee. I started thinking about Google Analitycs but I also wanted to keep this data for me, and granting the minimum privacy impact to the visitors.
I was trying to gather some analytics for my NextJS (v12 - `pages` folder or v13 - client components with some quirks) personal site, especially about the interactions with my resumee. I started thinking about Google Analitycs but I also wanted to keep this data for me, and granting the minimum privacy impact to the visitors.

Then I found Umami.is opting to self-host it on my home server (or better said, a Raspberry Pi 3), but I realized that umami provides it's own library.
I found [Umami](https://umami.is/) and it seemed to be a good fit for my needs. It's a self-hosted analytics tool, with a very simple and clean interface. It's also open source, free to use with self hosting capability. I was sold.

Then I opted to self host Umami in my home server (or better said, a Raspberry Pi 3), but I realized that umami provides it's own library.
I didn't want to let some adblocker or something preventing me from using those service, and I needed something that better integrates with NextJS.

### Other packages
Expand All @@ -63,13 +65,13 @@ This package is available via [NPM](https://www.npmjs.com/package/@parcellab/rea

```sh
# NPM
npm i react-umami
npm i @lbrdan/react-umami

# Yarn / Yarn Berry
yarn add react-umami
yarn add @lbrdan/react-umami

# PNPM
pnpm add react-umami
pnpm add @lbrdan/react-umami
```

## Usage
Expand Down Expand Up @@ -202,7 +204,7 @@ const PageTrackerRR: FC<{}> = () => {
export default App;
```

# API (WIP)
# API

# Contributing

Expand Down
37 changes: 19 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
"author": "Daniele Lubrano <lubrano.daniele@gmail.com>",
"license": "MIT",
"engines": {
"node": "^16.18.0"
"node": ">=24"
},
"packageManager": "pnpm@7.27.0",
"packageManager": "pnpm@10.28.0",
"exports": {
".": {
"types": "./dist/react-umami.d.ts",
"import": "./dist/react-umami.js",
"require": "./dist/react-umami.umd.cjs",
"types": "./dist/react-umami.d.ts"
"require": "./dist/react-umami.umd.cjs"
}
},
"scripts": {
Expand All @@ -31,21 +31,22 @@
"coverage": "vitest coverage"
},
"devDependencies": {
"@testing-library/react-hooks": "^8.0.1",
"@types/node": "^18.13.0",
"@types/react": "^18.0.28",
"@vitejs/plugin-react": "^3.1.0",
"@vitest/coverage-c8": "^0.28.4",
"jsdom": "^21.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0",
"typescript": "^4.9.5",
"vite": "^4.1.1",
"vite-plugin-dts": "^1.7.2",
"vitest": "^0.28.4"
"@testing-library/react": "^16.3.1",
"@types/node": "^24",
"@types/react": "^19.2.8",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2",
"@vitest/coverage-v8": "^4.0.17",
"jsdom": "^27.4.0",
"msw": "^2.12.7",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"typescript": "5.8.2",
"vite": "^7.3.1",
"vite-plugin-dts": "^4.5.4",
"vitest": "^4.0.17"
},
"peerDependencies": {
"react": "^18.2.0"
"react": "^18.0.0 || ^19.0.0"
}
}
Loading