Integration Overview
Umami offers extensive integration capabilities through its API, npm packages, hosting options, and framework support. Whether you're self-hosting or using Umami Cloud, these integrations enable seamless connection with your development workflow and tech stack.
Hosting Platforms
Vercel
One-Click Deploy:
Manual Setup:
# Clone repository
git clone https://github.com/umami-software/umami.git
cd umami
# Install dependencies
npm install
# Set environment variables in Vercel dashboard
DATABASE_URL=postgresql://...
HASH_SALT=your-random-salt
# Deploy
vercel deploy
Railway
One-Click Deploy:
# Deploy using Railway CLI
railway up
# Or use Railway button
# https://railway.app/new/template/umami
Environment Variables:
DATABASE_URL=postgresql://...
HASH_SALT=random-string-32-chars
PORT=3000
Netlify
# Install Netlify CLI
npm install -g netlify-cli
# Deploy
netlify deploy --prod
# Configure environment variables in Netlify dashboard
Docker
Docker Compose:
version: '3'
services:
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://umami:umami@db:5432/umami
DATABASE_TYPE: postgresql
HASH_SALT: replace-me-with-a-random-string
depends_on:
- db
restart: always
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: umami
volumes:
- umami-db-data:/var/lib/postgresql/data
restart: always
volumes:
umami-db-data:
Run with Docker Compose:
docker-compose up -d
DigitalOcean
Deploy as a DigitalOcean App:
# Create app.yaml
spec:
name: umami
services:
- name: web
github:
repo: your-username/umami
branch: master
build_command: npm run build
run_command: npm start
envs:
- key: DATABASE_URL
value: ${db.DATABASE_URL}
- key: HASH_SALT
value: your-random-salt
databases:
- name: db
engine: PG
version: "15"
Framework Integrations
Next.js
Installation:
npm install @umami/node
App Router (Next.js 13+):
// app/layout.js
import Script from 'next/script'
export default function RootLayout({ children }) {
return (
<html>
<head>
<Script
async
src="https://cloud.umami.is/script.js"
data-website-id="your-website-id"
strategy="afterInteractive"
/>
</head>
<body>{children}</body>
</html>
)
}
Pages Router:
// pages/_app.js
import Script from 'next/script'
function MyApp({ Component, pageProps }) {
return (
<>
<Script
async
src="https://cloud.umami.is/script.js"
data-website-id="your-website-id"
strategy="afterInteractive"
/>
<Component {...pageProps} />
</>
)
}
Track Events:
'use client'
export default function Component() {
const handleClick = () => {
umami.track('button-click', { location: 'homepage' })
}
return <button Me</button>
}
React
npm install @umami/react
import { UmamiProvider, useUmami } from '@umami/react'
function App() {
return (
<UmamiProvider
websiteId="your-website-id"
src="https://cloud.umami.is/script.js"
>
<YourApp />
</UmamiProvider>
)
}
function Component() {
const umami = useUmami()
const handleEvent = () => {
umami.track('event-name', { property: 'value' })
}
return <button Event</button>
}
Vue.js / Nuxt
Nuxt 3:
// plugins/umami.client.js
export default defineNuxtPlugin(() => {
const script = document.createElement('script')
script.async = true
script.src = 'https://cloud.umami.is/script.js'
script.setAttribute('data-website-id', 'your-website-id')
document.head.appendChild(script)
})
Vue 3 Composition API:
// composables/useUmami.js
export const useUmami = () => {
const track = (event, data) => {
if (typeof window !== 'undefined' && window.umami) {
window.umami.track(event, data)
}
}
return { track }
}
// Usage in component
const { track } = useUmami()
track('button-click', { page: 'home' })
SvelteKit
// src/routes/+layout.svelte
<script>
import { onMount } from 'svelte'
onMount(() => {
const script = document.createElement('script')
script.async = true
script.src = 'https://cloud.umami.is/script.js'
script.dataset.websiteId = 'your-website-id'
document.head.appendChild(script)
})
</script>
<!-- Track events -->
<button on:click={() => umami.track('click')}>
Track Click
</button>
Gatsby
npm install gatsby-plugin-umami
// gatsby-config.js
module.exports = {
plugins: [
{
resolve: 'gatsby-plugin-umami',
options: {
websiteId: 'your-website-id',
srcUrl: 'https://cloud.umami.is/script.js',
includeInDevelopment: false,
autoTrack: true,
respectDoNotTrack: true
}
}
]
}
Content Management Systems
WordPress
Manual Installation:
// Add to theme's functions.php or use Code Snippets plugin
function add_umami_tracking() {
?>
<script async
src="https://cloud.umami.is/script.js"
data-website-id="your-website-id">
</script>
<?php
}
add_action('wp_head', 'add_umami_tracking');
Using Plugin:
Search for "Umami Analytics" in WordPress plugin directory and install.
Ghost
// Settings > Code Injection > Site Header
<script async
src="https://cloud.umami.is/script.js"
data-website-id="your-website-id">
</script>
Webflow
- Go to Project Settings > Custom Code
- Add to Head Code:
<script async
src="https://cloud.umami.is/script.js"
data-website-id="your-website-id">
</script>
API Integration
Authentication
# Get API token
curl -X POST https://your-umami.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-password"}'
# Response includes token
{"token":"your-api-token"}
Fetch Website Stats
# Get website statistics
curl "https://your-umami.com/api/websites/WEBSITE_ID/stats?startAt=1640000000000&endAt=1672000000000" \
-H "Authorization: Bearer YOUR_TOKEN"
Get Events
# Fetch events data
curl "https://your-umami.com/api/websites/WEBSITE_ID/events?startAt=1640000000000&endAt=1672000000000" \
-H "Authorization: Bearer YOUR_TOKEN"
Node.js SDK
npm install @umami/node
const { UmamiClient } = require('@umami/node')
const client = new UmamiClient({
apiUrl: 'https://your-umami.com',
token: 'YOUR_API_TOKEN'
})
// Get website stats
const stats = await client.getWebsiteStats(websiteId, {
startAt: Date.now() - 7 * 24 * 60 * 60 * 1000, // 7 days ago
endAt: Date.now()
})
// Get active users
const activeUsers = await client.getActiveUsers(websiteId)
// Get events
const events = await client.getEvents(websiteId, {
startAt: Date.now() - 24 * 60 * 60 * 1000 // 24 hours
})
Database Integrations
PostgreSQL
# Connection string format
DATABASE_URL=postgresql://username:password@host:5432/database
# With SSL
DATABASE_URL=postgresql://username:password@host:5432/database?sslmode=require
MySQL
# Connection string format
DATABASE_URL=mysql://username:password@host:3306/database
# With SSL
DATABASE_URL=mysql://username:password@host:3306/database?ssl={"rejectUnauthorized":true}
Automation and Webhooks
Zapier Integration
Create custom Zapier integration using webhooks:
- Set up webhook trigger in Zapier
- Configure Umami to send event data to webhook URL
- Connect to 5000+ apps via Zapier
Custom Webhooks
// Send events to external webhook
async function sendToWebhook(event, data) {
await fetch('https://your-webhook.com/endpoint', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event: event,
data: data,
timestamp: new Date().toISOString()
})
})
// Also track in Umami
umami.track(event, data)
}
Data Export and Reporting
CSV Export
// Export data programmatically
const stats = await client.getWebsiteStats(websiteId, dateRange)
const csv = convertToCSV(stats)
fs.writeFileSync('analytics-report.csv', csv)
Google Sheets Integration
Use Google Apps Script to pull Umami data:
function importUmamiData() {
const response = UrlFetchApp.fetch(
'https://your-umami.com/api/websites/ID/stats',
{
headers: { 'Authorization': 'Bearer TOKEN' }
}
)
const data = JSON.parse(response.getContentText())
// Write to Google Sheet
const sheet = SpreadsheetApp.getActiveSheet()
sheet.getRange(1, 1).setValue(data.pageviews)
}
Reverse Proxy Setup
Nginx
server {
listen 80;
server_name analytics.yourdomain.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Apache
<VirtualHost *:80>
ServerName analytics.yourdomain.com
ProxyPreserveHost On
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
</VirtualHost>