--- title: HF Space Analytics emoji: 📊 colorFrom: yellow colorTo: indigo sdk: docker pinned: false license: mit --- # HF Space Analytics — Gradio Edition A small Gradio Space that tracks page views across your other Hugging Face Spaces. Gradio provides the dashboard, while an embedded FastAPI application provides the tracking endpoints. ## Features - Gradio dashboard at `/` - `POST /track` — record a page-view event - `GET /stats` — aggregated visit counts - `GET /events` — recent raw events - `GET /tracker.js` — reusable browser tracker - `GET /health` — health and storage check - Daily JSONL storage in an attached Hugging Face Storage Bucket ## 1. Create the analytics Space 1. Create a new Hugging Face Space. 2. Select **Gradio** as the SDK. 3. Select **ZeroGPU** hardware. Dashboard refreshes use a one-second ZeroGPU allocation; tracking and API requests remain CPU-only. 4. Upload every file in this project, or push the repository with Git. 5. In the Space settings, attach a Hugging Face Storage Bucket as a read-write volume mounted at `/data`. 6. Add the optional variables and secrets below. | Name | Type | Purpose | |---|---|---| | `TRACKING_KEY` | Secret | Required in tracking requests when set | | `ADMIN_KEY` | Secret | Protects `/stats`, `/events`, and the dashboard when set | | `ALLOWED_ORIGINS` | Variable | Comma-separated CORS origins; default `*` | | `DATA_DIR` | Variable | Storage path; default `/data/visits` | | `HASH_SALT` | Secret | Salt used to hash browser visitor IDs | | `GEOIP_DB_PATH` | Variable | Path to a MaxMind GeoLite2 City database; default `/data/GeoLite2-City.mmdb` | The top-level `app.py` starts the mounted Gradio/FastAPI application on port `7860`, the standard port for Gradio Spaces. Do not configure a `PORT` variable for this Space; that generic variable may be used by another process in the runtime. ## 2. Add tracking to another Space ### Static HTML or a custom frontend Add this before ``: ```html ``` Omit `data-key` when `TRACKING_KEY` is not configured. ### Another Gradio Space See [`examples/gradio_example.py`](examples/gradio_example.py). It injects the same tracker through `gr.Blocks(head=...)`. ### Direct JavaScript ```javascript fetch("https://YOUR-ANALYTICS-SPACE.hf.space/track", { method: "POST", headers: { "Content-Type": "application/json", "X-Tracking-Key": "YOUR_TRACKING_KEY" }, body: JSON.stringify({ space: "YOUR_USERNAME/YOUR_SPACE", path: location.pathname, referrer: document.referrer || null, visitor_id: localStorage.getItem("hf_analytics_visitor") }), keepalive: true }); ``` ## 3. Read statistics Open the analytics Space to use the Gradio dashboard, or call the API directly: ```bash curl "https://YOUR-ANALYTICS-SPACE.hf.space/stats?days=30" ``` With an admin key: ```bash curl -H "X-Admin-Key: YOUR_ADMIN_KEY" \ "https://YOUR-ANALYTICS-SPACE.hf.space/stats?days=30" ``` ## Storage The default layout is: ```text /data/visits/ ├── 2026-08-06.jsonl ├── 2026-08-07.jsonl └── ... ``` Without a bucket mounted at `/data`, files are written to the Space filesystem and may disappear after a restart or rebuild. ### IP-based location To store approximate IP-based location, provide a licensed MaxMind GeoLite2 City database at `GEOIP_DB_PATH` (the default is `/data/GeoLite2-City.mmdb`). Each event stores only the available coarse fields under `location`: country code, country, region, and city. The raw IP is never stored. If the database is absent or cannot identify an address, `location` is `null` and tracking continues normally. ## Privacy and security - A salted hash of the connecting IP address is stored as `ip_hash`; raw IP addresses are not stored. - Approximate IP-based location is stored only when a GeoLite2 database is configured. - The recorded address may be the Hugging Face proxy address rather than the visitor's original IP. - The tracker stores the browser-reported timezone and language as coarse location hints; it does not collect GPS coordinates. - Browser visitor IDs are salted and hashed before storage. - Paths and referrers may contain sensitive information; omit them when unnecessary. - `TRACKING_KEY` is visible to visitors when included in browser JavaScript. Treat it only as a low-value anti-spam key, never as a Hugging Face access token. - Set an `ADMIN_KEY` before exposing raw events or private analytics. - Publish an appropriate privacy notice for your users and jurisdiction. ## Local development ```bash python -m venv .venv source .venv/bin/activate pip install -r requirements.txt DATA_DIR=./local-data python app.py ``` Then open `http://localhost:7860`. Run tests: ```bash pip install -r requirements-dev.txt pytest ```