Automate reporting with the API
Pull stats from Umami programmatically to build custom reports, Slack notifications, email digests, or automated dashboards.
Authentication
Self-hosted
Authenticate with username and password to get a bearer token:
const { token } = await fetch('https://your-umami.example.com/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'admin', password: 'your-password' }),
}).then(r => r.json());Use the token in subsequent requests:
const headers = { Authorization: `Bearer ${token}` };Umami Cloud
Use your API key instead:
const headers = { 'x-umami-api-key': 'your-api-key' };Example: Daily traffic summary
Fetch yesterday's stats and format them for a report:
const websiteId = 'your-website-id';
const now = new Date();
const yesterday = new Date(now);
yesterday.setDate(now.getDate() - 1);
yesterday.setHours(0, 0, 0, 0);
const today = new Date(yesterday);
today.setDate(today.getDate() + 1);
const stats = await fetch(
`https://your-umami.example.com/api/websites/${websiteId}/stats` +
`?startAt=${yesterday.getTime()}&endAt=${today.getTime()}`,
{ headers }
).then(r => r.json());
const report = `
📊 Daily Report — ${yesterday.toDateString()}
Visitors: ${stats.visitors}
Page views: ${stats.pageviews}
Visits: ${stats.visits}
Bounce rate: ${((stats.bounces / stats.visits) * 100).toFixed(1)}%
`;Example: Send to Slack
await fetch('https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: report }),
});Example: Top pages report
const metrics = await fetch(
`https://your-umami.example.com/api/websites/${websiteId}/metrics` +
`?startAt=${yesterday.getTime()}&endAt=${today.getTime()}&type=path`,
{ headers }
).then(r => r.json());
const topPages = metrics
.sort((a, b) => b.y - a.y)
.slice(0, 10)
.map((p, i) => `${i + 1}. ${p.x} — ${p.y} views`)
.join('\n');Example: Weekly comparison
Compare this week vs. last week to detect trends:
const thisWeek = await fetch(
`https://your-umami.example.com/api/websites/${websiteId}/stats` +
`?startAt=${thisWeekStart}&endAt=${thisWeekEnd}`,
{ headers }
).then(r => r.json());
const lastWeek = await fetch(
`https://your-umami.example.com/api/websites/${websiteId}/stats` +
`?startAt=${lastWeekStart}&endAt=${lastWeekEnd}`,
{ headers }
).then(r => r.json());
const change = ((thisWeek.visitors - lastWeek.visitors) / lastWeek.visitors * 100).toFixed(1);
console.log(`Visitors: ${thisWeek.visitors} (${change > 0 ? '+' : ''}${change}% vs last week)`);Running on a schedule
Use a cron job, GitHub Actions, or a serverless function to run your reporting script on a schedule:
Cron (Linux/Mac):
# Run daily at 8am
0 8 * * * node /path/to/daily-report.jsGitHub Actions:
on:
schedule:
- cron: '0 8 * * *'
jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: node scripts/daily-report.jsSee the full API reference for all available endpoints.