paxalia-dashboard
A complete, self‑hosted analytics platform for Django, from Paxalia. Drop it into any Django project and get a beautiful, full‑featured analytics dashboard with zero third‑party services.
Table of Contents
- Why paxalia-dashboard?
- Features
- Tech Stack
- Installation
- Configuration
- Dashboard Pages
- Server Monitoring
- Bot Traffic
- Backup Management
- Admin Overview
- Custom Event Tracking
- Real User Monitoring
- Uptime Monitoring
- Compliance
- Data Import
- Slack/Discord App
- Internationalization
- Themes
- Exporting Data
- Billing Integration
- Project Structure
- Contributing
- License
- Security Center
- Advanced Analytics
- Reporting & Sharing
- Paxalia API
- Dependency Health
- Notifications & Alerts
- Multi-Site Analytics
- Release Center
- Operational Commands
- Security & Privacy Model
- Credits
Why paxalia-dashboard
paxalia-dashboard is designed as a privacy-first, self-hosted analytics and operational observability layer for Django
applications. It is broader than a simple page-view counter: the v3 platform combines product analytics, behavioral
analysis, security visibility, server/runtime monitoring, uptime checks, release/deployment context, compliance tooling,
reporting, sharing, API access, and operational utilities in one Django-native package.
The comparison below keeps the original high-level positioning while making the breadth of the current platform explicit. Availability of features from competing products varies by product tier, plan, add-on, or deployment configuration.
| Capability | Google Analytics | Typical lightweight Django analytics package | paxalia-dashboard |
|---|---|---|---|
| Self-hosted | ❌ | ✅ | ✅ |
| First-party data storage | ❌ | ✅ | ✅ |
| No required third-party analytics collector | ❌ | ✅ | ✅ |
| Django-native integration | ❌ | ✅ | ✅ |
| Page views & sessions | ✅ | ✅ | ✅ |
| Date-range analysis | ✅ | ✅ | ✅ |
| Previous-period comparison | ✅ | Varies | ✅ |
| Traffic sources / referrers | ✅ | Varies | ✅ |
| Browser / OS / device breakdown | ✅ | Varies | ✅ |
| Offline GeoIP world map | ❌ | Rare | ✅ |
| Country and city drill-down | ✅ | Rare | ✅ |
| Custom events | ✅ | Varies | ✅ |
| API traffic separation | Varies | Rare | ✅ |
| API endpoint analytics | Varies | Rare | ✅ |
| Real-time visitor monitoring | ✅ | Rare | ✅ |
| Broken-link analysis | Varies | Rare | ✅ |
| Bot traffic classification | Varies | Rare | ✅ |
| Search-engine crawler classification | Varies | Rare | ✅ |
| AI crawler classification | Varies | Rare | ✅ |
| Social-preview bot classification | Varies | Rare | ✅ |
| Malicious/scanner classification | Varies | Rare | ✅ |
| Goals | ✅ | Rare | ✅ |
| Funnel analysis | ✅ | Rare | ✅ |
| Behavioral segments | ✅ | Rare | ✅ |
| Campaign / UTM analysis | ✅ | Rare | ✅ |
| Cohort retention | ✅ | Rare | ✅ |
| Chart annotations | Varies | Rare | ✅ |
| Core Web Vitals / RUM | ✅ | Rare | ✅ |
| JavaScript error tracking | ✅ | Rare | ✅ |
| Scheduled uptime checks | Varies | Rare | ✅ |
| Incident history | Varies | Rare | ✅ |
| Server CPU monitoring | ❌ | ❌ | ✅ |
| Server memory monitoring | ❌ | ❌ | ✅ |
| Server disk monitoring | ❌ | ❌ | ✅ |
| Server network monitoring | ❌ | ❌ | ✅ |
| System service monitoring | ❌ | ❌ | ✅ |
| Process monitoring | ❌ | ❌ | ✅ |
| Slow-query monitoring | ❌ | ❌ | ✅ |
| Celery queue monitoring | ❌ | ❌ | ✅ |
| Deployment tracking | ❌ | ❌ | ✅ |
| Security Center | ❌ | Rare | ✅ |
| Login activity monitoring | Varies | Rare | ✅ |
| Active-session visibility | Varies | Rare | ✅ |
| IP blocklist | ❌ | ❌ | ✅ |
| CSP violation reporting | ❌ | Rare | ✅ |
| Security scorecard | ❌ | ❌ | ✅ |
| Dependency health | ❌ | ❌ | ✅ |
| MFA / 2FA dashboard integration | Varies | Rare | ✅ |
| Consent mode | Varies | Rare | ✅ |
| Data-retention controls | Varies | Rare | ✅ |
| Forget-this-visitor deletion | Varies | Rare | ✅ |
| Historical GA/Plausible import | Varies | Rare | ✅ |
| Scheduled email reports | Varies | Rare | ✅ |
| PDF report delivery | Varies | Rare | ✅ |
| Public read-only share links | Varies | Rare | ✅ |
| Scoped read API keys | ✅ | Rare | ✅ |
| Documented API reference | ✅ | Rare | ✅ |
| Slack / Discord command surface | Varies | Rare | ✅ |
| Backup management | ❌ | ❌ | ✅ |
| Chunked upload/download support | ❌ | ❌ | ✅ |
| Multi-site analytics | Varies | Rare | ✅ |
| Five-language UI + RTL support | Varies | Rare | ✅ |
| Bundled/offline charts and map assets | ❌ | Rare | ✅ |
The goal is not to replace every capability of a large analytics suite. The goal is to give a Django team a single, inspectable, self-hosted operational analytics surface where product analytics and application/server context can live together without making third-party analytics infrastructure mandatory.
Features
- Page Views & Sessions – track every page visit, session duration, bounce rate, pages per session, all anonymised.
- Traffic Sources – see referrers, browsers, operating systems, and device types.
- IP Geolocation – a beautiful offline world map with drill‑down to cities; uses the free GeoLite2 database.
- Custom Events – add a one‑line JavaScript snippet to your site and track any user interaction (button clicks, form submits, video plays, downloads).
- Billing Dashboard – (optional) plug into your billing app to see daily revenue, top plans, and recent transactions.
- Real‑time Monitoring – watch visitors arrive live with a configurable refresh interval.
- Server Monitoring – real‑time system metrics: CPU, memory, disk, network, services, processes – all directly from your server, no external agents.
- Bot Traffic Detection – automatically identify and separate scanner/malicious traffic and known crawlers (search engines, AI crawlers, social-preview bots, SEO tools) from real user visits; view them broken out by category on a dedicated Bots page with its own analytics.
- Backup Management – configure paths to back up, set a schedule, and create/restore backups from the dashboard. Chunked download for large archives.
- Admin Overview – a dedicated dashboard for administrators showing user registrations, content creation, and login activity.
- About Page – learn the story behind the project and support its development.
- Date Range Filter – any chart or table can be filtered by a custom date range with one‑click presets.
- Compare to Previous Period – overlay the previous period on any line chart with a single checkbox.
- CSV / JSON Export – every table has a download button; data respects the current date filter.
- 12 Luxury Themes – from Dark Gold to Onyx Pearl; switch themes instantly, no page reload.
- Multi‑language & RTL – English, Spanish, Arabic, Simplified Chinese, Brazilian Portuguese; Arabic flips the dashboard to right‑to‑left.
- Fully Responsive – works on desktop, tablet, and mobile; sidebar collapses to an overlay on small screens.
- Configurable – enable only the sections you need, change API paths, swap billing models, all from a single
PAXALIA_DASHBOARDdict. - Configurable Data Handling – IP address storage (raw by default, or SHA256-hashed if you turn on anonymization), and the anonymous session cookie, are both configurable in Settings; all data stays on your server regardless.
- Goals, Funnels & Segments – define conversion goals, multi-step funnels, and reusable behavioral segments for deeper product analysis.
- Campaign & UTM Analysis – capture campaign parameters and compare traffic and conversion behavior by campaign source, medium, and campaign.
- Cohort Retention – analyze visitor retention cohorts over time instead of looking only at aggregate traffic.
- Chart Annotations – mark deployments, campaigns, incidents, and other important dates directly on the analytics timeline.
- Broken Links – identify paths returning 404 responses, their frequency, and referring pages when available.
- Real User Monitoring (RUM) – collect LCP, CLS, and INP field data plus browser-side JavaScript errors without a separate tracking product.
- Uptime Monitoring – schedule HTTP checks, track status history, and keep transition-based incident records.
- Security Center – inspect login activity, active sessions, IP blocklists, audit/security signals, CSP violations, and security posture.
- Security Scorecard – surface security findings and configuration posture in one dashboard.
- Dependency Health – inspect the package's direct/transitive runtime dependency closure and progressively compare installed versions with upstream releases.
- Compliance Controls – optional consent gating, configurable retention periods, and visitor-deletion tooling.
- Reporting & Sharing – schedule report delivery and create protected public share links for selected dashboard views.
- Paxalia API – use scoped API keys for ingestion and read access to summaries, page views, and events.
- Slack / Discord Commands – query high-level analytics summaries from supported chat platforms.
- Historical Data Import – import aggregate GA/Plausible CSV history without requiring OAuth credentials or vendor-specific API clients.
- Multi-site Analytics – track multiple configured domains/sites within one dashboard and filter analytics by site.
- Release Center – manage release artifacts and connect deployment activity with analytics annotations.
- Server Operations – monitor CPU, memory, disk, network, services, processes, slow queries, Celery queues, and deployments directly from the host.
- Operational Automation – management commands cover aggregation, anomaly detection, backups, cleanup, retention, deployment tracking, server snapshots, uptime checks, and scheduled reports.
- Self‑Contained – no external CDN calls for maps, charts, or fonts – everything is bundled.
Tech Stack
| Component | Technology |
|---|---|
| Backend | Django 5.0+, Python 3.10+ |
| Database | Any Django‑supported database (SQLite, PostgreSQL) |
| Charts | Chart.js (bundled, no CDN) |
| World Map | Datamaps + D3.js + TopoJSON (bundled, offline) |
| GeoIP | MaxMind GeoLite2‑City (offline database) + geoip2 |
| User‑Agent Parsing | user‑agents (optional, bundled fallback) |
| Country Codes | pycountry |
| Server Metrics | psutil |
Installation
1. Install the package
pip install paxalia-dashboard
2. Add to INSTALLED_APPS
INSTALLED_APPS = [
# ...
'paxalia',
]
3. Include the URLs
The dashboard is mounted at a secret path of your choice. The event API is mounted at a fixed public path (hardcoded in JavaScript). This keeps your dashboard URL hidden while allowing the event tracking to work.
In your project’s root urls.py:
from django.urls import path, include
from django.views.i18n import set_language
from paxalia.views.events import analytics_event_api
# Choose a secret path for your dashboard
DASHBOARD_URL = 'insights/' # or a random string
urlpatterns = [
# ...
# Public event API (hardcoded path, matches JavaScript)
path('api/paxalia/event/', analytics_event_api, name='event_api'),
# Secret dashboard (everything else)
path(DASHBOARD_URL, include('paxalia.urls')),
# Required for language switching
path('i18n/setlang/', set_language, name='set_language'),
]
4. Add the analytics middleware
In settings.py, add paxalia.middleware.AnalyticsMiddleware to the bottom of MIDDLEWARE:
MIDDLEWARE = [
# ...
'paxalia.middleware.AnalyticsMiddleware',
]
This middleware automatically logs every page visit. Without it, no data will appear in the dashboard.
5. Run migrations
python manage.py migrate paxalia
Note: The package includes a clean
0001_initial.pymigration. If you're upgrading from an older version, you should runpython manage.py migrate paxaliato apply the latest schema. The migration is database-agnostic and works with SQLite, PostgreSQL, MySQL, and others.
6. Update your base.html for CSP compliance
The package uses nonce attributes on all <script> tags to comply with strict Content Security Policies. To enable
this:
- Add the CSP context processors to your
settings.py:
TEMPLATES = [
{
'OPTIONS': {
'context_processors': [
# ...
'paxalia.context_processors.analytics_config',
'csp.context_processors.nonce',
],
},
},
]
- Add the CSP middleware (if not already present):
MIDDLEWARE = [
# ...
'csp.middleware.CSPMiddleware',
]
- Configure CSP in
settings.pywithNONCEand'strict-dynamic':
from csp.constants import NONCE
CONTENT_SECURITY_POLICY = {
'DIRECTIVES': {
'default-src': ("'self'",),
'script-src': (
"'self'",
NONCE,
"'strict-dynamic'",
),
# ... other directives
}
}
- Add the nonce to external scripts in your own templates:
< script
nonce = "{{ request.csp_nonce }}"
src = "{% static 'paxalia/scripts/paxalia-events.js' %}" > < / script >
7. Compile translations (optional)
python manage.py compilemessages -l es -l ar -l zh-hans -l pt-br
8. Download the GeoIP database (required for the geography page)
Download GeoLite2‑City.mmdb (free) from MaxMind and place it in the directory specified by GEOIP_PATH (default: paxalia/geoip/ inside the package).
9. Start the server
python manage.py runserver
Visit http://127.0.0.1:8000/insights/ – your analytics dashboard is live.
Additional management commands
The package includes several management commands to help with daily operations:
# Aggregate yesterday's stats (run daily via cron)
python manage.py aggregate_daily_stats
# Seed the database with dummy data for testing
python manage.py seed_analytics
# Import a list of bot paths from a text file
python manage.py import_bot_paths /path/to/bot_paths.txt
# Create a backup (called by the backup system or cron)
python manage.py create_backup
Configuration
All dashboard behavior is configured through a single PAXALIA_DASHBOARD dictionary in the host project's
settings.py. The package reads this dictionary, merges it with its built-in defaults, and keeps optional integrations
disabled unless you explicitly enable/configure them.
The complete current configuration surface is:
PAXALIA_DASHBOARD = {
# ── Navigation ───────────────────────────────────────────────
'SIDEBAR_SECTIONS': [
'overview', 'pages', 'api', 'traffic', 'realtime', 'bots',
'geography', 'events', 'billing', 'releases', 'backups', 'security',
'sites', 'broken_links', 'goals', 'funnels', 'segments', 'campaigns',
'annotations', 'cohorts', 'api_keys', 'reports', 'share_links',
'notifications', 'rum', 'uptime', 'compliance', 'data_import', 'settings',
],
# ── Analytics / GeoIP ───────────────────────────────────────
'API_PATH_PREFIX': '/api/',
'GEOIP_PATH': None,
'DEFAULT_ANONYMIZE_IP': False,
'DEFAULT_IGNORED_PREFIXES': ['/admin/', '/static/', '/media/'],
'DEFAULT_IGNORED_EXTENSIONS': [
'.css', '.js', '.png', '.jpg', '.svg', '.ico', '.woff2',
],
'DEFAULT_REALTIME_REFRESH': 30,
'DEFAULT_SEARCH_QUERY_PARAMS': ['q', 'search', 'query'],
# ── Billing integration ────────────────────────────────────
'BILLING_INVOICE_MODEL': 'billing.BillingInvoice',
'BILLING_USER_PLAN_MODEL': 'billing.UserBilling',
'BILLING_DONATION_MODEL': 'billing.Donation',
# ── Uploads / imports ───────────────────────────────────────
'UPLOADS_INCOMING_ROOT': None,
'UPLOAD_CHUNK_SIZE_MB': 5,
'UPLOAD_MAX_FILE_SIZE_MB': 2048,
'DATA_IMPORT_MAX_FILE_SIZE_MB': 100,
'UPLOAD_SESSION_TTL_HOURS': 24,
# ── Security / IP resolution ───────────────────────────────
'TRUST_X_FORWARDED_FOR': False,
'TRUSTED_PROXY_COUNT': 1,
# ── Security Center ────────────────────────────────────────
'SECURITY_TRACK_ONLY_STAFF': True,
'SECURITY_LOG_RETENTION_DAYS': 180,
'SECURITY_FAILED_LOGIN_THRESHOLD': 5,
'SECURITY_FAILED_LOGIN_WINDOW_MINUTES': 15,
'SECURITY_ALERT_EMAILS': [],
'SECURITY_ALERT_WEBHOOK_URL': None,
'BACKUP_REAUTH_MINUTES': 15,
# ── Server / operations ─────────────────────────────────────
'SERVER_METRIC_RETENTION_DAYS': 7,
'SLOW_QUERY_THRESHOLD_MS': 100,
'CELERY_APP_PATH': None,
# ── Compliance ──────────────────────────────────────────────
'CONSENT_MODE_ENABLED': False,
'CONSENT_COOKIE_NAME': 'analytics_consent',
'CONSENT_COOKIE_GRANTED_VALUE': 'granted',
'DATA_RETENTION_DAYS': {},
# ── Slack / Discord ────────────────────────────────────────
'SLACK_SIGNING_SECRET': None,
'DISCORD_PUBLIC_KEY': None,
# ── Multi-site ──────────────────────────────────────────────
'AUTO_CREATE_SITES': False,
# ── Anomaly detection ──────────────────────────────────────
'ANOMALY_ALERT_THRESHOLD_PERCENT': 30,
}
Configuration groups
Navigation: SIDEBAR_SECTIONS controls which dashboard areas are exposed and in what order. Keep a section disabled
when the corresponding integration is not configured, especially optional billing.
Analytics: API_PATH_PREFIX identifies API traffic, GEOIP_PATH points to the MaxMind GeoLite2-City database, the
default ignored prefixes/extensions prevent static/admin traffic from polluting analytics, DEFAULT_REALTIME_REFRESH
controls the live page refresh interval, and DEFAULT_SEARCH_QUERY_PARAMS controls common search-query parameter names.
Billing: BILLING_INVOICE_MODEL, BILLING_USER_PLAN_MODEL, and BILLING_DONATION_MODEL point to models in the
host project. The dashboard does not own your billing data model.
Uploads/imports: UPLOADS_INCOMING_ROOT controls the staging location; UPLOAD_CHUNK_SIZE_MB and
UPLOAD_MAX_FILE_SIZE_MB control upload behavior; DATA_IMPORT_MAX_FILE_SIZE_MB limits historical CSV imports;
UPLOAD_SESSION_TTL_HOURS controls how long incomplete upload sessions are retained.
Proxy/IP trust: only enable TRUST_X_FORWARDED_FOR when a reverse proxy you control sets X-Forwarded-For.
TRUSTED_PROXY_COUNT controls the trusted hop count. Do not blindly trust client-supplied forwarding headers.
Security: login tracking defaults to privileged accounts only; failed-login thresholds, retention, security alert destinations, and backup re-authentication are configurable.
Operations: SERVER_METRIC_RETENTION_DAYS controls historical server snapshots, SLOW_QUERY_THRESHOLD_MS controls
slow-query capture, and CELERY_APP_PATH points to the host application's Celery instance when queue monitoring is
enabled.
Compliance: consent mode is disabled by default. When enabled, tracking waits for the configured consent cookie.
DATA_RETENTION_DAYS is empty by default; specify only the data types you explicitly want automatically pruned.
Chat integrations: Slack signing secrets and the Discord public key are optional. Endpoints remain unavailable until their credentials are configured.
Multi-site: AUTO_CREATE_SITES is disabled by default so unknown hostnames do not silently create database rows.
Anomaly detection: a traffic change larger than ANOMALY_ALERT_THRESHOLD_PERCENT versus the comparable prior-week
day produces an anomaly alert.
Host-project settings beyond PAXALIA_DASHBOARD
The package also integrates with standard Django settings for: INSTALLED_APPS, MIDDLEWARE, TEMPLATES,
database/cache configuration, email delivery, CSRF_TRUSTED_ORIGINS, CORS, CSP, session/cookie security, and ASGI/WSGI.
Those settings belong to the host project rather than the package's PAXALIA_DASHBOARD dict.
Event API Path
The event API is hardcoded in JavaScript at /api/paxalia/event/. This is intentional:
- The dashboard URL stays secret – never exposed in client code.
- The event API is public – accepts anonymous data only.
- No inline scripts needed – all CSP rules are satisfied with
nonce.
If you want to change the event API path, you must update:
- The URL pattern in your project's
urls.py - The
EVENT_URLvariable inpaxalia/static/paxalia/scripts/analytics-events.js
Middleware Integration
The package provides three middleware classes. They are deliberately split by responsibility so you can enable the minimum set required by your deployment.
Required: AnalyticsMiddleware
MIDDLEWARE = [
# ...
'paxalia.middleware.AnalyticsMiddleware',
]
AnalyticsMiddleware records page views, resolves sites, classifies bot/API traffic, applies configured ignore rules,
and feeds the dashboard's daily and session analytics.
Optional: SecurityBlockMiddleware
Place this before AnalyticsMiddleware if you want blocked IPs rejected before they are recorded as analytics
traffic:
MIDDLEWARE = [
# ...
'paxalia.middleware.SecurityBlockMiddleware',
'paxalia.middleware.AnalyticsMiddleware',
]
Blocked-IP lookups are briefly cached so the blocklist does not add an uncached database query to every request.
Optional: SlowQueryMiddleware
MIDDLEWARE = [
# ...
'paxalia.middleware.SlowQueryMiddleware',
'paxalia.middleware.AnalyticsMiddleware',
]
Queries at or above SLOW_QUERY_THRESHOLD_MS are recorded in SlowQuery. The middleware uses Django's query execution
wrapper and guards its own insert so it does not recursively record itself.
Recommended ordering
When both optional middleware classes are enabled, the package's intended ordering is:
MIDDLEWARE = [
# security / proxy / Django middleware ...
'paxalia.middleware.SecurityBlockMiddleware',
'paxalia.middleware.SlowQueryMiddleware',
'paxalia.middleware.AnalyticsMiddleware',
]
SecurityBlockMiddleware should run before analytics so denied traffic never becomes a page-view record.
SlowQueryMiddleware can wrap the request independently of analytics tracking.
Dashboard Pages
| Page | URL | What it shows |
|---|---|---|
| Overview | / |
Today/yesterday views, unique visitors, sessions, bounce rate, pages/session, API calls, top page, 30‑day trend chart, top‑10 bar chart, top pages table |
| Pages | /pages/ |
All tracked pages with view counts, search by path, pagination, links to per‑page detail |
| Page Detail | /pages/…/ |
30‑day view chart for a single page with compare toggle |
| API | /api/ |
API call counts today/yesterday, 30‑day API chart, top endpoints, status‑code distribution |
| Traffic | /traffic/ |
Top referrers, browsers, operating systems, device types |
| Geography | /geography/ |
Offline world map with drill‑down, country table, top cities (click a country to filter cities) |
| Events | /events/ |
Custom events: today/yesterday counts, daily chart, top categories, top actions, top labels, events by page, recent events feed |
| Real User Monitoring | /rum/ |
Core Web Vitals (LCP/CLS/INP) at the 75th percentile with good/needs-improvement/poor breakdown, top JavaScript errors |
| Uptime Monitoring | /uptime/ |
Monitor list with current status and uptime %, add/pause/delete monitors, recent incident log |
| Compliance | /compliance/ |
Consent-mode and retention status, "forget this visitor" deletion tool |
| Data Import | /import/ |
Upload a GA/Plausible CSV export to backfill DailySiteStats for dates before you started tracking |
| Billing | /billing/ |
(optional) Total revenue, today/month revenue, active subscriptions, donations, daily income chart, top plans, recent transactions, MRR/ARR trend, churn, failed-payment tracking |
| Real‑time | /realtime/ |
Live visitor count (last 5 min), unique IPs, recent page views table with configurable refresh |
| Server Overview | /server/overview/ |
System health snapshot: CPU, memory, disk, network usage with live charts |
| Server CPU | /server/cpu/ |
Detailed CPU usage per core, historical chart, load average |
| Server Memory | /server/memory/ |
RAM and swap usage with doughnut chart |
| Server Disk | /server/disk/ |
Partition usage bars and I/O history |
| Server Network | /server/network/ |
Interface statistics and network traffic chart |
| Server Services | /server/services/ |
List of running systemd services |
| Server Processes | /server/processes/ |
Active process list sorted by CPU usage |
| Server Slow Queries | /server/slow-queries/ |
Queries recorded by the opt-in SlowQueryMiddleware, over a configurable threshold |
| Server Queues | /server/queues/ |
Celery worker and task status (if CELERY_APP_PATH is configured) |
| Server Deployments | /server/deployments/ |
Log of recorded deployments (manage.py record_deployment), each creating a matching Overview chart annotation |
| Settings | /settings/ |
IP anonymisation, ignored paths/extensions, refresh interval, theme selector, language selector |
| Admin Overview | /admin-overview/ |
User registrations, content creation, and login activity charts |
| Bot Traffic | /bots/ |
Total bot requests, daily bot charts, top bot paths, bot requests by country, bot category breakdown (search engine/AI crawler/social preview/SEO tool/unknown/malicious) |
| Backups | /backups/ |
Configure backup paths, storage, schedule, and retention; create, download, and delete backups |
| About | /about/ |
The story behind the project, the developer, and support options |
All pages support date‑range filtering with one‑click presets (Today, Yesterday, Last 7 days, Last 30 days, This
month).
Every line chart includes a “Compare to previous period” toggle.
Every data table has CSV and JSON export buttons.
Custom Event Tracking
Track any user interaction — button clicks, form submissions, video plays, downloads — with a single JavaScript snippet.
Quick start
The package includes a lightweight event tracking script. You can either include it via Django's static tag, or copy the code directly into your project.
Option 1: Using Django's static tag (recommended for Django projects)
<script src="{% static 'paxalia/scripts/analytics-events.js' %}"></script>
Note: The default prefix is /insights/. If you changed it in your urls.py, replace YOUR_PREFIX in the script
above.
Tracking events
Once the script is loaded, you can track events in two ways:
Using data attributes (no JavaScript required):
<button data-analytics-category="download" data-analytics-action="click" data-analytics-label="windows">
Download for Windows
</button>
<form data-analytics-category="form" data-analytics-action="submit" data-analytics-label="contact-form">
...
</form>
Using JavaScript directly:
window.opAnalytics('video', 'play', 'intro-tutorial', 1);
All events appear in the Events dashboard with full date‑range filtering, comparison toggle, and CSV/JSON export.
Available event properties
| Property | Required | Description |
|---|---|---|
| category | Yes | Grouping name, e.g. button, video, form |
| action | Yes | What happened, e.g. click, play, submit |
| label | No | Extra detail, e.g. signup-hero, linux-download |
| value | No | Numeric value (optional) |
| path | No | Page path – auto‑filled from window.location.pathname |
Event API Path
The event tracking script uses hardcoded URLs: /api/paxalia/event/ and (since Real User Monitoring, below)
/api/paxalia/js-error/. This is intentional:
- It keeps the dashboard URL secret.
- It makes the JavaScript simple and fast.
- It allows you to mount the dashboard at any secret path.
If you need to change these paths, update:
- The URL patterns in your project's
urls.py - The
EVENT_URLandJS_ERROR_URLvariables inpaxalia/static/paxalia/scripts/analytics-events.js
Real User Monitoring
Core Web Vitals and JavaScript error tracking, collected by the same analytics-events.js script used for custom
events — no separate tracker file, no third-party web-vitals library dependency.
What's collected
- LCP (Largest Contentful Paint) and INP (Interaction to Next Paint) — measured natively via the browser's
PerformanceObserverAPI. - CLS (Cumulative Layout Shift) — computed with the standard session-window algorithm (shifts less than 1s apart, capped at a 5s session, largest session wins), not a naive lifetime sum.
- JavaScript errors — via
window.onerrorandunhandledrejection, including message, filename, line/column, and a truncated stack trace. Capped at 10 reports per page load (with per-error dedup) so a runaway error loop can't flood the endpoint.
All of it is sent right before the page is hidden/unloaded (Web Vitals, via sendBeacon, same lifecycle as the
existing time-on-page tracking) or immediately (JS errors, via fetch(..., {keepalive: true}), since a page may
keep running long after an error and you want to know sooner).
Where it's stored
- Web Vitals ride on the existing
AnalyticsEventmodel (category='web_vitals',actionis the metric name,valuethe metric value) — no new table for these. - JS errors get their own
JSErrormodel, since a useful report needs filename/line/column and a stack trace, whichAnalyticsEvent's generic 255-character label has no room for.
The /insights/rum/ page
- Three Web Vitals cards (LCP/CLS/INP), each showing the 75th percentile for the selected period — the industry-standard way to aggregate field data, not an average — plus a good/needs-improvement/poor breakdown bar and the sample count. A metric with no samples yet shows an empty state rather than a misleading zero.
- A Top JavaScript Errors table, grouped by error message (count, first seen, last seen, a sample file:line).
Accuracy notes (read before treating these as lab-grade metrics)
- INP here is the single worst interaction duration observed on the page, not the full percentile-ranking algorithm the spec uses for pages with dozens of interactions. This converges to the same number on a typical page and runs slightly pessimistic on a highly-interactive single-page app.
- User-Agent-based classification doesn't apply here, but the same "field data, not lab data" caveat as any RUM tool applies: these numbers reflect whatever devices/connections your real visitors actually have.
- JS error grouping is by message text only (not filename/line too) — grouping in a build-specific location would split the same error across every minified-bundle hash your deploys produce.
Uptime Monitoring
Scheduled HTTP checks against URLs you configure, with status history and an incident log — a new subsystem, not an extension of an existing page.
How it works
-
Add a monitor on
/uptime/: name, URL, HTTP method (GET/HEAD/POST), expected status code, timeout, and check interval. -
Schedule the check command via cron or Celery beat — this package already assumes cron/Celery beat access for
aggregate_daily_stats,send_scheduled_reports, anddetect_anomalies, so this isn't a new operational requirement:# Run every minute; each monitor is only actually pinged once its own # check_interval_minutes has elapsed since its last check. * * * * * cd /path/to/project && python manage.py check_uptime >> /var/log/uptime.log 2>&1
-
The
/uptime/page shows each monitor's current status, uptime % for the selected date range, and a combined recent-incidents table across all monitors.
Design notes
- No new dependency. The HTTP check uses only
urllib.requestfrom the standard library — a GET/HEAD with a timeout and a status-code check doesn't need anything therequestslibrary provides over urllib, and this package already goes out of its way to keep optional features from forcing new dependencies (django-otpandweasyprintare both guarded, optional imports). - Incidents are transition-based, not one row per failed check. An incident opens on an up→down transition (or a monitor's very first check coming back down) and resolves on the next down→up transition — a monitor that's down for an hour with a check every minute is one incident with a ~60-minute duration, not sixty rows.
- Alerts go through the same
send_alert()used by security and anomaly alerts (category='uptime') — every down/recovery transition creates an in-dashboard notification and, if configured, an email/webhook alert, exactly like every other alert category. - Uptime % for a period with zero checks is shown as "—", not 0% or 100% — nothing to compute yet is different from "always down" or "always up".
Compliance
Consent-mode gating, per-data-type retention policies, and a "forget this visitor" deletion tool — independent of any other section.
Consent Mode
Off by default — every deployment tracks exactly as it did before this feature existed. To require consent before tracking anything:
PAXALIA_DASHBOARD = {
...
'CONSENT_MODE_ENABLED': True,
'CONSENT_COOKIE_NAME': 'analytics_consent', # defaults shown
'CONSENT_COOKIE_GRANTED_VALUE': 'granted',
}
Then, on the pages you track, include the new template tag immediately before the analytics-events.js script tag:
{% load analytics_tags %}
{% analytics_consent_config %}
<script src="{% static 'paxalia/scripts/analytics-events.js' %}"></script>
Your own consent-banner/CMP JavaScript is responsible for setting the cookie once a visitor accepts — this package doesn't provide a banner UI, only the gate that reads the cookie it sets. Until that cookie is present with the configured value:
- No
PageViewrow is written, and no session cookie is set —AnalyticsMiddlewarereturns early, before any tracking state is created. - The public event/JS-error API endpoints skip the write and return
{"status": "skipped"}rather than an error. analytics-events.jsdoesn't attach any listeners or send any beacons —window.opAnalyticsbecomes a no-op so existingonclick="opAnalytics(...)"call sites on your pages don't throw.
The server-side checks (middleware and the API endpoints) are the actual compliance guarantee; the client-side check is about not even trying, and can't be relied on alone since a request could be sent directly to the API.
Data Retention
Per-data-type retention, separate from SECURITY_LOG_RETENTION_DAYS (which only covers LoginEvent/
SecurityAuditLog) and SERVER_METRIC_RETENTION_DAYS (pruned inline by record_server_metrics, not by this):
PAXALIA_DASHBOARD = {
...
'DATA_RETENTION_DAYS': {
'pageview': 400,
'analytics_event': 400,
'js_error': 90,
'uptime_check': 90,
'slow_query': 30,
},
}
Empty by default — nothing is deleted unless you explicitly opt a data type in. Schedule the command like the others:
0 3 * * * cd /path/to/project && python manage.py prune_analytics_data >> /var/log/prune-paxalia.log 2>&1
Forget This Visitor
On /compliance/, delete every stored row for a given session ID or IP address — real, immediate deletion (since
anonymize_ip defaults off, IP addresses are typically stored raw, so this is a real capability, not a symbolic
one). Matches both a raw IP and its SHA-256 hash, since a deployment that toggled anonymize_ip partway through
its history could have stored a visitor's IP either way at different times.
Known gap: JS errors can only be deleted by session ID — the JSError model doesn't store an IP address, so an
IP-based deletion request won't reach it. Documented here rather than silently leaving rows behind.
The audit log records that a deletion happened and how much was deleted, but not the raw identifier that was requested to be forgotten — logging the exact thing someone asked to have forgotten, in a different table, would defeat the point.
Data Import
Import historical daily stats from a Google Analytics or Plausible CSV export, for people migrating in — on
/import/.
Why CSV, not the GA4 API
A real GA4 API integration needs OAuth credentials, a Google API client library dependency, and per-property configuration this package has no way to own — the same category of problem as billing or Celery (it isn't this package's data or credentials to hold). A CSV export needs nothing but a file you already have:
- Google Analytics: Reports → export any report as CSV.
- Plausible: Settings → Imports & Export → export CSV.
This is a deliberate scope decision, not a shortcut: it trades "fully automated" for "works today, no credentials, no new dependency."
One parser for both sources
A GA4 daily-metrics export and a Plausible export are both, underneath the different UIs, a table with a date column and a handful of aggregate metric columns — they don't need two bespoke parsers, just column-name recognition across both vocabularies (GA says "Views"/"Sessions"/"Users"; Plausible says "pageviews"/"visitors"). GA's exports also carry a few leading title/date-range lines before the real header row — the parser skips anything before the first row that looks like a real header, and skips (with a warning, not an error) any data row whose date column doesn't parse, which also quietly handles a trailing "Totals" summary row.
Scope
Only date + aggregate-metric CSVs are supported — one row per day. A page-level or dimension-broken-down export (e.g. GA's "Pages and screens" report, one row per URL) won't import usefully: historical data lands in daily aggregate stats, not individual page-view rows, since there's no way to reconstruct individual historical hits from an aggregate export.
Metric mapping (documented, not guessed silently):
| Export column | Lands in |
|---|---|
| views / pageviews | total_views |
| visitors / users | unique_ips (closest available field — not literally an IP count, see below) |
| sessions | total_sessions |
| bounce rate (%) | bounces, computed as round(bounce_rate / 100 * sessions) when both are present |
Anything this package can't derive from a generic aggregate export — unique_users as distinct from unique_ips,
api_calls, top_pages, bot_views — is left at 0/empty on imported rows rather than guessed.
A date that already has a DailySiteStats row for the target site is skipped by default — import is meant to
fill in history from before you started tracking with this package, not to silently overwrite real tracked data
that happens to overlap. Check "Overwrite" on the import form if you do want to replace it. Imported rows are
tagged (imported_from: ga/plausible/csv) so they're distinguishable from live-tracked days in the Django
admin.
Slack/Discord App
alerts.py has been able to send alerts to a Slack/Discord incoming webhook since v2.2.0. This is the other
direction: a slash command that asks for data on demand — /analytics today, /analytics week, etc.
Slack setup
- Create a Slack app at api.slack.com/apps and add a Slash Command (e.g.
/analytics) pointing athttps://yourdomain.com/api/paxalia/slack/command/. - Copy the app's Signing Secret into your settings:
PAXALIA_DASHBOARD = { ... 'SLACK_SIGNING_SECRET': 'your-signing-secret', }
- No new dependency — Slack verification is HMAC-SHA256 over the request body, using only
hmac/hashlibfrom the standard library.
Discord setup
- Create a Discord application at discord.com/developers/applications,
register a slash command (e.g.
/analyticswith an optionalperiodchoice: today/yesterday/week/month), and set the Interactions Endpoint URL tohttps://yourdomain.com/api/paxalia/discord/interactions/. - Copy the application's Public Key into your settings:
PAXALIA_DASHBOARD = { ... 'DISCORD_PUBLIC_KEY': 'your-public-key', }
- Discord requires Ed25519 signature verification, which the standard library doesn't provide — install
PyNaCl (
pip install pynacl) to enable it. This is an optional dependency, the same pattern asdjango-otp/weasyprint: without it installed, the Discord endpoint responds "not configured" (and, notably, Discord won't even let you save the Interactions Endpoint URL, since it requires the initial verification ping to pass). Slack support needs no such dependency either way.
Scope
One command surface, reusing the exact same compute_overview_snapshot() the scheduled email/PDF report and
public share links already use: total views, unique visitors, top 5 pages, top 5 referrers, for
today/yesterday/this week/this month — answered against combined (all-sites) traffic; there's no per-site argument
in this version. Both platforms get the same plain-text response format rather than either platform's richer
formatting (Slack Block Kit / Discord embeds) — a single shared format that renders reasonably on both was worth
more here than a prettier response on only one of them.
Admin Overview
The Admin Overview page provides a high‑level summary of site activity for administrators. It shows:
- User statistics – total users, new users today, new users this week, active users (last 7 days).
- Content statistics – total content items (articles, pages, etc.), configurable via
CONTENT_MODELSin the view. - Charts – user registrations over the last 30 days, content creation, and user logins.
- Recent activity – a table of recent actions from
django-auditlog(if installed) or recent user logins.
This page is designed to give you a quick glance at the health of your site without diving into the Django admin or raw database tables.
Server Monitoring
The dashboard includes a full server monitoring suite that reads metrics directly from your system using the psutil
library. No agents, no external services – all data is collected locally.
Available Pages
- Overview – a real‑time dashboard showing CPU, memory, disk, and network usage with live‑updating charts.
- CPU – per‑core usage, historical chart, and load average.
- Memory – RAM and swap usage with a doughnut chart.
- Disk – partition usage bars and I/O history.
- Network – interface statistics and traffic history.
- Services – list of running systemd services (Linux) with status.
- Processes – active process list sorted by CPU usage, updated every 5 seconds.
- Slow Queries – database queries that took longer than a configurable threshold, recorded by the opt-in
SlowQueryMiddleware(see below). - Queues – Celery worker and task status, if
CELERY_APP_PATHis configured (see below). - Deployments – a log of recorded deployments, each one also creating a matching annotation on the Overview traffic chart.
History charts are now backed by real data
api_server_history used to generate synthetic random.randint() data as a placeholder — that's fixed. History
now comes from ServerMetricSnapshot, written by a new scheduled command:
# Run every minute; also prunes snapshots older than
# SERVER_METRIC_RETENTION_DAYS (default 7) on every run.
* * * * * cd /path/to/project && python manage.py record_server_metrics >> /var/log/server-metrics.log 2>&1
Without this scheduled, the history charts show an empty state rather than fabricated numbers.
Slow query tracking (opt-in)
Add the middleware to your project's MIDDLEWARE, the same way AnalyticsMiddleware itself is added:
MIDDLEWARE = [
...
'paxalia.middleware.SlowQueryMiddleware',
]
Any query slower than SLOW_QUERY_THRESHOLD_MS (default 100ms, configurable in your PAXALIA_DASHBOARD dict) gets
recorded. This instruments Django's own query execution via connection.execute_wrapper(), so it works identically
across every database backend Django supports — no per-engine slow-query-log file to locate or parse.
Queue monitoring (Celery)
Point CELERY_APP_PATH at your project's Celery Application instance:
PAXALIA_DASHBOARD = {
...
'CELERY_APP_PATH': 'myproject.celery.app',
}
This package doesn't add celery as a dependency — if it's not installed, or CELERY_APP_PATH isn't configured, the
Queues page just shows an empty state. RQ isn't implemented yet; it would follow the same dotted-path pattern.
Deployment tracking
Call this from CI/CD right after a successful deploy:
python manage.py record_deployment --version "$(git rev-parse --short HEAD)" --notes "Deploy from main"
This records a Deployment row and auto-creates a matching ChartAnnotation at the same date, so the deploy shows
up on the Overview traffic chart with no extra configuration.
Privacy and Security
All metrics are read locally; no data is sent to any third‑party service. The server views are protected by the same
@staff_member_required decorator as the rest of the admin pages, so only logged‑in staff can access them.
Configuration
No additional configuration is required for the server section – it works out of the box on Linux, macOS, and Windows.
The only dependency is psutil, which is automatically installed with the package.
Bot Traffic
The dashboard can automatically detect and separate bot/scanner traffic from real user visits. This keeps your main analytics clean and provides a dedicated view for security monitoring.
How it works
- You define a list of bot paths (one per line) in the Settings page, e.g.:
/robots.txt
/.env
/wp-admin/
/xmlrpc.php
- The middleware checks each incoming request: if the path matches any bot path, it:
- Marks the
PageViewwithis_bot=Trueandbot_category='malicious' - Increments
DailySiteStats.bot_views(nottotal_views)
- Marks the
- In addition, every request's User-Agent is checked against a maintained pattern list (
paxalia/bot_classification.py) for known search engines (Googlebot, Bingbot, ...), AI crawlers (GPTBot, ClaudeBot, CCBot, ...), social-preview bots (facebookexternalhit, Twitterbot, Slackbot, ...), and SEO tools (AhrefsBot, SemrushBot, ...) — any match also setsis_bot=True, withbot_categoryset to the matching category. A generic bot-like User-Agent that doesn't match a known list (curl/...,python-requests/..., a bare "bot"/"crawler"/" spider" token, or no User-Agent at all) is categorized'unknown'.
⚠️ Breaking change:
is_botused to be set only from the path match above — a real crawler (Googlebot, a social-media link-preview fetch, etc.) visiting an ordinary page was previously counted as regular human traffic in Overview/Traffic/Cohorts/Funnels/Goals and everywhere else that filtersis_bot=False. That was never actually correct, but it means upgrading will change your numbers: "human" page-view counts will drop and Bot Traffic counts will rise on any site that gets real crawler traffic (which is nearly every public site). Existing rows are not reclassified automatically — runpython manage.py backfill_pageview_bot_categoryonce after upgrading to apply the new classification to history (safe to re-run any timebot_pathschanges or the pattern list is extended). Add--dry-runto preview the counts first.User-Agent is exactly what the request claims to be — nothing here verifies it against the crawler's published IP ranges (that would require a network call this package doesn't make). A path match on a known attack-probe path always overrides a UA claim, precisely because scanners sometimes spoof "Googlebot" to bypass filtering — but a spoofed UA hitting an ordinary page will be misclassified as the real thing.
- Bot requests are excluded from all main analytics (overview, pages, geography, traffic, real‑time, events, API).
- They are only visible on the dedicated Bot Traffic page, which shows:
- Total bot requests, today's bot requests, unique bot IPs
- Daily bot requests chart (last 30 days)
- Top 20 bot paths (horizontal bar chart)
- Bot requests by country (doughnut chart)
- Bot category breakdown (search engine / AI crawler / social preview / SEO tool / unknown / malicious), last 30 days
Importing a large bot path list
If you have a large file of known bot paths (e.g., from server logs), you can import it using the management command:
python manage.py import_bot_paths /path/to/bot_paths.txt
The file should contain one path per line. The command automatically merges new paths with existing ones and supports --replace to overwrite.
This is useful for blocking common scanners (e.g., WordPress exploit attempts, .env file probes, wlwmanifest.xml scans). A pre‑populated bots_paths.txt file is included in the package with over 3,400 known malicious paths.
Backup Management
The dashboard includes a full backup management system that lets you create, download, and delete server backups directly from the web interface.
Features
- Configurable paths – specify which directories or files to back up (one per line).
- Storage location – choose an absolute path on your server where backups are stored.
- Scheduled backups – set a schedule (manual, daily, weekly, monthly) and run via cron.
- Retention – keep the last N backups; older ones are automatically deleted.
- On‑demand backup creation – click a button to create a backup immediately (runs in the background so the page doesn't block).
- Chunked download – large backup files are downloaded in 5 MB chunks for reliability.
- Status tracking – see if a backup is pending, creating, completed, or failed.
Configuration
- Go to
/insights/backups/(the Settings card is at the top of the page). - Fill in:
- Paths to backup – one per line (absolute or relative to project root).
- Storage directory – absolute path (must be writable by the web server).
- Enable automatic backups – check to allow scheduled backups.
- Schedule – how often to run.
- Retention – number of backups to keep.
- Click Save Settings.
- To create a backup, click Create Backup in the Archives card.
Management command for scheduled backups
Add a cron job to run the backup command at your chosen schedule. For daily backups at 2 AM:
0 2 * * * cd /path/to/project && python manage.py create_backup >> /var/log/backup.log 2>&1
The command reads the configuration from the database and prunes old backups automatically.
Internationalization
The dashboard ships with complete translations for five languages:
| Language | Code | RTL |
|---|---|---|
| English | en |
No |
| Spanish | es |
No |
| Arabic | ar |
Yes |
| Simplified Chinese | zh-hans |
No |
| Brazilian Portuguese | pt-br |
No |
Arabic automatically flips the entire dashboard to right‑to‑left layout using the dir="rtl" attribute.
The language switcher is available in Settings → Language. It uses Django's standard set_language view — no extra
middleware or configuration is required.
Adding a new language
- Copy
paxalia/locale/en/LC_MESSAGES/django.potopaxalia/locale/<code>/LC_MESSAGES/. - Translate every
msgstrline. - Run
python manage.py compilemessages -l <code>. - Add the language to the
languageslist inpaxalia/views/settings.py(or override the view).
All translatable strings use Django's {% trans %} and {% blocktrans %} tags, so the dashboard can scale to any
number of languages without template changes.
Themes
Twelve complete dashboard themes are included, each defining the full --analytics-* palette: background, surface,
border, text, dim text, accent, accent‑hover, and comparison colour.
| Theme | Slug | Style |
|---|---|---|
| Dark Gold | dark |
Warm gold on deep charcoal — the default |
| Skybound Silk | default |
Soft lavender accent, the OP brand theme |
| Golden Dusk | golden |
Cream & classic gold, warm and inviting |
| Azure Drift | azure |
Cool ice‑blue, crisp and modern |
| Sunlit Meadow | sunlit |
Fresh lime green, bright and energetic |
| Indigo Spectrum | indigo |
Deep violet night, bold and creative |
| Arctic Horizon | arctic |
Icy blue & steel, calm and focused |
| Ocean Breeze | ocean |
Teal & navy, serene and deep |
| Twilight Reverie | twilight |
Mysterious violet, elegant and moody |
| Velvet Noir | velvet |
Dramatic crimson, luxurious and bold |
| Citrine Prestige | citrine |
True gold, refined and prestigious |
| Onyx Pearl | onyx |
Minimal silver on black, ultra‑modern |
Switching themes
- Go to Settings.
- Open the Theme dropdown.
- Select any theme — the entire dashboard recolours instantly, no page reload.
- Your choice is saved to
localStorageand persists across sessions.
Creating a custom theme
Add a new [data-analytics-theme="your-slug"] block in paxalia/static/paxalia/styles/themes.css:
[data-analytics-theme="your-slug"] {
--analytics-bg: #…;
--analytics-surface: #…;
--analytics-border: #…;
--analytics-text: #…;
--analytics-text-dim: #…;
--analytics-gold: #…;
--analytics-gold-dim: rgba(…, 0.12);
--analytics-gold-hover: #…;
--analytics-compare: #…;
}
Then add {'slug': 'your-slug', 'label': 'Your Theme'} to the themes list in paxalia/views/settings.py. The theme will appear in the dropdown automatically.
Exporting Data
Every data table in the dashboard has two download buttons:
- CSV — opens immediately as a
.csvfile, compatible with Excel, Google Sheets, and any spreadsheet tool. - JSON — downloads a
.jsonfile with an array of objects, ideal for scripts and APIs.
The export respects:
- The current date range (start and end dates).
- The current path search (on the Pages list).
- The current country filter (on the Geography page).
No additional configuration is needed. The export buttons appear automatically on every table card.
Available exports
| Export | What it contains |
|---|---|
| Top Pages | Top 10 pages with view counts |
| All Pages | Every tracked page with view counts |
| Top API Endpoints | Endpoint paths with call counts |
| API Status Codes | Status code distribution |
| Top Referrers | Referring URLs with visit counts |
| Browsers | Browser names with view counts |
| Operating Systems | OS names with view counts |
| Device Types | Device categories with view counts |
| Countries | Country names with visitor counts |
| Top Cities | City, country, and visitor counts |
| Events Categories | Category names with event counts |
| Events Actions | Category, action, and event counts |
| Events Labels | Label values with event counts |
| Events by Page | Page paths with event counts |
| Recent Events | Last 50 events with timestamps |
| Billing Plans | Plan slugs with user counts |
| Recent Transactions | Invoice number, user, amount, and date |
| Failed Payments (Dunning) | Invoice number, user, amount, date, and status for non-paid invoices in the last 90 days |
Billing Integration
If your project has billing models (invoices, user plans, donations), the analytics dashboard can display revenue and subscription data automatically.
Requirements
Your project must have three models that follow this approximate structure:
| Model | Expected fields |
|---|---|
| Invoice | date (DateField), amount (DecimalField), status (CharField with 'paid'), user (ForeignKey to User), invoice_number (CharField) |
| User Plan | current_plan (ForeignKey to a Plan model with a slug field), user (OneToOneField to User) |
| Donation | amount (DecimalField) |
Setup
- Add
'billing'toSIDEBAR_SECTIONSin yourPAXALIA_DASHBOARDconfig. - Set the model paths to match your project:
PAXALIA_DASHBOARD = {
'SIDEBAR_SECTIONS': [..., 'billing', ...],
'BILLING_INVOICE_MODEL': 'myapp.Invoice',
'BILLING_USER_PLAN_MODEL': 'myapp.UserPlan',
'BILLING_DONATION_MODEL': 'myapp.Donation',
}
- Restart the server. The Billing link will appear in the sidebar, and
/insights/billing/will show:
- Total revenue (all‑time)
- Revenue today and this month
- Active subscriptions count
- Total donations
- Daily income chart with compare toggle
- Plan distribution table
- Recent transactions table
- Monthly revenue trend, last 12 months, plus a projected ARR run-rate (an invoice-based proxy for MRR — see the note below)
- Churn (customer and revenue), computed from the last two fully-completed calendar months of invoice history
- Failed/pending payments ("dunning"), grouped by whatever status values your
Invoice.statusfield actually uses, with CSV/JSON export
If the models don't exist or aren't configured, the billing section simply doesn't appear — no errors, no broken pages.
Why "MRR proxy" and not MRR: this package doesn't require a Plan/price field in its documented contract above, only
current_plan.slug. So "MRR" here is the sum of'paid'invoices in a calendar month — a reasonable stand-in when there's genuine month-to-month billing, but it will differ from true subscription MRR if your billing cycles aren't monthly, or if a Plan's price ever changed after an invoice was cut. Likewise, churn is computed from invoice history ( paid last month, not paid this month) since there's no subscription start/cancel timestamp in the documented contract — it won't catch a customer who churns and resubscribes within the same window, and works best for regular (e.g. monthly) billing cycles.
Security Center
The Security Center is a first-class dashboard surface for privileged operational visibility. It is designed to complement, not replace, your host operating system's security controls.
Login and session visibility
The package records authentication activity through Django's authentication signals. By default, successful-login tracking is limited to staff/superuser accounts to preserve the privacy-first posture; failed-login attempts remain visible for brute-force detection.
The Security Center can show login results, location/device context, active sessions, session revocation, and logout information when the host application exposes the required Django authentication/session data.
IP blocklist
Staff can add an IP to the dashboard blocklist. When SecurityBlockMiddleware is installed, subsequent requests from
active blocked addresses are rejected before the analytics middleware records them.
Brute-force alerting
SECURITY_FAILED_LOGIN_THRESHOLD and SECURITY_FAILED_LOGIN_WINDOW_MINUTES define the threshold used to surface
repeated failed logins as a possible brute-force event. Alerts can be sent through configured email/webhook
destinations.
CSP violation reporting
The dashboard can collect Content Security Policy violations and surface them for investigation. This is especially useful during deployment hardening because blocked resources, inline-script violations, and unexpected origins can be examined from the same operational interface.
Security scorecard
The scorecard summarizes selected security findings and hardening checks so operational teams can identify outstanding configuration issues without inspecting several Django settings modules manually.
MFA / 2FA
The package includes a dashboard enrollment surface for authenticator-based two-factor authentication when the host
project has the required django-otp / two-factor stack installed and configured.
Backup re-authentication
Backup downloads can require recent password authentication through BACKUP_REAUTH_MINUTES, reducing the risk of an
already-authenticated staff browser becoming an unattended archive download point.
Advanced Analytics
Goals
Goals let a deployment define meaningful conversion targets rather than only tracking traffic volume. Goals can be used as reusable inputs to conversion-oriented analysis.
Funnels
Funnels model ordered steps and expose drop-off between stages. A typical flow is landing page → signup → activation → checkout.
Segments
Segments provide reusable behavioral filters so the same audience definition can be applied across analytics views rather than rebuilding filters manually each time.
Campaigns
Campaign tracking captures UTM-style campaign context and exposes traffic performance by source, medium, and campaign.
Cohorts
Cohort retention groups visitors by an initial activity period and follows subsequent activity over time, making repeat engagement visible rather than hiding it inside aggregate counts.
Annotations
Annotations place contextual markers on charts for deployments, campaigns, incidents, migrations, and other events that may explain traffic changes.
Reporting & Sharing
Scheduled reports
Reports can be generated from the same analytics snapshot used by the dashboard and other integrations. Scheduled delivery can use the host project's email configuration and optional PDF support.
Public share links
Share links provide a controlled, read-only presentation of selected dashboard information for external stakeholders.
Password-protected links use a one-way password hash rather than storing the clear-text password, with the current
migration represented by 0019_sharelink_password_hash.
Exports
The dashboard provides CSV/JSON exports for supported tables, respecting applicable filters such as date range, path search, and geography selection.
Paxalia API
The package exposes a versioned, key-authenticated API surface in addition to its browser event endpoint. Scoped API keys can be used for ingestion and read access without exposing staff dashboard credentials.
Current API capabilities include:
- event/data ingestion
- summary statistics
- page-view reads
- analytics-event reads
- API documentation through the dashboard's API Reference surface
The host application is responsible for securely storing API keys and selecting the appropriate scope.
Browser event API
The public browser event endpoint is intentionally separate from the secret dashboard URL. This allows the tracking script to remain functional without embedding the dashboard's private route in client-side code.
Dependency Health
The Dependency Health page is intended for runtime maintenance rather than package installation. It starts from the
installed paxalia-dashboard distribution and resolves its runtime dependency closure, while also recognizing direct
requirements declared by the package.
The page can progressively check upstream package releases after the local inventory is rendered, so opening the page does not need to wait for every external version lookup.
Dependency states distinguish current packages, packages with a newer upstream release, missing packages, and packages whose upstream check could not be completed. The page does not automatically upgrade packages.
Decorative README separators such as ---, ===, and other non-requirement lines are ignored by the requirement parser
rather than treated as package names.
Notifications & Alerts
Notifications provide an in-dashboard event surface for security, anomaly, uptime, and other supported alert categories.
Optional alert destinations include email and webhook delivery, while the in-dashboard notification center provides the local operational history without requiring an external notification platform.
Alerting is intentionally best-effort: a notification delivery failure should not turn the underlying analytics or security event into an application failure.
Multi-Site Analytics
Multiple domains can be represented by Site records and tracked through the same dashboard. Requests are resolved by
hostname, cached briefly, and associated with the matching active site.
AUTO_CREATE_SITES is disabled by default. Enable it only when automatically registering unknown hostnames is an
explicit part of your deployment model.
Release Center
The Release Center provides a dashboard surface for release artifacts and release context. Deployment tracking is
separate from artifact storage: CI/CD can call record_deployment after a successful deploy, which records the
deployment and creates a corresponding chart annotation so traffic changes can be interpreted against release events.
Example:
python manage.py record_deployment \
--version "$(git rev-parse --short HEAD)" \
--notes "Deploy from main"
Operational Commands
The v3 package includes management commands for ongoing operations:
python manage.py aggregate_daily_stats
python manage.py backfill_pageview_bot_category
python manage.py backfill_pageview_is_api
python manage.py check_uptime
python manage.py cleanup_uploads
python manage.py create_backup
python manage.py detect_anomalies
python manage.py import_bot_paths /path/to/bot_paths.txt
python manage.py prune_analytics_data
python manage.py prune_security_logs
python manage.py record_deployment --version "$(git rev-parse --short HEAD)"
python manage.py record_server_metrics
python manage.py seed_analytics
python manage.py send_scheduled_reports
Typical scheduled jobs are:
# Daily analytics aggregation
0 0 * * * cd /path/to/project && python manage.py aggregate_daily_stats
# Server history snapshot
* * * * * cd /path/to/project && python manage.py record_server_metrics
# Uptime checks
* * * * * cd /path/to/project && python manage.py check_uptime
# Anomaly detection
10 * * * * cd /path/to/project && python manage.py detect_anomalies
# Analytics data retention
0 3 * * * cd /path/to/project && python manage.py prune_analytics_data
# Security log retention
20 3 * * * cd /path/to/project && python manage.py prune_security_logs
Adapt schedules and log destinations to the host operating system.
Security & Privacy Model
The package is designed around keeping analytics data on the host server. IP storage/anonymization behavior is configurable, consent mode can prevent tracking until a visitor has consented, and data-retention commands allow a deployment to define how long different categories are retained.
What the package does not do
- It does not provide a cookie-consent banner; your CMP/banner is responsible for collecting consent and setting the configured cookie.
- It does not verify crawler identity against published crawler IP ranges; bot classification is based on request path and user-agent patterns.
- It does not automatically rotate credentials or install OS firewall rules.
- It does not automatically upgrade Python packages from the Dependency Health page.
- It does not make the host project's Celery, billing, Redis, PostgreSQL, SMTP, or reverse-proxy configuration on your behalf.
Production principle
Use the dashboard as an observability and application-level security layer alongside normal OS, database, reverse-proxy, backup, network, and identity controls.
Project Structure
paxalia-dashboard
├── paxalia
│ ├── admin.py
│ ├── alerts.py
│ ├── anomalies.py
│ ├── api_keys.py
│ ├── apps.py
│ ├── bot_classification.py
│ ├── bots_paths.txt
│ ├── chat_ops.py
│ ├── cohorts.py
│ ├── compliance.py
│ ├── conf_uploads.py
│ ├── context_processors.py
│ ├── conversions.py
│ ├── data_import.py
│ ├── geoip
│ ├── __init__.py
│ ├── locale
│ │ ├── ar
│ │ │ └── LC_MESSAGES
│ │ │ ├── django.mo
│ │ │ └── django.po
│ │ ├── en
│ │ │ └── LC_MESSAGES
│ │ │ └── django.po
│ │ ├── es
│ │ │ └── LC_MESSAGES
│ │ │ ├── django.mo
│ │ │ └── django.po
│ │ ├── pt-br
│ │ │ └── LC_MESSAGES
│ │ │ ├── django.mo
│ │ │ └── django.po
│ │ └── zh-hans
│ │ └── LC_MESSAGES
│ │ ├── django.mo
│ │ └── django.po
│ ├── management
│ │ └── commands
│ │ ├── aggregate_daily_stats.py
│ │ ├── backfill_pageview_bot_category.py
│ │ ├── backfill_pageview_is_api.py
│ │ ├── check_uptime.py
│ │ ├── cleanup_uploads.py
│ │ ├── create_backup.py
│ │ ├── detect_anomalies.py
│ │ ├── import_bot_paths.py
│ │ ├── prune_analytics_data.py
│ │ ├── prune_security_logs.py
│ │ ├── record_deployment.py
│ │ ├── record_server_metrics.py
│ │ ├── seed_analytics.py
│ │ └── send_scheduled_reports.py
│ ├── middleware.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_security_center.py
│ │ ├── 0003_csp_violations.py
│ │ ├── 0004_pageview_is_api.py
│ │ ├── 0005_flip_anonymize_ip_default.py
│ │ ├── 0006_multisite.py
│ │ ├── 0007_goals_funnels_segments_annotations.py
│ │ ├── 0008_dashboard_access_permissions.py
│ │ ├── 0009_paxalia_api_key.py
│ │ ├── 0010_reporting_sharing.py
│ │ ├── 0011_notifications.py
│ │ ├── 0012_bot_category.py
│ │ ├── 0013_js_error.py
│ │ ├── 0014_uptime_monitoring.py
│ │ ├── 0015_ops_monitoring.py
│ │ ├── 0016_compliance_permission.py
│ │ ├── 0017_data_import.py
│ │ ├── 0018_fix_dailysitestats_duplicates.py
│ │ ├── 0019_sharelink_password_hash.py
│ │ └── __init__.py
│ ├── models.py
│ ├── permissions.py
│ ├── queue_monitor.py
│ ├── report_delivery.py
│ ├── reporting.py
│ ├── requirements.txt
│ ├── revenue.py
│ ├── rum.py
│ ├── security_audit.py
│ ├── security_scorecard.py
│ ├── segments.py
│ ├── settings.py
│ ├── signals.py
│ ├── static
│ │ └── paxalia
│ │ ├── icons
│ │ │ ├── archive
│ │ │ │ ├── icon-file-text.svg
│ │ │ │ ├── icon-global.svg
│ │ │ │ └── icon-time-spendin.svg
│ │ │ ├── brand
│ │ │ │ ├── icon-brand.png
│ │ │ │ └── icon-brand.svg
│ │ │ ├── ui
│ │ │ │ ├── icon-bar-chart.svg
│ │ │ │ ├── icon-bot.svg
│ │ │ │ ├── icon-cpu.svg
│ │ │ │ ├── icon-download.svg
│ │ │ │ ├── icon-harddisk.svg
│ │ │ │ ├── icon-key.svg
│ │ │ │ ├── icon-layers.svg
│ │ │ │ ├── icon-memory.svg
│ │ │ │ ├── icon-network.svg
│ │ │ │ ├── icon-overview.svg
│ │ │ │ └── icon-server.svg
│ │ │ └── ui-multi
│ │ │ ├── icon-cloud-uploading.svg
│ │ │ └── icon-setting.svg
│ │ ├── scripts
│ │ │ ├── admin-overview.js
│ │ │ ├── analytics-events.js
│ │ │ ├── api.js
│ │ │ ├── backups.js
│ │ │ ├── billing-chart.js
│ │ │ ├── bots.js
│ │ │ ├── chart.umd.js
│ │ │ ├── d3.v3.min.js
│ │ │ ├── datamaps.world.min.js
│ │ │ ├── dependencies.js
│ │ │ ├── events-chart.js
│ │ │ ├── filter-bar.js
│ │ │ ├── geography-map.js
│ │ │ ├── language-manager.js
│ │ │ ├── overview.js
│ │ │ ├── page-detail.js
│ │ │ ├── realtime.js
│ │ │ ├── security.js
│ │ │ ├── server
│ │ │ │ ├── cpu.js
│ │ │ │ ├── disk.js
│ │ │ │ ├── memory.js
│ │ │ │ ├── network.js
│ │ │ │ ├── overview.js
│ │ │ │ ├── processes.js
│ │ │ │ └── services.js
│ │ │ ├── sidebar.js
│ │ │ ├── theme-manager.js
│ │ │ ├── topojson.v1.min.js
│ │ │ └── upload-widget.js
│ │ └── styles
│ │ ├── base.css
│ │ ├── components
│ │ │ ├── about.css
│ │ │ ├── backup.css
│ │ │ ├── buttons.css
│ │ │ ├── charts.css
│ │ │ ├── dependencies.css
│ │ │ ├── export-btn.css
│ │ │ ├── filter-bar.css
│ │ │ ├── icon.css
│ │ │ ├── menu.css
│ │ │ ├── notifications.css
│ │ │ ├── release-center.css
│ │ │ ├── rum.css
│ │ │ ├── security.css
│ │ │ ├── server.css
│ │ │ ├── settings-form.css
│ │ │ ├── sidebar.css
│ │ │ ├── stat-cards.css
│ │ │ ├── tables.css
│ │ │ ├── topbar.css
│ │ │ ├── typography.css
│ │ │ └── upload.css
│ │ ├── dashboard-refinements.css
│ │ ├── layout.css
│ │ ├── themes.css
│ │ └── tokens.css
│ ├── templates
│ │ └── paxalia
│ │ ├── about.html
│ │ ├── admin_overview.html
│ │ ├── annotations.html
│ │ ├── api_docs.html
│ │ ├── api.html
│ │ ├── api_keys.html
│ │ ├── backup_reauth.html
│ │ ├── backups.html
│ │ ├── base.html
│ │ ├── billing.html
│ │ ├── bots.html
│ │ ├── broken_links.html
│ │ ├── campaigns.html
│ │ ├── cohorts.html
│ │ ├── compliance.html
│ │ ├── dashboard.html
│ │ ├── data_import.html
│ │ ├── dependencies.html
│ │ ├── email
│ │ │ └── report_digest.html
│ │ ├── events.html
│ │ ├── funnels.html
│ │ ├── geography.html
│ │ ├── goals.html
│ │ ├── includes
│ │ │ └── filter_bar.html
│ │ ├── mfa_enroll.html
│ │ ├── notifications.html
│ │ ├── page_detail.html
│ │ ├── pages.html
│ │ ├── realtime.html
│ │ ├── releases.html
│ │ ├── reports.html
│ │ ├── rum.html
│ │ ├── security.html
│ │ ├── segments.html
│ │ ├── server_cpu.html
│ │ ├── server_deployments.html
│ │ ├── server_disk.html
│ │ ├── server_memory.html
│ │ ├── server_network.html
│ │ ├── server_overview.html
│ │ ├── server_processes.html
│ │ ├── server_queues.html
│ │ ├── server_services.html
│ │ ├── server_slow_queries.html
│ │ ├── settings.html
│ │ ├── shared_dashboard.html
│ │ ├── share_links.html
│ │ ├── sites.html
│ │ ├── traffic.html
│ │ └── uptime.html
│ ├── templatetags
│ │ ├── analytics_tags.py
│ │ └── __init__.py
│ ├── tests.py
│ ├── uptime.py
│ ├── urls.py
│ └── views
│ ├── about.py
│ ├── admin_overview.py
│ ├── annotations.py
│ ├── api_docs.py
│ ├── api_keys.py
│ ├── api.py
│ ├── backup.py
│ ├── billing.py
│ ├── bots.py
│ ├── broken_links.py
│ ├── campaigns.py
│ ├── chat_ops.py
│ ├── cohorts.py
│ ├── compliance.py
│ ├── csp_reports.py
│ ├── dashboard.py
│ ├── data_import.py
│ ├── dependencies.py
│ ├── events.py
│ ├── export.py
│ ├── geography.py
│ ├── goals.py
│ ├── __init__.py
│ ├── mfa.py
│ ├── notifications.py
│ ├── page_detail.py
│ ├── pages.py
│ ├── paxalia_api.py
│ ├── realtime.py
│ ├── releases.py
│ ├── reports.py
│ ├── rum.py
│ ├── security.py
│ ├── segments.py
│ ├── server.py
│ ├── settings.py
│ ├── share_links.py
│ ├── sites.py
│ ├── traffic.py
│ ├── uploads.py
│ ├── uptime.py
│ └── utils.py
├── LICENSE
├── MANIFEST.in
├── package-lock.json
├── pyproject.toml
├── README.md
├── setup.cfg
└── setup.py
Note: The
.mmdbGeoIP database files are not included in the Git repository because of their size.
Download them separately from MaxMind and place them inpaxalia/geoip/.
Contributing
Contributions are welcome!
If you'd like to improve the dashboard, fix a bug, or add a new language, please open an issue first to discuss your
idea.
Development setup
- Clone the repository.
- Install the package in editable mode:
pip install -e . - Make your changes.
- Run the test suite:
python manage.py test analytics - Submit a pull request.
Please follow the existing code style: token‑driven CSS, external JavaScript with window.__analytics_* data injection,
and Django's standard patterns.
Developer conventions
This project follows a small set of conventions to keep code readable, consistent, and easy to maintain. Please follow these rules when contributing.
Commit message format
Use conventional commits with the form type(scope): short summary. Keep bodies short and informative.
Common types:
- feat(scope): new feature
Example:feat(auth): add remember-me option for login - fix(scope): bug fix
Example:fix(download): correct checksum copy function - refactor(scope): non‑behavioral refactor
Example:refactor(scripts): move page scripts to components/pages - style(scope): visual‑only / CSS changes
Example:style(home): refine hero spacing - docs(scope): README or documentation updates
Example:docs(readme): add developer conventions - chore(scope): tooling, build, or cleanup
Example:chore(assets): add archive/assets-archive/ - perf(scope): performance improvements
- polish(scope): UI/UX refinements, empty states, success messages
Example:polish(analytics): add empty states to all charts
When a change touches many files, include a short Added / Modified / Fixed list in the commit body.
Commit body structure
For non‑trivial commits, include a structured body with these sections:
type(scope): short summary
Scope:
- file paths (modified/new)
Changes:
- bullet list of what changed
Behavior:
- how the system behaves now
Impact:
- why it matters
example:
feat(analytics): add world map with drill‑down to cities
Scope:
- paxalia/views/geography.py (modified)
- paxalia/static/paxalia/scripts/geography-map.js (new)
- paxalia/templates/paxalia/geography.html (new)
Changes:
- Created a geography page with an offline Datamaps world map
- Added country‑level visitor counts with quintile‑based coloring
- Implemented click‑to‑filter on the map to show cities for a selected country
Behavior:
- Staff can see visitor distribution across countries on a world map
- Clicking a country filters the cities table to that country
- The map is fully offline; no external API calls are made
Impact:
- The dashboard now provides geographic insights comparable to Google Analytics
while remaining fully privacy‑first and self‑hosted
Branching rules
main— protected, always deployable- Feature & refactor branches (short‑lived):
feat/<name>orfeat/<scope>/<name>refactor/<name>orrefactor/<scope>/<name>
- Docs branches:
docs/<short‑description>
- Hotfixes:
fix/<issue>orhotfix/<issue>
- When merging: prefer small focused PRs; squash or keep history tidy.
Ideas for contribution
The table below is retained as a forward-looking roadmap. Several items that were originally future ideas have since been implemented in v3; the list remains useful for potential extensions and contributors.
If you’re looking for a bigger feature to build, here are some ideas that would make the analytics dashboard even
better.
All of them respect the privacy‑first philosophy and fit the existing architecture.
| Feature | Description | Effort |
|---|---|---|
| City bubbles on the world map | When a country is clicked, zoom in and show city circles sized by visitor count | Medium |
| Session replay / user journey | Show the sequence of pages a single anonymous session visited, with timestamps | Medium |
| Funnel analysis | Define a series of pages or events and see drop‑off between each step (e.g., landing → signup → checkout) | Medium |
| Goal completions | Let users define a goal (e.g., /signup/, event form:submit) and track completions over time with conversion rates |
Medium |
| Annotations on charts | Allow staff to add notes to specific dates (“new feature launched”) visible as markers on every chart | Small |
| Scheduled email reports | A management command that emails a weekly summary PDF/CSV to configured recipients | Small |
| Page‑load time tracking | A tiny JS snippet addition to measure and display average page load times (Performance API) | Small |
| Custom dashboards | Let users pin their favourite charts and tables to a custom overview page, drag‑and‑drop layout | Large |
| More languages | Contribute a complete .po file for a new language (German, French, Japanese, Italian, Korean, etc.) |
Small |
| Dark/Light theme per section | Allow some dashboard sections to be light while others stay dark, or schedule theme changes | Medium |
| Admin dashboard widgets | Show today’s key metrics directly on the Django admin index page as custom admin widgets | Small |
| Audience retention / cohort table | Show what percentage of visitors return after N days, based on anonymous session IDs | Medium |
| Behavior flow diagram | A Sankey or flow chart showing how visitors move between pages (e.g., home → pricing → signup) | Large |
| Campaign / UTM tracking | Automatically extract utm_source, utm_medium, utm_campaign from URLs and show campaign performance |
Medium |
| Alerts / thresholds | Let staff set thresholds (e.g., “notify me if bounce rate > 80%”) and receive Django signals or email alerts | Medium |
| A/B testing integration | Track variants of a page and show which version performs better on a chosen metric | Large |
| Heatmap generation | Record click coordinates (anonymously) and generate a heatmap overlay for any page | Large |
| GDPR / cookie‑less mode | Add a fully cookie‑less mode that uses fingerprinting‑free session detection for even stricter privacy | Medium |
| Custom event schema | Let users define a schema for their events (allowed categories, actions, labels) and validate incoming events | Small |
| Video / audio engagement tracking | Pre‑built watchers for <video> and <audio> elements that automatically send play, pause, complete events |
Small |
| PDF export of the entire dashboard | Generate a multi‑page PDF report of the current view (charts + tables) with one click | Medium |
| Public sharing links | Generate a secret, read‑only link to share a dashboard view with external stakeholders | Medium |
| Multi‑site / tenant support | Track multiple domains or sites in a single analytics installation, with per‑site filtering | Large |
| AI‑powered insights | Use a local LLM to generate natural‑language summaries of traffic changes (“Traffic spiked 40% on Tuesday, driven by…”) | Large |
| Plugin / extension system | Allow developers to register custom charts, tables, or pages that plug into the analytics dashboard | Large |
If you’d like to work on any of these, please open an issue to discuss the approach first — I’ll be happy to help guide the implementation.
License
This project is licensed under the Apache License 2.0.
See the LICENSE file for the full text.
You are free to:
- Use, copy, modify, and distribute the software
- Use it for personal, commercial, and open‑source projects
- Build and sell products that include this software
Under the following terms:
- You must include a copy of the license and copyright notice
- You must state significant changes made to the original code
- You may not use the author’s name to endorse derived products without permission
This license also includes an express grant of patent rights from contributors to users.
Credits
Built entirely by Parsa Zaydany — solo, offline, during difficult circumstances – and published under the **Paxalia ** brand.
The Story
This dashboard exists because the analytics landscape is broken. Most tools track your users, expose their IPs, and send data to third‑party servers. They're insecure by design, and they don't respect privacy.
paxalia-dashboard is different:
- It's completely open source.
- It runs entirely on your own server – no external calls, no tracking pixels.
- Data handling (including IP anonymization) is yours to configure in Settings.
The world map database is only 60MB. Downloading it took over four hours over an unreliable connection. Pushing this first release to GitHub required buying a small amount of bandwidth — a purchase that came from savings I had set aside over two years for my main project. For someone in my situation, even this single push was expensive.
But developers exist because we help each other. Every language we use, every framework, every open‑source package — someone built it and shared it. This is my contribution back.
About Paxalia
Paxalia is a workspace, timer, planner, and team-tools platform — one app covering deep-focus timers, notes, goals, an infinite canvas board, a Life OS, live shareable pages, events and alarms, and team chat — built and maintained by a single developer. This analytics dashboard is part of the same ecosystem.
Full Story
To learn more about the project, the developer, and how to support its continued development, visit the About page
inside the dashboard at /insights/about/.
Support
If this package helps your project, consider:
- Giving it a star on GitHub
- Sharing it with the Django community
- Contributing a translation or feature
- Supporting via Paxalia
Thank you for using paxalia-dashboard.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file paxalia_dashboard-3.0.0.tar.gz.
File metadata
- Download URL: paxalia_dashboard-3.0.0.tar.gz
- Upload date:
- Size: 526.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13308ab41cd32bb1e00fcf2dc7ac929aea5cab13502d9ab4a1ad6cac7343a8fc
|
|
| MD5 |
4b83f88879935168071412a108c3210a
|
|
| BLAKE2b-256 |
ff7f3810dc364ae9517f1e1c4cc622628e8d7e42c77a5f22d67d0277538943c8
|
File details
Details for the file paxalia_dashboard-3.0.0-py3-none-any.whl.
File metadata
- Download URL: paxalia_dashboard-3.0.0-py3-none-any.whl
- Upload date:
- Size: 578.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
804d091e283a0cf0bc402fd98c22f70a33fb1968e3aa1e2e38a0b92c428619cf
|
|
| MD5 |
be3c741baa2d72f53e4993c5c902a03d
|
|
| BLAKE2b-256 |
53bbdfafef8f79d49497356e62698c786a7554eb87e86fe1eb68ad0163b108c9
|