Penny Metrics
Penny Metrics
Docs
Log in
Documentation

Penny Metrics is a lightweight, privacy-friendly, cookie-free web analytics tool. Drop one small script onto your site and watch visitors, pageviews, referrers, and custom events roll in — no consent banner required.

~1 KB script

Async, deferred, and never blocks rendering.

No cookies

Daily-rotating visitor hashes — GDPR friendly.

Custom events

Track clicks and conversions with one attribute.

Quick start
  1. 1
    Add your site

    Sign in, open the Dashboard, and click "Add site". Enter the domain you want to track (for example, mydomain.com).

  2. 2
    Install the snippet

    Copy the snippet from your site's menu and paste it inside the <head> of every page you want to track. It is the same snippet shown here, with your domain filled in:

    html

    &lt;script
        defer
        src="https://pennymetrics.dev/stats.js"
        data-hostname="mydomain.com"
    &gt;&lt;/script&gt;
  3. 3
    Watch the data arrive

    Deploy your change and visit your site. Within a few seconds the first pageview appears on your analytics dashboard. That's it!

Use the bare domain
The data-hostname should be your registered domain without a scheme or path. A "www." prefix is matched automatically, so mydomain.com also collects traffic from www.mydomain.com.
Script options

Configure the tracker with data attributes on the script tag.

Attribute
Required
Description
data-hostname No The domain to attribute traffic to. Defaults to the current window hostname. Set this when serving the same code from multiple domains or from localhost.
data-debug No Logs every payload to the browser console instead of sending silently. Handy while verifying your install locally.
Custom events

Track conversions like sign-ups, purchases, or downloads. There are two ways to send an event.

1. With an HTML attribute

Add data-s-event to any element. The event is sent automatically when the element is clicked.

html

&lt;button data-s-event="Signup click"&gt;Sign up&lt;/button&gt;

Attach extra properties with data-s-event-props. Separate pairs with a semicolon and keys from values with an equals sign:

html

&lt;button
    data-s-event="Signup click"
    data-s-event-props="plan=pro;period=monthly"
&gt;
    Sign up
&lt;/button&gt;
2. With JavaScript

Call window.stats.event() for anything that isn't a simple click. The signature is event(name, path?, props?):

javascript

window.stats.event("Signup click", "/dashboard/[userId]/settings", {
    plan: "pro",
    logged_in: "true",
});
The optional second argument overrides the page path — useful for merging dynamic routes such as /users/123 into /users/[id]. Property values are trimmed and stored as strings.
Single-page apps

The tracker hooks into the History API, so client-side navigations (pushState / replaceState / back & forward) are counted as pageviews automatically. React Router, Vue Router, Livewire wire:navigate, and similar libraries work out of the box.

If you navigate in some other way and need to record a pageview manually, call:

javascript

window.stats.pageview();
Privacy

The tracker is designed to be compliant by default:

  • No cookies or other persistent identifiers are stored on visitors' devices.

  • Visitors are counted using a hash of a daily-rotating salt, the site, the IP address, and the user agent. Raw IP addresses are never stored.

  • Because the salt rotates every day, visitors cannot be tracked across days, and the hash cannot be reversed.

  • Known bots and crawlers are detected and discarded.

Payload reference

Under the hood the script sends a POST request to the ingest endpoint with a JSON body. You normally never need this, but it is documented here for custom integrations.

bash

curl -X POST https://pennymetrics.dev/api/collect \
    -H "Content-Type: text/plain" \
    -d '{
        "type": "pageview",
        "hostname": "mydomain.com",
        "path": "/pricing",
        "query": "?utm_source=newsletter",
        "referrer": "https://news.ycombinator.com/"
    }'
Field
Type
Description
type
string
Either "pageview" or "event".
name
string
Event name. Required when type is "event".
hostname
string
The domain the hit belongs to. Must match a registered site.
path
string
The page path, e.g. /pricing.
query
string
The query string. UTM parameters are parsed from it.
referrer
string
The full referring URL. Self-referrals are dropped.
props
object
Optional key/value pairs of scalar values (events only).
The body is sent with a text/plain content type so the browser never issues a CORS preflight. Country is derived server-side from CDN geo headers (e.g. CF-IPCountry); browser, OS, and device are parsed from the user agent.
Troubleshooting
I don't see any data

Add the data-debug attribute to the script and reload the page. You should see the payload logged in the console. Confirm the data-hostname exactly matches the domain you registered, and that the snippet is in the <head>.

Testing on localhost

Set data-hostname to your real registered domain while testing locally, otherwise hits are attributed to "localhost" and dropped as an unknown site.

My own visits are counted

Use an ad blocker or a browser extension that blocks the script, or simply browse with the tracker disabled during development.

Still stuck? Open the Dashboard to manage your sites.