10 KiB
Umami Website Creation Fix
Problem
The Umami tracking website creation was not working properly because:
- The auto-creation wasn't being triggered during initial setup
- No frontend UI existed to manually trigger website creation if needed
Solution
Automatic Creation During Setup
The initial setup process now automatically creates the Umami website:
- When you complete the setup wizard, it fetches
/umami/config - Backend detects that UMAMI credentials are in
.envbut no UMAMI_WEBSITE_ID exists - Backend automatically creates the website using the domain from your site
- Analytics tracking starts working immediately
Manual Creation (Backup Option)
Added a new "Umami Analytics" tab to the Settings Admin Page that allows:
- Viewing current Umami configuration status
- Manually creating a new Umami website with custom name and domain
- Refreshing the Umami configuration
Changes Made
Frontend Changes
File: frontend/src/pages/SetupPage.tsx
Added automatic Umami initialization during setup:
// Step 3: Initialize Umami Analytics (auto-create website)
setSetupProgress('Konfiguruji analytiku...');
try {
// Trigger Umami config fetch - backend will auto-create website if credentials are present
const axios = (await import('axios')).default;
const apiUrl = (API_URL || '').replace(/\/$/, '');
await axios.get(`${apiUrl}/umami/config`);
console.log('Umami analytics initialized');
} catch (err) {
console.warn('Umami initialization failed (non-critical):', err);
}
File: frontend/src/pages/admin/SettingsAdminPage.tsx
-
Added new imports:
import api from '../../services/api';
-
Added new state variables:
const [umamiWebsiteId, setUmamiWebsiteId] = useState<string>(''); const [umamiDomain, setUmamiDomain] = useState<string>(''); const [umamiName, setUmamiName] = useState<string>(''); const [umamiInitializing, setUmamiInitializing] = useState<boolean>(false); const [umamiConfig, setUmamiConfig] = useState<any>(null); -
Added
fetchUmamiConfig()function to load current Umami status -
Added "Umami Analytics" tab to the settings page with:
- Status indicator (green for active, yellow for not configured)
- Form fields for website name and domain
- "Create Website" button that calls
/admin/umami/initialize - "Refresh Status" button to reload configuration
Backend API
Authentication with Token Verification
File: internal/services/umami_service.go
The backend implements smart token management:
-
Initial Authentication (
POST /api/auth/login)- Sends username and password in JSON format (from
.env) - Receives JWT token with 24-hour expiration
- Stores token with expiration timestamp
- Sends username and password in JSON format (from
-
Token Verification (twice daily - every 12 hours)
- Uses
POST /api/auth/verifyendpoint - Checks if existing token is still valid
- Only re-authenticates if verification fails
- Reduces unnecessary login requests
- Uses
-
Automatic Re-authentication
- If token expires or verification fails
- Automatically gets a new token
- Seamless for the application
Token Lifecycle:
Initial: Login → Get Token (valid 24h)
After 12h: Verify Token → Still valid? Continue using it
After 24h: Token expired → Re-authenticate → Get new token
All API calls use: Authorization: Bearer <token> header
Website Creation Endpoint
Endpoint: POST /admin/umami/initialize
File: internal/controllers/umami_controller.go
Request body:
{
"name": "Your Club Name",
"domain": "yourclub.example.com"
}
Response (success):
{
"message": "Umami initialized successfully",
"website_id": "abc123-def456-...",
"script_url": "https://umami.tdvorak.dev/script.js"
}
Testing Instructions
1. Verify Environment Variables
Your .env file already has the correct credentials (they don't change):
UMAMI_URL=https://umami.tdvorak.dev
UMAMI_USERNAME=admin
UMAMI_PASSWORD=eevRQ6h3G@!c#y4A1T
UMAMI_WEBSITE_ID= # Leave empty - will be auto-created during setup
Important: These credentials are permanent and don't need to be modified.
2. Run Initial Setup
- Navigate to
/setuproute - Complete the setup wizard (club info, admin account, etc.)
- During setup, you'll see: "Konfiguruji analytiku..." (Configuring analytics)
- Backend automatically creates Umami website using your domain
- Setup completes and analytics are ready!
3. Verify Umami is Working
After setup, check the analytics:
- Login to admin panel
- Navigate to Settings → Umami Analytics tab
- You should see green status: "✓ Umami je aktivní"
- Website ID should be displayed
4. Manual Creation (If Needed)
If auto-creation didn't work during setup, you can manually create:
- Navigate to Settings → Umami Analytics tab
- Fill in the form:
- Name: Your club name
- Domain: Your website domain
- Click "Vytvořit webovou stránku" (Create Website)
- Success message will show the Website ID
4. Verify via API (PowerShell)
You can also verify directly with PowerShell:
# Login to get token
$body = @{
username = "admin"
password = "eevRQ6h3G@!c#y4A1T"
} | ConvertTo-Json
$response = Invoke-RestMethod -Uri "https://umami.tdvorak.dev/api/auth/login" `
-Method Post `
-ContentType "application/json" `
-Body $body
$token = $response.token
Write-Output "Token: $token"
# List websites to verify creation
$headers = @{
Authorization = "Bearer $token"
}
$websites = Invoke-RestMethod -Uri "https://umami.tdvorak.dev/api/websites" `
-Headers $headers `
-Method Get
$websites.data
5. Website ID Persistence
The Website ID is stored in-memory by the backend after auto-creation. To make it permanent across server restarts:
Option 1: Let it auto-create on each restart (Recommended)
- Leave
UMAMI_WEBSITE_ID=empty in.env - Backend checks if website exists and reuses it (or creates new one if missing)
- Works seamlessly
Option 2: Store Website ID in .env
- Copy the Website ID from Settings → Umami Analytics tab
- Add to
.env:UMAMI_WEBSITE_ID=abc123-def456-... - Restart backend server
- Backend will use this ID directly without checking/creating
How It Works
Frontend Flow
- User opens Settings → Umami Analytics tab
fetchUmamiConfig()is called on page load- Backend checks if
UMAMI_WEBSITE_IDis set - If not set and credentials are available, backend may auto-create on first request
- User can manually create via the UI by clicking "Create Website"
- Frontend calls
POST /admin/umami/initializewith name and domain - Backend authenticates with Umami and creates the website
- Backend returns the Website ID
- Frontend displays success and refreshes the configuration
Backend Flow
- Receives request at
/admin/umami/initialize - Validates request payload (name and domain required)
- Calls
umamiService.authenticate():- POST to Umami
https://umami.tdvorak.dev/api/auth/login - Payload:
{"username": "admin", "password": "..."} - Receives JWT token
- POST to Umami
- Calls
umamiService.EnsureWebsite():- First checks if website exists: GET
/api/websites?query={domain} - If exists, returns existing ID
- If not, creates new website: POST
/api/websites - Payload:
{"name": "...", "domain": "..."} - Authorization header:
Bearer {token}
- First checks if website exists: GET
- Updates in-memory config with Website ID
- Returns success response to frontend
Troubleshooting
Error: "authentication failed"
- Check UMAMI_USERNAME and UMAMI_PASSWORD in
.env - Verify credentials work by testing with PowerShell script above
Error: "create website failed"
- Check if website already exists (list via PowerShell)
- Verify token has correct permissions
- Check Umami server logs
Website ID not persisting
- The Website ID is stored in memory only
- Update
.envwithUMAMI_WEBSITE_ID=...for persistence - Restart backend server after updating
.env
Additional Notes
- The backend automatically tries to create a website on first request to
/umami/configif credentials are set - In production, it only auto-creates for non-localhost domains
- In development, it allows localhost
- The manual UI provides explicit control over website creation
- You can create multiple websites for different domains if needed
Umami v2 Compatibility Update (Latest Fix)
Problem with Umami v2
In Umami v2, when users are part of teams, creating a website may require specifying a teamId. Without this parameter, the website creation request could fail.
Solution Implemented
Updated CreateWebsite() method in umami_service.go to:
- Fetch current user information via
POST /api/auth/verify - Retrieve user's teams via
GET /api/users/:userId/teams - Automatically use the first available team when creating a website
- Gracefully degrade if teams cannot be fetched (continues without teamId)
New Methods Added
// GetCurrentUser - Retrieves authenticated user info from Umami
func (u *UmamiService) GetCurrentUser() (map[string]interface{}, error)
// GetUserTeams - Retrieves user's teams from Umami
func (u *UmamiService) GetUserTeams(userID string) ([]UmamiTeam, error)
Updated CreateWebsite Flow
1. Authenticate with Umami
2. Get current user info (to obtain user ID)
3. Fetch user's teams (if user has teams)
4. Prepare website creation request with:
- name: Website name
- domain: Website domain
- teamId: First available team ID (optional)
5. Send POST /api/websites with Authorization Bearer token
6. Return website ID on success
Enhanced Error Logging
All error messages now include detailed response bodies from Umami API for easier debugging:
- Authentication failures show full error response
- Website creation errors display Umami's error message
- Team fetch failures log warnings but don't block website creation
Testing the Fix
To verify the fix works:
-
Check backend logs during website creation - you should see:
Creating Umami website: name='...', domain='...' Using team ID: xxx-xxx-xxx (team name: ...) Sending website creation request to Umami API: https://umami.tdvorak.dev/api/websites Successfully created Umami website: ... (ID: xxx, Domain: ...) -
If teams aren't available, you'll see:
Failed to fetch user teams (continuing without team): ... Successfully created Umami website: ... (ID: xxx, Domain: ...) -
Monitor for creation errors - detailed error messages will help diagnose issues
This update ensures compatibility with both Umami v1 (no teams) and Umami v2 (with teams).