Installing
There are three ways to install UsherStats, plus proxy mode, and they build on each other.
| Way | What you get | What you change |
|---|---|---|
| Snippet | Human analytics, goals, journeys, A/B tests | One tag in your pages |
| First-party path | The same, served from your own domain, so blockers aimed at third parties leave it alone | A route on your server |
| Worker SDK | All of the above, plus crawler and AI-bot analytics and bot protection | Your Cloudflare Worker |
| Proxy mode | The same as the Worker SDK, with no code | A DNS record |
Your site's public key (pk_…) and server secret (sk_live_…) are on its Install page in the dashboard. The
public key is public by design. Keep the server secret on your server: it is what lets UsherStats believe what your
server says about its visitors.
The snippet
<script defer src="https://collect.usherstats.com/t.js" data-site="pk_…"></script>Put it in the <head> of every page. Optional attributes:
data-page-type="article": a short label for the kind of page, for the dashboard's page-type views.data-journeys="off": send pageviews and events only, not journeys.
If your site sends a Content Security Policy, allow https://collect.usherstats.com in script-src and connect-src.
A first-party path
Served from your own domain, the script and its reports are first-party: nothing for a blocker to drop as a third party.
Your server forwards /_us/ to https://collect.usherstats.com/, and the snippet says so:
<script defer src="/_us/t.js" data-site="pk_…" data-api="/_us"></script>Your server must tell UsherStats who the visitor is. Behind your proxy, UsherStats sees your server, not the visitor, and a server's network is a hosting network, which UsherStats counts as automated. So every forwarded request carries your server secret and the visitor's details:
| Header | Value |
|---|---|
x-usher-proxy | your server secret, sk_live_… |
x-usher-client-ip | the visitor's IP address |
x-usher-client-country | the visitor's two-letter country code |
x-usher-client-asn | the visitor's network number (AS number) |
x-usher-client-as-org | the visitor's network name, such as Comcast Cable Communications, LLC |
UsherStats uses these only with a valid secret for that site. If your server cannot supply the visitor's network (AS number and name), use the snippet directly instead: otherwise your readers will be counted as hosting-network traffic. On Cloudflare, the Worker SDK fills all of them for you. Elsewhere, a GeoIP database with network data (for example MaxMind's GeoLite2 ASN and Country) provides them.
Cloudflare Workers
Use the Worker SDK: it serves /_us/ and adds the snippet to your pages for you.
Next.js
Most Next.js hosts do not tell your code the visitor's network, so for Next.js the simplest correct install is the direct snippet, in your root layout:
import Script from 'next/script';
export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
<Script src="https://collect.usherstats.com/t.js" data-site="pk_…" strategy="afterInteractive" />
</head>
<body>{children}</body>
</html>
);
}If your Next.js site runs behind Cloudflare, put a Worker with the Worker SDK in front of it for a
first-party path. If your host gives you the visitor's network in request headers, you can forward /_us/ with a
route handler that sets the headers above, as in the Nginx example.
Nginx
With the GeoIP2 module and the GeoLite2 ASN and Country databases
loaded as $geoip2_asn, $geoip2_as_org and $geoip2_country:
location /_us/ {
proxy_pass https://collect.usherstats.com/;
proxy_ssl_server_name on;
proxy_set_header Host collect.usherstats.com;
proxy_set_header Cookie "";
proxy_set_header x-usher-proxy "sk_live_…";
proxy_set_header x-usher-client-ip $remote_addr;
proxy_set_header x-usher-client-country $geoip2_country;
proxy_set_header x-usher-client-asn $geoip2_asn;
proxy_set_header x-usher-client-as-org $geoip2_as_org;
}If Nginx is itself behind a proxy or load balancer, use the visitor's address it forwards (for example with the
realip module) rather than the load balancer's.
Caddy
With a GeoIP plugin that sets the visitor's country and network as placeholders (named here
{geoip.country}, {geoip.asn} and {geoip.as_org}; use your plugin's names):
handle_path /_us/* {
reverse_proxy https://collect.usherstats.com {
header_up Host collect.usherstats.com
header_up -Cookie
header_up x-usher-proxy {env.USHERSTATS_SECRET}
header_up x-usher-client-ip {remote_host}
header_up x-usher-client-country {geoip.country}
header_up x-usher-client-asn {geoip.asn}
header_up x-usher-client-as-org {geoip.as_org}
}
}Both examples drop your site's cookies on the way: UsherStats needs none of them. (The one exception is the cookie that marks your own team's browsers as internal; see Concepts. The Worker SDK forwards that one alone.)
The Worker SDK
For a site served by a Cloudflare Worker, wrap your handler:
import { withUsherStats } from '@usherstats/worker';
const site = async (request) => new Response('<!doctype html><html><head><title>Home</title></head><body>Hello</body></html>', {
headers: { 'content-type': 'text/html; charset=utf-8' },
});
export default {
fetch: withUsherStats(site, { pageType: (path) => (path.startsWith('/blog/') ? 'article' : 'page') }),
};Put the server secret in the Worker secret USHERSTATS_SECRET and the public key in USHERSTATS_SITE_KEY. The SDK:
- serves the snippet and its reports from
/_us/on your hostname, with the visitor's network details, and adds the snippet to your HTML pages; - records every request your Worker answers, people and crawlers alike, and sends the records in batches after the response, so no page waits for UsherStats;
- runs your site's bot protection before your code.
If UsherStats is slow or unreachable, your site is served as if it were not there. The options, and how bot protection decides, are on the Bot protection page.
Proxy mode
If your site is not on Cloudflare Workers, or you would rather not change it, point a hostname at UsherStats and it sits in front of your server, with analytics and bot protection and no code. See Proxy mode.
Checking the install
The site's Install page shows when the last pageview and the last server record arrived. Requests your server or proxy records count towards your plan's server requests; pageviews count towards its human pageviews (see Billing and plans).