On this page
React
Last updated
Integrate vTilt into a standalone React app (Vite, Create React App, or any React renderer) — npm package or inline script, identify on auth state changes.
vTilt drops into any React app — Vite, CRA, RSPack, or a custom Webpack setup. Initialise the SDK once on startup, then identify the user whenever your auth state changes.
#1. Add your environment variables
# .env
VITE_VTILT_TOKEN=YOUR_PROJECT_TOKEN
VITE_VTILT_HOST=https://www.vtilt.com#2. Install & initialise
Choose how you load the Browser SDK. npm boots the SDK from a provider component; the inline script drops a stub in index.html with no package to install. Both expose the same window.vt global — the rest of this guide is identical either way.
Install the package:
npm install @v-tilt/browserInitialise the SDK in a provider that identifies the user when auth is ready:
// src/lib/vtilt.tsx
import { useEffect } from 'react'
import { vt } from '@v-tilt/browser'
import { useAuth } from '../auth'
export function VTiltProvider({ children }: { children: React.ReactNode }) {
const { user, isLoading } = useAuth()
useEffect(() => {
vt.init(import.meta.env.VITE_VTILT_TOKEN, {
api_host: import.meta.env.VITE_VTILT_HOST,
autocapture: true,
capture_pageview: true,
capture_pageleave: true,
})
}, [])
useEffect(() => {
if (isLoading) return
if (user?.id) {
vt.identify(user.id, { email: user.email })
} else if (vt.getUserState() === 'identified') {
vt.resetUser()
}
}, [user, isLoading])
return <>{children}</>
}// src/main.tsx
import ReactDOM from 'react-dom/client'
import { VTiltProvider } from './lib/vtilt'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')!).render(
<VTiltProvider>
<App />
</VTiltProvider>,
)useAuth() is your app's hook — any shape with { user, isLoading } works (Clerk, Auth0, Supabase, custom context).
#3. Capture events from any component
import { vt } from '@v-tilt/browser'
export function CtaButton() {
return (
<button onClick={() => vt.capture('cta_clicked', { location: 'hero' })}>
Get started
</button>
)
}#4. Pageviews for client-side routers
Most SPA routers update the History API on navigation, which the SDK picks up automatically. If yours doesn't (rare), emit a pageview from a route effect:
import { useLocation } from 'react-router'
function PageviewTracker() {
const location = useLocation()
useEffect(() => {
vt.capture('$pageview', {
$current_url: window.location.href,
$pathname: location.pathname,
})
}, [location.pathname])
return null
}#Next steps
- Identify & alias — anonymous → known user merge.
- Autocapture — what's captured automatically.
- Reverse proxy — block-resistant ingestion.
- Common mistakes — integration pitfalls to avoid before you ship.