Skip to main content

Installation

npm install --save @outlit/browser

Quick Start

Create a client component to initialize Outlit:
// app/providers.tsx
'use client'

import { useEffect } from 'react'
import outlit from '@outlit/browser'

export function OutlitProvider() {
  useEffect(() => {
    outlit.init({
      publicKey: process.env.NEXT_PUBLIC_OUTLIT_KEY!,
      trackPageviews: true,
    })
  }, [])

  return null
}
Add to your root layout:
// app/layout.tsx
import { OutlitProvider } from './providers'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <OutlitProvider />
        {children}
      </body>
    </html>
  )
}
Add your public key to .env.local:
NEXT_PUBLIC_OUTLIT_KEY=pk_your_public_key_here
For a better experience with React hooks, use the React provider:
// app/providers.tsx
'use client'

import { OutlitProvider } from '@outlit/browser/react'

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <OutlitProvider
      publicKey={process.env.NEXT_PUBLIC_OUTLIT_KEY!}
      trackPageviews
    >
      {children}
    </OutlitProvider>
  )
}
// app/layout.tsx
import { Providers } from './providers'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  )
}
See the React integration guide for full React provider documentation.

Tracking Events

Track custom events in client components:
// app/dashboard/page.tsx
'use client'

import { useEffect } from 'react'
import outlit from '@outlit/browser'

export default function Dashboard() {
  useEffect(() => {
    outlit.track('dashboard_viewed')
  }, [])

  function handleExport() {
    outlit.track('data_exported', {
      format: 'csv',
      rows: 1500
    })
  }

  return (
    <div>
      <h1>Dashboard</h1>
      <button onClick={handleExport}>Export Data</button>
    </div>
  )
}

With React Provider

'use client'

import { useOutlit } from '@outlit/browser/react'

export default function PricingButton() {
  const { track } = useOutlit()

  return (
    <button onClick={() => track('pricing_clicked', { plan: 'pro' })}>
      View Pricing
    </button>
  )
}

Identifying Users

Identify users after authentication:
// app/login/page.tsx
'use client'

import { useState } from 'react'
import { useRouter } from 'next/navigation'
import outlit from '@outlit/browser'

export default function LoginPage() {
  const router = useRouter()
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')

  async function handleLogin(e: React.FormEvent) {
    e.preventDefault()

    const user = await login(email, password)

    outlit.identify({
      email: user.email,
      userId: user.id,
      traits: {
        name: user.name,
        plan: user.plan
      }
    })

    router.push('/dashboard')
  }

  return (
    <form onSubmit={handleLogin}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
      />
      <button type="submit">Login</button>
    </form>
  )
}

Server-Side Auth Integration

With NextAuth

// app/providers.tsx
'use client'

import { OutlitProvider } from '@outlit/browser/react'
import { useSession } from 'next-auth/react'

export function Providers({ children }: { children: React.ReactNode }) {
  const { data: session, status } = useSession()

  const user = status === 'authenticated' && session?.user ? {
    email: session.user.email!,
    userId: session.user.id,
    traits: {
      name: session.user.name
    }
  } : null

  return (
    <OutlitProvider
      publicKey={process.env.NEXT_PUBLIC_OUTLIT_KEY!}
      user={user}
      trackPageviews
    >
      {children}
    </OutlitProvider>
  )
}

With Clerk

// app/providers.tsx
'use client'

import { OutlitProvider } from '@outlit/browser/react'
import { useUser } from '@clerk/nextjs'

export function Providers({ children }: { children: React.ReactNode }) {
  const { user, isLoaded } = useUser()

  const outlitUser = isLoaded && user ? {
    email: user.primaryEmailAddress?.emailAddress,
    userId: user.id,
    traits: {
      name: user.fullName
    }
  } : null

  return (
    <OutlitProvider
      publicKey={process.env.NEXT_PUBLIC_OUTLIT_KEY!}
      user={outlitUser}
      trackPageviews
    >
      {children}
    </OutlitProvider>
  )
}

With Supabase

// app/providers.tsx
'use client'

import { OutlitProvider } from '@outlit/browser/react'
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'
import { useEffect, useState } from 'react'

export function Providers({ children }: { children: React.ReactNode }) {
  const supabase = createClientComponentClient()
  const [user, setUser] = useState<any>(null)

  useEffect(() => {
    supabase.auth.getSession().then(({ data: { session } }) => {
      setUser(session?.user ?? null)
    })

    const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
      setUser(session?.user ?? null)
    })

    return () => subscription.unsubscribe()
  }, [supabase])

  const outlitUser = user ? {
    email: user.email,
    userId: user.id,
    traits: {
      name: user.user_metadata?.name
    }
  } : null

  return (
    <OutlitProvider
      publicKey={process.env.NEXT_PUBLIC_OUTLIT_KEY!}
      user={outlitUser}
      trackPageviews
    >
      {children}
    </OutlitProvider>
  )
}

Server Actions

Track events from server actions:
// app/actions.ts
'use server'

import { Outlit } from '@outlit/node'

const outlit = new Outlit({
  privateKey: process.env.OUTLIT_PRIVATE_KEY!
})

export async function trackServerEvent(userId: string) {
  await outlit.track({
    visitorId: userId,
    event: 'server_action_completed',
    properties: {
      action: 'data_export',
      timestamp: new Date().toISOString()
    }
  })
}
For server-side tracking, see the Node.js integration guide.

API Routes

Track events from API routes:
// app/api/checkout/route.ts
import { NextResponse } from 'next/server'
import { Outlit } from '@outlit/node'

const outlit = new Outlit({
  privateKey: process.env.OUTLIT_PRIVATE_KEY!
})

export async function POST(request: Request) {
  const { userId, amount } = await request.json()

  await outlit.track({
    visitorId: userId,
    event: 'checkout_completed',
    properties: { amount }
  })

  return NextResponse.json({ success: true })
}

Middleware Tracking

Track pageviews from middleware:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const response = NextResponse.next()

  // Add tracking headers
  response.headers.set('X-Outlit-Track', 'pageview')

  return response
}

Environment Variables

Set up your environment variables:
# .env.local

# Public key (used in browser)
NEXT_PUBLIC_OUTLIT_KEY=pk_your_public_key_here

# Private key (used in server actions/API routes)
OUTLIT_PRIVATE_KEY=sk_your_private_key_here
Never expose your private key in client-side code. Only use it in server components, API routes, or server actions.

TypeScript Support

Full TypeScript support is included:
import outlit, { type OutlitOptions } from '@outlit/browser'

const options: OutlitOptions = {
  publicKey: process.env.NEXT_PUBLIC_OUTLIT_KEY!,
  trackPageviews: true,
  flushInterval: 5000
}

outlit.init(options)

Next Steps