Umami is an open-source, privacy-friendly web analytics tool. Compared to Google Analytics, Umami doesn’t use cookies, doesn’t track users across sites, and is fully GDPR compliant. This guide will show you how to deploy Umami for free using Vercel + Neon PostgreSQL and integrate it with your astro-minimax blog.
Why Choose Umami
| Feature | Umami | Google Analytics |
|---|---|---|
| Privacy-friendly | Fully GDPR compliant | Requires cookie consent |
| Self-hosted | Supported | Not supported |
| Data ownership | Full control | Google holds data |
| Cookie usage | None | Required |
| Page size impact | Minimal (< 2KB) | Larger |
| Open source | MIT license | Closed source |
Deployment Options Comparison
| Option | Cost | Advantages | Disadvantages |
|---|---|---|---|
| Vercel + Neon (Recommended) | Free | Zero ops, one-click deploy, auto updates | Vercel free tier limits |
| Self-hosted Docker | Free | Full control, unlimited | Requires server, self-maintenance |
| Umami Cloud | Paid | No ops, auto updates | From $9/month |
Recommended: Vercel + Neon - Completely free, no server needed, simple deployment, suitable for personal blogs and small websites.
Option A: Vercel + Neon Deployment (Recommended)
Host Umami on Vercel with Neon PostgreSQL database from Vercel Storage for zero-cost deployment.
Prerequisites
- GitHub account
- Vercel account (login with GitHub)
- Neon account (auto-linked via Vercel Storage)
Step 1: Fork Umami Repository
- Visit Umami GitHub Repository
- Click Fork button in the top right to fork the repository to your account
Step 2: Deploy Umami on Vercel
- Login to Vercel Dashboard
- Click Add New → Project
- Select your forked
umamirepository - Configure the project:
- Framework Preset: Select
Next.js - Environment Variables: Skip for now, configure later
- Framework Preset: Select
- Click Deploy to start deployment
First deployment may fail (missing database connection). This is normal - redeploy after configuring the database in the next step.
Step 3: Create Neon PostgreSQL Database
- In Vercel Dashboard, go to your Umami project
- Click Storage tab at the top
- Click Create Database
- Select Neon PostgreSQL as database type
- Login to Neon account to authorize (if not linked)
- Configure the database:
- Project Name: e.g.,
umami-analytics - Database Name: Recommended
umami - Region: Choose closest to your users
- Project Name: e.g.,
- Click Create to create the database
Once created, Vercel will automatically inject the DATABASE_URL environment variable into the project.
Step 4: Redeploy
- Go to Deployments tab
- Select the latest deployment
- Click Redeploy to redeploy
- Wait for deployment to complete (~1-2 minutes)
DATABASE_URLis the only required environment variable.APP_SECRET(for session encryption) is now optional - Umami will auto-generate it.
Step 5: Initialize Umami
- After successful deployment, click Visit to access your Umami instance
- First login with default credentials:
- Username:
admin - Password:
umami
- Username:
- Change default password immediately: Click avatar in top right → Profile → Change Password
Step 6: Bind Custom Domain (Optional)
- Project → Settings → Domains
- Enter your domain, e.g.,
umami.yourdomain.com - Add CNAME record in your DNS pointing to
cname.vercel-dns.com - Wait for DNS propagation
Option B: Self-Hosted Docker Deployment
If you have server resources and want full control over data, use Docker for self-hosted deployment.
Quick Deploy
Create docker-compose.yml file:
services:
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
container_name: umami
restart: unless-stopped
ports:
- "3001:3000"
environment:
DATABASE_URL: postgresql://umami:umami@db:5432/umami
depends_on:
- db
db:
image: postgres:15-alpine
container_name: umami-db
restart: unless-stopped
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: umami
volumes:
- umami-db-data:/var/lib/postgresql/data
volumes:
umami-db-data:yaml
DATABASE_URLis the only required environment variable.APP_SECRET(for session encryption) is optional - Umami will auto-generate it.
Start the service:
docker compose up -dbashService will start at http://localhost:3001. Default admin credentials:
- Username:
admin - Password:
umami
Change default password immediately after first login.
Production Configuration
Reverse Proxy Configuration
Recommended to use Nginx or Caddy as reverse proxy with HTTPS:
Nginx Example:
server {
listen 443 ssl http2;
server_name umami.your-domain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://127.0.0.1:3001;
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;
}
}nginxCaddy Example (Simpler):
umami.your-domain.com {
reverse_proxy localhost:3001
}plaintextCaddy automatically requests and renews HTTPS certificates.
Environment Variables
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string |
APP_SECRET | No | Session encryption, auto-generated |
TRACKER_SCRIPT_NAME | No | Tracker script filename, default script.js |
DISABLE_TELEMETRY | No | Disable telemetry, set to 1 |
REMOVE_TRAILING_SLASH | No | Remove trailing slash from URLs, set to 1 |
PostgreSQL Optimization
For production, adjust PostgreSQL configuration:
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: your-secure-password-here
volumes:
- umami-db-data:/var/lib/postgresql/data
command: postgres -c shared_buffers=256MB -c max_connections=200yamlData Backup
Backup PostgreSQL data regularly:
# Backup
docker exec umami-db pg_dump -U umami umami > umami_backup_$(date +%Y%m%d).sql
# Restore
cat umami_backup_20260318.sql | docker exec -i umami-db psql -U umami umamibashOption C: Umami Cloud
If you don’t want to manage operations, use Umami Cloud hosted service.
Pricing
| Plan | Monthly | Websites | Pageviews |
|---|---|---|---|
| Pro | $9 | 10 | 100,000/month |
| Business | $19 | 25 | 500,000/month |
| Enterprise | Custom | Unlimited | Custom |
Usage Steps
- Register for Umami Cloud account
- Login and go to Dashboard
- Click Add website to add your website
- Get
websiteIdand script URL
Get Website ID
Regardless of which option you use, you need to get the websiteId for blog integration.
Steps
- Login to Umami dashboard
- Click Settings → Websites in top right
- Click Add website to add your site:
- Name: Your blog name
- Domain: Your blog domain (e.g.,
blog.example.com)
- After adding, click the website name to view details
- In Tracking code section you’ll see:
data-website-id: This is yourwebsiteId- Script URL: e.g.,
https://your-umami-instance/script.js
Example tracking code:
<script async src="https://umami.example.com/script.js" data-website-id="1419a8ae-a14b-4bb7-8c39-ee5fe00a8a88"></script>htmlExtract from the code above:
websiteId:1419a8ae-a14b-4bb7-8c39-ee5fe00a8a88src:https://umami.example.com/script.js
Integrate with Blog
Configure Umami in src/config.ts:
umami: {
enabled: true,
websiteId: "1419a8ae-a14b-4bb7-8c39-ee5fe00a8a88",
src: "https://umami.example.com/script.js",
},js| Option | Description |
|---|---|
enabled | Enable analytics. Script auto-injected when true |
websiteId | Website ID from Umami dashboard |
src | Umami tracker script URL. Use your domain for self-hosted, https://cloud.umami.is/script.js for cloud |
After configuration, rebuild and deploy your blog:
pnpm run buildbashVerify Integration
After deployment, open browser developer tools:
- Check Network tab for requests to your Umami service
- Check Realtime page in Umami dashboard to confirm visit records
Environment Variables Reference
If you don’t want to commit websiteId to the repository, use environment variables:
Method 1: Build-time Environment Variables
Add in your deployment platform’s build configuration:
UMAMI_WEBSITE_ID=your-website-id
UMAMI_SRC=https://umami.example.com/script.jsbashModify src/config.ts:
umami: {
enabled: true,
websiteId: import.meta.env.UMAMI_WEBSITE_ID || "your-website-id",
src: import.meta.env.UMAMI_SRC || "https://umami.example.com/script.js",
},jsMethod 2: Use .env File
Create .env file (add to .gitignore):
UMAMI_WEBSITE_ID=your-website-id
UMAMI_SRC=https://umami.example.com/script.jsbashPrivacy Compliance
Umami was designed with privacy compliance in mind:
GDPR Compliance
- No Cookies: Umami doesn’t rely on cookies for tracking
- No Cross-site Tracking: Data limited to your website
- Data Minimization: Only collects necessary statistics
- Data Ownership: With self-hosting, you own all data
Privacy Policy Suggestion
Declare Umami usage in your privacy policy:
This website uses Umami for analytics. Umami does not use cookies, does not track personal information, and all data is used solely to improve website experience.
User Opt-out
Umami supports user opt-out from tracking. Add an opt-out link:
<a href="#" data-umami-track="false">Opt out of tracking</a>htmlOr via JavaScript:
window.umami.trackView = false;jsTroubleshooting
Statistics Not Displaying
- Check script loading: In browser developer tools Network tab, confirm
script.jsloads successfully - Check domain configuration: Ensure domain in Umami matches actual blog domain
- Check CSP policy: If using Content Security Policy, allow Umami script domain
Vercel Deployment Failed
- Check environment variables: Confirm
DATABASE_URLandAPP_SECRETare correctly configured - Check database status: In Vercel Storage, confirm Neon database is created
- View build logs: Check Deployments page for detailed error messages
Neon Database Connection Issues
- Database suspended: Neon free tier suspends after idle, first access needs wake-up (~5-10 seconds)
- SSL connection: Neon requires SSL, ensure connection string includes
?sslmode=require - Connection timeout: Check region settings, choose closest region for lower latency
Docker Self-hosted Won’t Start
- Check database connection: Ensure PostgreSQL container is running
- Check logs: Run
docker logs umamito view error messages - Check port: Ensure port 3001 is not occupied
CORS Issues
If Umami and blog are on different domains, configure CORS:
Vercel deployment: Add environment variable:
CORS_ALLOWED_ORIGINS=https://your-blog-domain.complaintextDocker deployment: Add to docker-compose.yml:
environment:
# ... other config
CORS_ALLOWED_ORIGINS: https://your-blog-domain.comyamlInaccurate Statistics
Umami uses fingerprinting to identify users. These situations may cause statistical bias:
- Users disable JavaScript
- Users use privacy browsers (e.g., Tor)
- Users use ad blockers
Next Steps
After configuring Umami:
- Configure Waline Comment System - Add article interaction
- Configure AI Chat Assistant - Enhance user experience
- Deploy Blog to Cloudflare Pages - Enjoy global CDN acceleration
For more Umami features, refer to Umami Documentation.
评论区
文明评论,共建和谐社区