Skip to content

About

😻 Privacy-focused Fathom Analytics for React, Next.js, and React Native with automatic pageview tracking and TypeScript support

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

react-fathom

npm npm bundle size TypeScript

Privacy-focused analytics for React, Next.js, and React Native.

πŸ“– Full Documentation Β· API Reference Β· Troubleshooting

Quick Start

npm install react-fathom fathom-client
// App.tsx or layout.tsx
import { FathomProvider } from 'react-fathom'

function App() {
  return (
    <FathomProvider siteId="YOUR_FATHOM_SITE_ID">
      <YourApp />
    </FathomProvider>
  )
}
// Any component
import { useFathom } from 'react-fathom'

function MyComponent() {
  const { trackEvent } = useFathom()
  return <button onClick={() => trackEvent('signup-click')}>Sign Up</button>
}

Pageviews are tracked automatically.

Why react-fathom?

Fathom Analytics is a privacy-focused alternative to Google Analyticsβ€”no cookies, no consent banners, GDPR compliant by default.

The official fathom-client works, but:

Problem react-fathom solution
Web onlyβ€”no React Native Full React Native support with offline event queuing
Next.js App Router requires boilerplate NextFathomProviderApp works directly in Server Component layouts
Imperative API only Hooks (useFathom, useTrackOnMount, useTrackOnVisible) and declarative components (<TrackClick>, <TrackVisible>)
No tree-shaking Fully tree-shakeableβ€”bundle only what you use

New to Fathom? Get a $10 credit with this referral link.

Features

  • πŸ”’ Privacy-first Fathom Analytics integration
  • βš›οΈ Hooks API and declarative tracking components
  • πŸ“± React Native with offline queuing and navigation tracking
  • ⚑ Next.js App Router and Pages Router support
  • πŸ›€οΈ React Router v6+ and Remix support
  • 🏠 Gatsby support with @reach/router integration
  • 🧭 TanStack Router support with type-safe routing
  • πŸ› Debug mode for development with event subscription hooks
  • 🌳 Tree-shakeable, fully typed (TypeScript)

Usage

Next.js App Router

// app/layout.tsx
import { NextFathomProviderApp } from 'react-fathom/next'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <NextFathomProviderApp siteId="YOUR_SITE_ID">
          {children}
        </NextFathomProviderApp>
      </body>
    </html>
  )
}

πŸ“– Full Next.js guide

Next.js Pages Router

// pages/_app.tsx
import { FathomProvider } from 'react-fathom'
import { NextFathomTrackViewPages } from 'react-fathom/next'

function MyApp({ Component, pageProps }) {
  return (
    <FathomProvider siteId="YOUR_SITE_ID" clientOptions={{ auto: false }}>
      <NextFathomTrackViewPages />
      <Component {...pageProps} />
    </FathomProvider>
  )
}

πŸ“– Full Next.js guide

React Router / Remix

// App.tsx or root.tsx
import { BrowserRouter } from 'react-router-dom'
import { FathomProvider } from 'react-fathom'
import { ReactRouterFathomTrackView } from 'react-fathom/react-router'

function App() {
  return (
    <BrowserRouter>
      <FathomProvider siteId="YOUR_SITE_ID" clientOptions={{ auto: false }}>
        <ReactRouterFathomTrackView />
        <Routes>...</Routes>
      </FathomProvider>
    </BrowserRouter>
  )
}

πŸ“– Full React Router guide

Gatsby

// gatsby-browser.js or Layout component
import { FathomProvider } from 'react-fathom'
import { GatsbyFathomTrackView } from 'react-fathom/gatsby'

export const wrapRootElement = ({ element }) => (
  <FathomProvider siteId="YOUR_SITE_ID" clientOptions={{ auto: false }}>
    <GatsbyFathomTrackView />
    {element}
  </FathomProvider>
)

πŸ“– Full Gatsby guide

TanStack Router

// src/routes/__root.tsx
import { createRootRoute, Outlet } from '@tanstack/react-router'
import { FathomProvider } from 'react-fathom'
import { TanStackRouterFathomTrackView } from 'react-fathom/tanstack-router'

