Installation
Copy
npm install --save @outlit/browser
Quick Start
- App Router
- Pages Router
Create a client component to initialize Outlit:Add to your root layout:
Copy
// 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
}
Copy
// app/layout.tsx
import { OutlitProvider } from './providers'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<OutlitProvider />
{children}
</body>
</html>
)
}
Initialize in
_app.tsx:Copy
// pages/_app.tsx
import { useEffect } from 'react'
import type { AppProps } from 'next/app'
import outlit from '@outlit/browser'
export default function App({ Component, pageProps }: AppProps) {
useEffect(() => {
outlit.init({
publicKey: process.env.NEXT_PUBLIC_OUTLIT_KEY!,
trackPageviews: true,
})
}, [])
return <Component {...pageProps} />
}
Add your public key to
.env.local:Copy
NEXT_PUBLIC_OUTLIT_KEY=pk_your_public_key_here
Using the React Provider (Recommended)
For a better experience with React hooks, use the React provider:Copy
// 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>
)
}
Copy
// app/layout.tsx
import { Providers } from './providers'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}
Tracking Events
Track custom events in client components:Copy
// 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
Copy
'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:Copy
// 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
Copy
// 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
Copy
// 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
Copy
// 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:Copy
// 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:Copy
// 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:Copy
// 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:Copy
# .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:Copy
import outlit, { type OutlitOptions } from '@outlit/browser'
const options: OutlitOptions = {
publicKey: process.env.NEXT_PUBLIC_OUTLIT_KEY!,
trackPageviews: true,
flushInterval: 5000
}
outlit.init(options)