Skip to main content

Installation

npm install @databuddy/sdk

Databuddy Component

The <Databuddy /> component injects the tracking script into your app. It renders nothing to the DOM.

Next.js App Router

app/layout.tsx
import { Databuddy } from '@databuddy/sdk/react';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Databuddy
          trackWebVitals
          trackErrors
          trackScrollDepth
        />
      </body>
    </html>
  );
}
The clientId is automatically detected from the NEXT_PUBLIC_DATABUDDY_CLIENT_ID environment variable.

Next.js Pages Router

pages/_app.tsx
import { Databuddy } from '@databuddy/sdk/react';
import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <Databuddy
        trackWebVitals
        trackErrors
      />
    </>
  );
}

React (Vite / CRA)

src/main.tsx
import { Databuddy } from '@databuddy/sdk/react';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
    <Databuddy
      clientId="your-client-id"
      trackWebVitals
      trackErrors
    />
  </StrictMode>
);

Component Props

All configuration options are available as props:
<Databuddy
  clientId="your-client-id"              // Auto-detected from env
  apiUrl="https://basket.databuddy.cc"   // Custom API endpoint
  
  // Automatic tracking features
  trackWebVitals={true}                   // Core Web Vitals
  trackErrors={true}                      // JavaScript errors  
  trackScrollDepth={true}                 // Scroll engagement
  trackOutgoingLinks={true}               // External links
  trackInteractions={true}                // Click interactions
  trackAttributes={true}                  // data-* attributes
  
  // Performance & optimization
  samplingRate={0.5}                      // Track 50% of sessions
  enableBatching={true}                   // Batch events (default)
  batchSize={10}                          // Events per batch
  batchTimeout={2000}                     // Flush interval (ms)
  
  // Privacy controls
  disabled={!userConsent}                 // Disable tracking
  skipPatterns={['/admin/**']}            // Ignore patterns
  maskPatterns={['/users/*']}             // Mask sensitive URLs
  
  // Debugging
  debug={process.env.NODE_ENV === 'development'}
/>

Tracking Functions

Import tracking functions from the core SDK:
import { track, flush, clear } from '@databuddy/sdk';

Track Custom Events

import { track } from '@databuddy/sdk';

function CheckoutButton() {
  const handleClick = () => {
    track('checkout_started', {
      cartValue: 99.99,
      itemCount: 3,
      currency: 'USD'
    });
  };
  
  return <button onClick={handleClick}>Checkout</button>;
}

Track Component Events

import { track } from '@databuddy/sdk';
import { useEffect } from 'react';

function PricingPage() {
  useEffect(() => {
    track('pricing_page_viewed', {
      source: 'navigation',
      timestamp: Date.now()
    });
  }, []);
  
  return <div>Pricing content...</div>;
}

Track Form Submissions

import { track } from '@databuddy/sdk';
import { useState } from 'react';

function SignupForm() {
  const [email, setEmail] = useState('');
  
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    track('signup_form_submitted', {
      formType: 'newsletter',
      source: 'footer'
    });
    
    // Submit form...
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <button type="submit">Subscribe</button>
    </form>
  );
}

Track Errors

import { trackError } from '@databuddy/sdk';
import { useEffect } from 'react';

function DataFetcher() {
  useEffect(() => {
    async function fetchData() {
      try {
        const res = await fetch('/api/data');
        if (!res.ok) throw new Error('Fetch failed');
      } catch (error) {
        trackError(error.message, {
          error_type: error.name,
          context: 'data_fetcher',
          endpoint: '/api/data'
        });
      }
    }
    
    fetchData();
  }, []);
  
  return null;
}

Session Management

Get Tracking IDs

import { getAnonymousId, getSessionId } from '@databuddy/sdk';
import { useEffect, useState } from 'react';

function UserProfile() {
  const [anonId, setAnonId] = useState<string | null>(null);
  
  useEffect(() => {
    setAnonId(getAnonymousId());
  }, []);
  
  return <div>Anonymous ID: {anonId}</div>;
}

Clear Session on Logout

import { clear } from '@databuddy/sdk';
import { useRouter } from 'next/navigation';

function LogoutButton() {
  const router = useRouter();
  
  const handleLogout = async () => {
    // Clear tracking session
    clear();
    
    // Clear auth session
    await fetch('/api/logout', { method: 'POST' });
    
    router.push('/login');
  };
  
  return <button onClick={handleLogout}>Logout</button>;
}
import { getTrackingParams } from '@databuddy/sdk';

function ExternalLink({ href, children }) {
  const params = getTrackingParams();
  const url = `${href}${params ? `?${params}` : ''}`;
  
  return <a href={url}>{children}</a>;
}

