thephpx / matrix
Laravel analytics package — tracks user signups and daily unique visitors via a SQLite-backed bearer-authenticated API
Requires
- php: ^8.1
- illuminate/database: ^10.0|^11.0
- illuminate/http: ^10.0|^11.0
- illuminate/routing: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
This package is auto-updated.
Last update: 2026-05-22 13:25:43 UTC
README
A lightweight Laravel package that tracks user signups and daily unique visitors using a dedicated SQLite database, exposed via bearer-authenticated JSON API endpoints.
Features
- Counts registered users from your application's
userstable - Tracks daily unique visitors by IP address (one count per IP per day)
- Logs every visit with a full timestamp, IP address, and ISO country code
- Resolves country codes via the free ip-api.com service with a local SQLite cache — each IP is looked up only once
- Stores all analytics in an isolated SQLite database — no changes to your main database
- Zero-configuration setup — all three tables are created automatically on first boot
- Two API endpoints protected by a bearer token
- Returns the last 30 days of data with zero-gap date fill
- Automatically purges visitor records older than 30 days to keep the database light
- Country lookups and DB writes run after the response is sent — zero latency added to your users
Requirements
- PHP 8.1+
- Laravel 10 or 11
- SQLite PHP extension (
ext-pdo_sqlite) - cURL PHP extension (
ext-curl) — used for IP-to-country lookups
Installation
1. Install via Composer
composer require thephpx/matrix
Laravel auto-discovers the service provider. No manual registration needed.
2. Add the bearer token to .env
MATRIX_BEARER_TOKEN=your-secret-token-here
3. (Optional) Publish the config
php artisan vendor:publish --tag=matrix-config
This copies config/matrix.php into your application's config directory so you can customise values.
Configuration
// config/matrix.php return [ // Bearer token required to access the /matrix/* endpoints. 'bearer_token' => env('MATRIX_BEARER_TOKEN'), // Absolute path to the SQLite file (auto-created if missing). 'database_path' => env('MATRIX_DATABASE_PATH', storage_path('matrix.sqlite')), ];
| ENV key | Default | Description |
|---|---|---|
MATRIX_BEARER_TOKEN |
null |
Required. Secret token for API access. |
MATRIX_DATABASE_PATH |
storage/matrix.sqlite |
Path to the SQLite analytics database. |
API Endpoints
All endpoints require an Authorization: Bearer {token} header.
GET /matrix/stats
Returns the total registered user count and the last 30 days of unique daily visitor counts.
Request
GET /matrix/stats HTTP/1.1 Authorization: Bearer your-secret-token-here
Response 200 OK
{
"user_count": 312,
"visitors": [
{ "date": "2026-04-22", "visitor_count": 0 },
{ "date": "2026-04-23", "visitor_count": 14 },
{ "date": "2026-04-24", "visitor_count": 31 },
...
{ "date": "2026-05-21", "visitor_count": 87 }
]
}
| Field | Type | Description |
|---|---|---|
user_count |
integer |
Total rows in the users table |
visitors |
array |
30-element array ordered oldest → today |
visitors[].date |
string |
Date in Y-m-d format |
visitors[].visitor_count |
integer |
Unique IPs recorded on that date (0 if none) |
GET /matrix/visitors
Returns the full visit log for the last 30 days — every page hit with its timestamp, IP address, and country code.
Request
GET /matrix/visitors HTTP/1.1 Authorization: Bearer your-secret-token-here
Response 200 OK
{
"visitors": [
{
"ip_address": "102.45.67.89",
"country_code": "NG",
"visited_at": "2026-05-21 14:32:11"
},
{
"ip_address": "66.249.64.20",
"country_code": "US",
"visited_at": "2026-05-21 13:18:44"
},
{
"ip_address": "81.22.44.11",
"country_code": "DE",
"visited_at": "2026-05-21 11:05:02"
}
]
}
Results are ordered most-recent first.
| Field | Type | Description |
|---|---|---|
visitors[].ip_address |
string |
IPv4 or IPv6 address of the visitor |
visitors[].country_code |
string|null |
ISO 3166-1 alpha-2 code (e.g. US, GB, DE). null for private/unresolvable IPs |
visitors[].visited_at |
string |
Full timestamp in Y-m-d H:i:s format |
401 Unauthorized (both endpoints)
Returned when the Authorization header is missing or the token is incorrect.
{
"error": "Unauthorized"
}
How visitor tracking works
The package automatically injects TrackVisitor into Laravel's web middleware group. On every web request:
- The response is sent to the browser first — no latency is added
- After the response is sent, the visitor's IP is resolved to a country code via ip-api.com (free, no API key required)
- The country result is stored in
matrix_ip_cache— subsequent visits from the same IP are served from the local SQLite cache with no network call - A row is upserted into
matrix_daily_visitors(unique per IP per day — drives the/matrix/statscounts) - A row is inserted into
matrix_visitor_logs(every hit — drives the/matrix/visitorslog)
The /matrix/* endpoint and common internal paths (/horizon/*, /telescope/*, /_debugbar/*) are excluded from tracking.
Automatic data purge
The package registers a daily scheduled task that deletes visitor records older than 30 days from both matrix_daily_visitors and matrix_visitor_logs. The matrix_ip_cache table is intentionally kept to avoid re-querying the geo API for previously seen IPs.
The purge runs automatically as long as your application's scheduler is active. If it is not already running, add the following cron entry to your server:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
No configuration is needed — the task is registered by the service provider and named matrix:purge-visitors.
Database
The package creates and manages its own SQLite connection named matrix. All three tables are created automatically on first boot.
matrix_daily_visitors — unique daily counts
| Column | Type | Notes |
|---|---|---|
id |
integer | Auto-increment primary key |
ip_address |
varchar(45) | Supports IPv4 and IPv6 |
date |
date | Visit date (Y-m-d) |
created_at |
timestamp | |
updated_at |
timestamp | |
| (unique) | (ip_address, date) |
matrix_visitor_logs — detailed visit log
| Column | Type | Notes |
|---|---|---|
id |
integer | Auto-increment primary key |
ip_address |
varchar(45) | Supports IPv4 and IPv6 |
country_code |
char(2) | ISO 3166-1 alpha-2 · nullable |
visited_at |
datetime | Full visit timestamp |
created_at |
timestamp | |
updated_at |
timestamp | |
| (index) | visited_at |
matrix_ip_cache — IP-to-country lookup cache
| Column | Type | Notes |
|---|---|---|
id |
integer | Auto-increment primary key |
ip_address |
varchar(45) | Unique |
country_code |
char(2) | ISO 3166-1 alpha-2 · nullable |
created_at |
timestamp | |
updated_at |
timestamp |
Uninstalling
- Remove the package:
composer remove thephpx/matrix - Delete the SQLite file:
rm storage/matrix.sqlite - Remove
MATRIX_BEARER_TOKEN(andMATRIX_DATABASE_PATHif set) from.env - If published, delete
config/matrix.php
Author
Faisal Ahmed thephpx@gmail.com
License
MIT