Download the PHP package hkyss/beacon without Composer
On this page you can find all versions of the php package hkyss/beacon. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Package beacon
Short Description Self-hosted traffic and Core Web Vitals from real visits, cookieless by default
License MIT
Informations about the package beacon
Beacon
Self-hosted traffic and Core Web Vitals from real visits — in your own database, with no cookie and no third party.
- Page views with referrer, device class and campaign tags, and LCP, INP, CLS, TTFB and FCP measured in real browsers.
- Cookieless by default: no address stored, a visitor token salted and rotated at midnight, Do Not Track honoured before anything is sent.
- SQLite, MySQL, PostgreSQL, or newline-delimited JSON files.
- No runtime dependencies and no build step. The agent inlines before
</body>: 5.9 KB, about 2.2 KB compressed. - No dashboard. Reports come back as arrays and you draw them.
Install
A runtime dependency, not a dev one — this runs in production.
The namespace is hkyss\Beacon\, lowercase vendor. Composer matches PSR-4
prefixes case-sensitively, so Hkyss\Beacon\ compiles and never autoloads. Copy
the imports as written.
Enable
BEACON decides what is kept:
| Value | What is stored |
|---|---|
false |
Nothing. The agent is not even injected |
anonymous |
Page, referrer host, device class, campaign tags, and a daily visitor token. No address, no user agent, no cookie |
full |
All of the above plus the raw address and user agent |
Without BEACON_SECRET there is no visitor token: page views still count,
unique visitors read zero. full stores personal data, and the obligations that
come with it are yours.
| Variable | Default | |
|---|---|---|
BEACON_SECRET |
— | Salt for the daily visitor token |
BEACON_SITE |
default |
Which site the events belong to, when one install serves several |
BEACON_SAMPLE |
1.0 |
Share of visitors kept, 0.0 to 1.0 |
BEACON_ENDPOINT |
/beacon |
Where the agent posts |
BEACON_RESPECT_DNT |
1 |
Honour Do Not Track and Global Privacy Control |
BEACON_RETENTION_DAYS |
0 |
Days to keep an event; 0 keeps everything |
BEACON_THROTTLE |
120 |
Deliveries per address per minute; 0 removes the limit |
BEACON_STORAGE |
pdo |
pdo, jsonl or null |
BEACON_PATH |
— | Where JsonlStorage writes |
BEACON_PREFIX |
beacon_ |
Table prefix for PdoStorage |
The last three are read by the Laravel config, which builds the storage for you.
Elsewhere you construct the driver yourself and Config::fromEnv() ignores them.
The ingest endpoint is public
A beacon is sent by sendBeacon during unload: no session, no CSRF token, no
headers it can set. BEACON_THROTTLE caps deliveries per address per minute.
The window slides, so a burst cannot spend one limit either side of a minute
boundary.
Laravel puts its own ThrottleRequests on the route and answers 429.
Everywhere else Throttle counts, and a refused delivery is still answered
204. Either way the address is salted and hashed before anything is written,
and a counter that cannot be kept means no throttling rather than no analytics.
Files count per machine, so each server behind a balancer allows the full limit.
PdoCounter counts in the shared database and needs its table — Beacon::migrate()
or (new PdoCounter($pdo))->migrate().
One delivery carries at most 20 events and at most 64 KB.
Content-Security-Policy
The agent is inline. Under a script-src without 'unsafe-inline' both tags
need this request's nonce, or the agent is blocked with nothing to show for it
but a console error in production.
Laravel and PSR-15 need no configuration: the middleware reads the csp-nonce
request attribute, and Laravel falls back to Vite::cspNonce(). Override
nonce() on the Laravel middleware if yours lives elsewhere. Injecting by hand:
No nonce means no nonce attribute, which is right for a site with no policy.
Storage
Two tables, beacon_events and beacon_metrics, in the dialect your driver
speaks. migrate() is safe to run twice. JsonlStorage writes one file per UTC
day and needs no database, but aggregates in PHP. NullStorage is the default
when nothing is configured.
Every timestamp, bucket label and retention window is UTC. Writing a driver of
your own is seven methods against hkyss\Beacon\Storage\Storage, held to the
built-in behaviour by tests/StorageContract.php.
Laravel
The service provider is auto-discovered. It registers the ingest route, inlines the agent into HTML responses, and adds two commands.
Publish the config only to set something in code rather than in the environment.
The ingest route sits outside the web middleware group: a beacon carries no
CSRF token, and the session stack would set a cookie for every visitor. Its one
middleware is the rate limit — override ingestMiddleware() to add your own.
Evolution CMS 3
Injection and ingest both go through OnWebPagePrerender, which covers pages
served from the EVO page cache and works without a router. Set BEACON and
BEACON_SECRET in core/custom/.env or in the web server environment.
The provider builds its storage from EVO's own database connection, so all that is left is creating the tables once, from a CLI script inside EVO:
PSR-15
One middleware answers POST /beacon and inlines the agent into every other
HTML response. The throttle is optional — leave it out if the pipeline already
has a rate limiter in front.
Plain PHP
Beacon is for code with no container to ask. Where there is one, build
Ingest, Report and Agent yourself — the Laravel integration does.
| Call | |
|---|---|
Beacon::boot(?Config, ?Storage, ?Throttle) |
Wire it up once; returns the resolved config |
Beacon::receive(?Payload) |
Take one delivery; returns how many events were stored |
Beacon::inject($html, ?$nonce) |
Agent inserted before </body> |
Beacon::migrate() |
Create the event tables and the throttle counter |
Beacon::prune(?$now) |
Delete past the retention window; returns rows removed |
Beacon::report() |
The Report for the configured site |
Beacon::collecting() |
Whether the mode is anything but off |
Reports
Ratings are p75 against Google's thresholds. samples is how many measurements
a summary was computed from; past twenty thousand in one period it is a sample
of that size, drawn across the whole period rather than its first hour.
What it does not do
- No dashboard. Reports return arrays; the drawing is yours.
- No geography. Country from address needs a GeoIP database.
- No sessions, funnels or goals. Beacon counts visits and measures pages.
- Bots are dropped, not counted. Detection is a substring list, so it stops the honest crawlers and nothing else.
- No proxy headers. The address is
REMOTE_ADDR;X-Forwarded-Foris attacker-controlled unless the app has already decided which proxies to trust.
Development
SQLite always runs; MySQL and PostgreSQL run the same contract when you point the tests at a server and skip when you do not. CONTRIBUTING.md has the variables.
License
MIT — see LICENSE.