Installation
Copy
npm install --save @outlit/browser
Quick Start
Add Outlit to your base layout:Copy
---
// src/layouts/BaseLayout.astro
const PUBLIC_OUTLIT_KEY = import.meta.env.PUBLIC_OUTLIT_KEY
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>My Site</title>
</head>
<body>
<slot />
<script>
import outlit from '@outlit/browser'
outlit.init({
publicKey: import.meta.env.PUBLIC_OUTLIT_KEY,
trackPageviews: true,
})
</script>
</body>
</html>
Add your public key to
.env:Copy
PUBLIC_OUTLIT_KEY=pk_your_public_key_here
Alternative: Inline Script
Use an inline script for better performance:Copy
---
// src/layouts/BaseLayout.astro
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>My Site</title>
</head>
<body>
<slot />
<script>
import outlit from '@outlit/browser'
outlit.init({
publicKey: import.meta.env.PUBLIC_OUTLIT_KEY,
trackPageviews: true,
})
</script>
</body>
</html>
Tracking Events
Track events in Astro components:Copy
---
// src/components/PricingButton.astro
---
<button id="pricing-btn" data-plan="pro">
View Pricing
</button>
<script>
import outlit from '@outlit/browser'
const button = document.getElementById('pricing-btn')
button?.addEventListener('click', () => {
const plan = button.getAttribute('data-plan')
outlit.track('pricing_clicked', { plan })
})
</script>
With Client Directives
Use client directives for interactive components:Copy
---
// src/pages/index.astro
import PricingButton from '../components/PricingButton.jsx'
---
<html>
<body>
<PricingButton client:load />
</body>
</html>
Framework Islands
React Island
Copy
// src/components/PricingButton.jsx
import { useEffect } from 'react'
import outlit from '@outlit/browser'
export default function PricingButton() {
function handleClick() {
outlit.track('pricing_clicked', { plan: 'pro' })
}
return (
<button onClick={handleClick}>
View Pricing
</button>
)
}
Vue Island
Copy
<!-- src/components/PricingButton.vue -->
<script setup>
import outlit from '@outlit/browser'
function handleClick() {
outlit.track('pricing_clicked', { plan: 'pro' })
}
</script>
<template>
<button @click="handleClick">
View Pricing
</button>
</template>
Svelte Island
Copy
<!-- src/components/PricingButton.svelte -->
<script>
import outlit from '@outlit/browser'
function handleClick() {
outlit.track('pricing_clicked', { plan: 'pro' })
}
</script>
<button on:click={handleClick}>
View Pricing
</button>
Identifying Users
Identify users after authentication:Copy
---
// src/components/LoginForm.astro
---
<form id="login-form">
<input type="email" name="email" placeholder="Email" />
<input type="password" name="password" placeholder="Password" />
<button type="submit">Login</button>
</form>
<script>
import outlit from '@outlit/browser'
const form = document.getElementById('login-form')
form?.addEventListener('submit', async (e) => {
e.preventDefault()
const formData = new FormData(e.target)
const email = formData.get('email')
const password = formData.get('password')
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
})
const user = await response.json()
outlit.identify({
email: user.email,
userId: user.id,
traits: {
name: user.name,
plan: user.plan
}
})
window.location.href = '/dashboard'
})
</script>
View Transitions
Track navigation with Astro’s View Transitions:Copy
---
// src/layouts/BaseLayout.astro
import { ViewTransitions } from 'astro:transitions'
---
<!DOCTYPE html>
<html lang="en">
<head>
<ViewTransitions />
</head>
<body>
<slot />
<script>
import outlit from '@outlit/browser'
outlit.init({
publicKey: import.meta.env.PUBLIC_OUTLIT_KEY,
trackPageviews: false, // Manual tracking
})
// Track pageviews (fires on initial load and navigation with View Transitions)
document.addEventListener('astro:page-load', () => {
outlit.track('pageview', {
path: window.location.pathname
})
})
</script>
</body>
</html>
API Routes
Track events from API endpoints:Copy
// src/pages/api/checkout.ts
import type { APIRoute } from 'astro'
import { Outlit } from '@outlit/node'
const outlit = new Outlit({
privateKey: import.meta.env.OUTLIT_PRIVATE_KEY
})
export const POST: APIRoute = async ({ request }) => {
const body = await request.json()
await outlit.track({
visitorId: body.userId,
event: 'checkout_completed',
properties: {
amount: body.amount,
plan: body.plan
}
})
return new Response(JSON.stringify({ success: true }), {
status: 200,
headers: { 'Content-Type': 'application/json' }
})
}
For server-side tracking, see the Node.js integration guide.
SSR Pages
For SSR pages, ensure tracking runs client-side:Copy
---
// src/pages/products/[id].astro
export const prerender = false // SSR mode
const { id } = Astro.params
const product = await fetchProduct(id)
---
<html>
<body>
<h1>{product.name}</h1>
<div id="product-data" data-product-id={id} style="display: none;"></div>
<script>
import outlit from '@outlit/browser'
// Track product view
const productId = document.getElementById('product-data')?.dataset.productId
outlit.track('product_viewed', {
productId
})
</script>
</body>
</html>
Content Collections
Track interactions with content:Copy
---
// src/pages/blog/[...slug].astro
import { getEntry } from 'astro:content'
const entry = await getEntry('blog', Astro.params.slug)
---
<article>
<h1>{entry.data.title}</h1>
<div set:html={entry.body} />
<div id="blog-data" data-slug={Astro.params.slug} data-title={entry.data.title} style="display: none;"></div>
</article>
<script>
import outlit from '@outlit/browser'
const blogData = document.getElementById('blog-data')
outlit.track('blog_post_viewed', {
slug: blogData?.dataset.slug,
title: blogData?.dataset.title
})
</script>
Consent Management
Handle user consent:Copy
---
// src/components/CookieBanner.astro
---
<div id="cookie-banner" style="display: none;">
<p>We use cookies to improve your experience.</p>
<button id="accept-btn">Accept</button>
</div>
<script>
import outlit from '@outlit/browser'
// Initialize without auto-tracking
outlit.init({
publicKey: import.meta.env.PUBLIC_OUTLIT_KEY,
autoTrack: false
})
// Check consent
const hasConsent = localStorage.getItem('tracking-consent')
if (hasConsent === 'true') {
outlit.enableTracking()
} else {
document.getElementById('cookie-banner').style.display = 'block'
}
// Handle accept
document.getElementById('accept-btn')?.addEventListener('click', () => {
localStorage.setItem('tracking-consent', 'true')
outlit.enableTracking()
document.getElementById('cookie-banner').style.display = 'none'
})
</script>
<style>
#cookie-banner {
position: fixed;
bottom: 1rem;
left: 1rem;
right: 1rem;
padding: 1rem;
background: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 0.5rem;
}
</style>
Environment Variables
Configure environment variables:Copy
# .env
# Public key (used in browser)
PUBLIC_OUTLIT_KEY=pk_your_public_key_here
# Private key (used in API routes)
OUTLIT_PRIVATE_KEY=sk_your_private_key_here
Never expose your private key in client-side code. Only use it in API routes.
TypeScript Support
Full TypeScript support is included:Copy
import outlit, { type OutlitOptions } from '@outlit/browser'
const options: OutlitOptions = {
publicKey: import.meta.env.PUBLIC_OUTLIT_KEY,
trackPageviews: true,
flushInterval: 5000
}
outlit.init(options)