export const Route = createRootRoute({
  component: () => (
    <FathomProvider siteId="YOUR_SITE_ID" clientOptions={{ auto: false }}>
      <TanStackRouterFathomTrackView />
      <Outlet />
    </FathomProvider>
  ),
})

πŸ“– Full TanStack Router guide

Hooks

import {
  useFathom,
  useTrackOnMount,
  useTrackOnClick,
  useTrackOnVisible,
} from 'react-fathom'

function MyComponent() {
  const { trackEvent, trackGoal } = useFathom()

  // Track on mount
  useTrackOnMount({ url: '/custom-page' })

  // Track clicks
  const handleClick = useTrackOnClick({ eventName: 'cta-click', _value: 100 })

  // Track visibility
  const ref = useTrackOnVisible({ eventName: 'hero-viewed' })

  return (
    <>
      <div ref={ref}>Hero section</div>
      <button onClick={handleClick}>Get Started</button>
      <button onClick={() => trackGoal('purchase', 2999)}>Buy Now</button>
    </>
  )
}

πŸ“– Hooks API reference

Declarative Components

import { TrackPageview, TrackClick, TrackVisible } from 'react-fathom'

function MyPage() {
  return (
    <>
      <TrackPageview url="/landing" />

      <TrackVisible eventName="section-viewed">
        <section>Tracks when visible</section>
      </TrackVisible>

      <TrackClick eventName="signup-click">
        <button>Sign Up</button>
      </TrackClick>
    </>
  )
}

πŸ“– Components API reference

React Native

npm install react-native-webview
import { NativeFathomProvider } from 'react-fathom/native'

function App() {
  return (
    <NativeFathomProvider siteId="YOUR_SITE_ID" debug={__DEV__} trackAppState>
      <YourApp />
    </NativeFathomProvider>
  )
}

πŸ“– Full React Native guide

Debug Mode

Enable debug mode to log tracking calls and subscribe to events for custom UI:

// Console logging during development
<FathomProvider siteId="YOUR_SITE_ID" debug={{ enabled: true }}>

// Subscribe to events programmatically
import { useDebugSubscription } from 'react-fathom'

function DebugPanel() {
  const { events, debugEnabled, clearEvents } = useDebugSubscription({
    maxEvents: 20,
    onEvent: (event) => console.log('Tracked:', event)
  })

  if (!debugEnabled) return null

  return (
    <div>
      {events.map(e => <div key={e.id}>{e.type}: {e.eventName || e.url}</div>)}
    </div>
  )
}

Debug mode does not block actual trackingβ€”events are still sent to Fathom.

API Overview

Providers

Component Use case
FathomProvider Basic React apps
NextFathomProviderApp Next.js App Router
NextFathomTrackViewPages Next.js Pages Router (add inside FathomProvider)
ReactRouterFathomTrackView React Router v6+ / Remix (add inside FathomProvider)
GatsbyFathomTrackView Gatsby (add inside FathomProvider)
TanStackRouterFathomTrackView TanStack Router (add inside FathomProvider)
NativeFathomProvider React Native

Hooks

Hook Description
useFathom() Returns trackPageview, trackEvent, trackGoal, and more
useTrackOnMount(opts?) Track pageview when component mounts
useTrackOnClick(opts) Returns click handler that tracks event
useTrackOnVisible(opts) Returns ref; tracks when element becomes visible
useDebugSubscription(opts?) Subscribe to debug events for custom UI

Components

Component Description
<TrackPageview> Track pageview on mount
<TrackClick> Track event on click
<TrackVisible> Track when visible (IntersectionObserver)

πŸ“– Full API Reference

Common Issues

Events not appearing?

  1. Verify site ID matches your Fathom dashboard
  2. Check for ad blockers (test in incognito)
  3. Add { includedDomains: ['localhost'] } to clientOptions

Duplicate pageviews?

// Disable fathom-client's auto tracking when using NextFathomTrackViewApp
<FathomProvider siteId="..." clientOptions={{ auto: false }}>

πŸ“– Full Troubleshooting Guide

Documentation

License

MIT Β© Ryan Hefner

About

😻 Privacy-focused Fathom Analytics for React, Next.js, and React Native with automatic pageview tracking and TypeScript support

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages