| favicons | Update favicons and reset default password hash | |
| .gitignore | First commit | |
| analytics.php | Switch to JS-based tracking | |
| config.php | Remove default password hash and allow open access when empty | |
| dashboard.php | Remove default password hash and allow open access when empty | |
| README.md | Switch to JS-based tracking | |
| track.js | Switch to JS-based tracking | |
simian
A minimal, self-contained page-view tracker. Add a single script tag to any page — HTML or PHP — and hits land in a local SQLite database. No external services, no cookies by default. simian stands for simple minimal analytics.
Features
- One script tag — works with any HTML or PHP page
- SQLite storage — zero infrastructure
- Bot filtering — common crawlers and tools are ignored
- Referrer tracking — query strings and tokens are stripped before storage
- Self-exclusion — toggle tracking for your own browser via a URL flag
- Standalone dashboard — password-protected, independent of the host app
- Sparkline chart and referrer breakdown
- 7, 30, and 90-day periods
- Respects
prefers-color-scheme(light/dark)
Requirements
- PHP 8.1 or later
pdo_sqliteextension (enabled by default in most PHP installs)
Files
simian/
├── analytics.php — library + beacon endpoint (serves the tracking pixel)
├── config.php — all settings (edit this, leave the others alone)
├── dashboard.php — web UI
├── track.js — JS snippet (add this to your pages)
└── data/
└── analytics.db — created automatically on first hit
Installation
Copy the simian/ folder into your web root (or alongside your project):
your-project/
├── index.html
├── ...
└── simian/
├── analytics.php
├── config.php
├── dashboard.php
└── track.js
Configuration
Open config.php and update the following:
Database path
define("ANALYTICS_DB", __DIR__ . "/data/analytics.db");
The data/ directory is created automatically. If possible, move the DB
outside your web root:
define("ANALYTICS_DB", "/var/data/mysite/analytics.db");
Dashboard password
Generate a hash and paste it in:
php -r "echo password_hash('yourpassword', PASSWORD_DEFAULT);"
define("ANALYTICS_PASSWORD_HASH", '2ドルy12ドル$...');
Leave empty to skip the password prompt (not recommended for public sites).
Excluded paths
Paths that start with any of these strings are never recorded:
define("ANALYTICS_EXCLUDE_PATHS", [
"/analytics/", // always exclude the dashboard itself
"/admin",
"/api/",
]);
Bot pattern
A case-insensitive regex matched against the user-agent. Extend as needed:
define("ANALYTICS_BOT_PATTERN",
"/bot|crawl|slurp|spider|.../i"
);
Usage
Add one script tag to the <head> of every page you want to track:
<script src="/simian/track.js" data-endpoint="/simian/analytics.php"></script>
That's it. The snippet sends a tiny image request (a tracking pixel) to
analytics.php, which records the page path and referrer in SQLite.
The data-endpoint attribute tells the snippet where analytics.php lives.
If you omit it, the snippet assumes analytics.php is in the same directory
as track.js.
Dashboard
Visit yoursite.com/simian/dashboard.php in your browser. It has its own
login session, independent of any auth in the host app.
The dashboard shows:
- Today's hits vs yesterday (with delta)
- Total hits for the selected period
- Daily sparkline chart
- Top referrers with relative bar chart
Use the 7d, 30d, and 90d links to switch periods.
Excluding your own visits
Visit any tracked page with ?toggle in the URL:
yoursite.com/index.html?toggle
A confirmation message appears:
analytics tracking disabled for this browser.
The snippet sets a cookie (analytics_ignore) that prevents your visits from
being recorded. Visit ?toggle again to re-enable tracking. The cookie lasts
one year and covers the entire site (/). It is per-browser — repeat the
toggle in any other browser or device where you don't want to be counted.
What is and isn't recorded
Each hit stores:
| Field | Value |
|---|---|
path |
URL path only, no query string |
referrer |
Scheme + host + path (query strings stripped; self-referrals dropped) |
ua |
User-agent string, truncated to 255 characters |
ts |
Unix timestamp |
Nothing else is stored. No IP addresses, no personal data.
Database maintenance
For a low-traffic personal site the database will stay small for years. If you ever want to prune old data, connect to the DB directly:
sqlite3 simian/data/analytics.db \
"DELETE FROM hits WHERE ts < strftime('%s', 'now', '-1 year');"
Security notes
- The
data/directory should not be publicly accessible. Add a rule to.htaccessif your web root includes it:<Directory "simian/data"> Require all denied </Directory> - The dashboard has no rate limiting on the login form. If the dashboard URL is publicly known, consider protecting it at the web server level as well (HTTP basic auth or IP restriction).
- Always change the default password before deploying.
- The tracking snippet must be served from the same origin as your pages so that the exclusion cookie is properly sent with the beacon request.