// Usage
<ExternalLink href="https://shop.example.com">
  Visit Shop
</ExternalLink>

Feature Flags

Feature flags require the FlagsProvider wrapper component.

FlagsProvider Setup

app/layout.tsx
import { Databuddy } from '@databuddy/sdk/react';
import { FlagsProvider } from '@databuddy/sdk/react';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <FlagsProvider
          clientId="your-client-id"
          user={{
            userId: '12345',
            email: '[email protected]'
          }}
        >
          {children}
        </FlagsProvider>
        <Databuddy trackWebVitals />
      </body>
    </html>
  );
}

useFlag Hook

Get a feature flag’s full state:
import { useFlag } from '@databuddy/sdk/react';

function NewFeature() {
  const flag = useFlag('new-checkout-flow');
  
  if (flag.loading) {
    return <Skeleton />;
  }
  
  if (!flag.on) {
    return <OldCheckout />;
  }
  
  return <NewCheckout variant={flag.variant} />;
}

useFeature Hook

Simplified feature check:
import { useFeature } from '@databuddy/sdk/react';

function DarkModeToggle() {
  const darkMode = useFeature('dark-mode');
  
  if (darkMode.loading) return null;
  
  return (
    <div className={darkMode.on ? 'dark' : 'light'}>
      {/* Content */}
    </div>
  );
}

useFeatureOn Hook

Boolean-only check with default value (SSR-safe):
import { useFeatureOn } from '@databuddy/sdk/react';

function BetaBanner() {
  const showBanner = useFeatureOn('beta-banner', false);
  
  if (!showBanner) return null;
  
  return <div>Try our new beta features!</div>;
}

useFlagValue Hook

Get typed flag values:
import { useFlagValue } from '@databuddy/sdk/react';

function ItemList() {
  const maxItems = useFlagValue<number>('max-items', 10);
  const theme = useFlagValue<'light' | 'dark'>('theme', 'light');
  
  return <div>Showing {maxItems} items in {theme} mode</div>;
}

useVariant Hook

A/B testing with variants:
import { useVariant } from '@databuddy/sdk/react';

function CheckoutFlow() {
  const variant = useVariant('checkout-experiment');
  
  switch (variant) {
    case 'control':
      return <OldCheckout />;
    case 'treatment-a':
      return <NewCheckoutA />;
    case 'treatment-b':
      return <NewCheckoutB />;
    default:
      return <DefaultCheckout />;
  }
}

Advanced Usage

Conditional Rendering

import { Databuddy } from '@databuddy/sdk/react';

function App() {
  const isDevelopment = process.env.NODE_ENV === 'development';
  const hasConsent = useUserConsent();
  
  return (
    <>
      <YourApp />
      
      {/* Only load in production with consent */}
      {!isDevelopment && hasConsent && (
        <Databuddy
          trackWebVitals
          trackErrors
        />
      )}
    </>
  );
}

Dynamic Configuration

import { Databuddy } from '@databuddy/sdk/react';
import { useEffect, useState } from 'react';

function App() {
  const [config, setConfig] = useState(null);
  
  useEffect(() => {
    fetch('/api/analytics-config')
      .then(res => res.json())
      .then(setConfig);
  }, []);
  
  if (!config) return <div>Loading...</div>;
  
  return (
    <>
      <YourApp />
      <Databuddy {...config} />
    </>
  );
}

Flush Before Navigation

import { track, flush } from '@databuddy/sdk';
import { useRouter } from 'next/navigation';

function ExternalLinkButton({ url }: { url: string }) {
  const router = useRouter();
  
  const handleClick = () => {
    track('external_link_clicked', { url });
    
    // Ensure event is sent before leaving
    flush();
    
    setTimeout(() => {
      window.location.href = url;
    }, 100);
  };
  
  return <button onClick={handleClick}>Visit External Site</button>;
}

TypeScript Support

Full TypeScript support with intelligent autocomplete:
import type { DatabuddyConfig, EventProperties } from '@databuddy/sdk';
import { Databuddy } from '@databuddy/sdk/react';

const config: DatabuddyConfig = {
  clientId: 'your-client-id',
  trackWebVitals: true,
  samplingRate: 0.5,
};

function App() {
  return <Databuddy {...config} />;
}

// Type-safe event tracking
const eventProps: EventProperties = {
  plan: 'pro',
  price: 29.99,
  currency: 'USD'
};

track('subscription_created', eventProps);

Next Steps

Configuration

See all available configuration options

JavaScript SDK

Learn about vanilla JavaScript usage

Vue SDK

Vue 3 composables and plugins

Node.js SDK

Server-side event tracking

Build docs developers (and LLMs) love