Install the tracking code
Add fastmon to your site with a single script tag. Five minutes from sign-up to first data point.
One <script> tag in your <head> is the whole setup. It works on
anything you can inject a script into: static HTML, a React or Vue
app, Hugo, Next.js, WordPress, a tag manager.
Time to first data: about five minutes. You'll need: access to your site's HTML and a fastmon account.
Your snippet
Opened from the app, these are filled in with your application's real values. Otherwise, paste them here and every snippet on this page updates.
Find both hashes in the app under Applications → ··· → IDs & hashes.
Applications and sites
If you opened this page from an application's Set up button, it already exists and the hashes above are filled in. Skip to step 1.
Otherwise, create one first. An application is one tracking snippet. It owns the collection settings and the two hashes below, and it can serve one domain or twenty.
In fastmon, open Applications and click Add. Give it a name and
the domain you want to monitor (the bare hostname, no protocol:
acme.com). Fastmon creates the application and its first site
for that domain in one step, then hands you the snippet.
That gives the application two short hashes:
source_hash: goes into the script URL.collector_hash: where the tracker posts data. It's baked into the script, so you normally never touch it by hand.
Both are on the application's card under ··· → IDs & hashes.
Running several domains off one snippet? Add them as further sites on the same application. Every site keeps its own dashboard and traffic, but they share one snippet and one set of collection settings. Only add a second application when a domain genuinely needs different settings.
1. Add the tracker tag
This one tag is the whole required setup. Drop it into the <head> of
every page you want to monitor:
<script defer src="https://fastmon.site/s/{source_hash}.js"></script>The tag uses defer: it loads in parallel with HTML parsing, never
blocks the parser, and runs in source order once the DOM is parsed.
async would also load without blocking, but it can interrupt parsing
the moment the download finishes, and the order between multiple async
scripts is whichever-finishes-first. For Web Vitals we want predictable
timing, so defer wins.
(Attribute order inside the tag is irrelevant to the browser:
<script defer src="…"> and <script src="…" defer> behave
identically. We write defer first so it matches what the app hands
you.)
Placement isn't critical, but <head> is the better spot: it lets the
tracker catch the very first paint.
Where to put it
| Site type | Put the tag in… |
|---|---|
| Plain HTML / Hugo / Jekyll | <head> of your base template. |
| WordPress | A header-snippet plugin, or header.php. |
| Next.js / Nuxt / Astro | The framework's head/script primitive (Next.js: <Script strategy="afterInteractive"> in app/layout.tsx). |
| Single-page apps | The static index.html shell: once is enough. |
2. Deploy and load a page
Push to the environment you want to monitor and open any page on the site.
The tracker registers PerformanceObserver for Web Vitals, buffers
events in memory, and POSTs batched payloads over the page view's
lifecycle: on load, on visibilitychange → hidden, on pagehide, and
at periodic flushes. Expect a few requests per page view, not exactly
one. Switching tabs or closing the page is the most reliable way to
force a flush while testing.
Then check it arrived: see Verify it works.
If the domain isn't a site yet
Beacons are matched to a site by the page's hostname. If you added the domain when creating the application, you're done: data lands on that site.
If you didn't (you created an empty application, or you've just put the snippet on an additional domain), the first page view doesn't get thrown away silently: the hostname shows up on the application as a suggested domain, and you add it as a site in one click. Beacons from before you adopt it aren't kept, so the numbers start from the moment you add it.
Which of those happens is the application's Unknown domains setting:
| Setting | What happens on a beacon from an unregistered domain |
|---|---|
| Suggest (default) | Listed as a suggested domain to adopt; the beacon itself is dropped. |
| Auto-create | A site is created automatically on the first beacon. |
| Ignore | Dropped silently: no suggestion, no site. |
Consent: when the session id is written
If your application stores a session id and the consent level is left
at its default (off), the tracker does not write the session id
until you tell it consent was granted. Call this from your cookie
banner's accept handler, and on every page load while consent stands:
// In your cookie banner's "Accept" callback, and on every page load// while consent is granted (most consent managers do this for you):window.fastmon && window.fastmon.grantConsent && window.fastmon.grantConsent();Without that call the tracker still measures Web Vitals and page views; it just doesn't stitch them into multi-page sessions. If your application doesn't store a session id at all, the served bundle never touches storage and there's nothing to gate.
See Privacy for what is and isn't collected.
Optional extras
Neither is needed to get data flowing. Add them once the tracker tag is in place and working.
Catch errors that fire before the tracker loads
A deferred script only starts once the DOM is parsed, so a JavaScript error thrown during early parsing happens before fastmon is listening. This tiny inline snippet queues those errors and hands them over when the tracker boots.
It only works above the tracker tag from step 1, so put it there,
first thing in the <head>:
<script> window.__fastmon = window.__fastmon || { q: [] }; (function (q) { function h(k) { return function (e) { q.push([k, e, Date.now()]); }; } addEventListener("error", h("e"), true); addEventListener("unhandledrejection", h("r")); })(window.__fastmon.q);</script>Skip it if you don't care about the first few hundred milliseconds of error coverage.
Count visitors without JavaScript
A <noscript> pixel records a page view for visitors with JavaScript
disabled. It carries no Web Vitals (there's no JS to measure them), just
the page view. Goes anywhere in the <head> after the tracker tag:
<noscript><img src="https://fastmon.site/c/{collector_hash}.gif" alt="" width="1" height="1" referrerpolicy="no-referrer-when-downgrade" /></noscript>Where the beacons go
The collector setting on the application decides the host in the snippet above.
fastmon (default)
Script and beacons load from fastmon.site. Nothing to configure. It is
third-party from your site's perspective, so a strict content blocker
can block it.
Same-origin (relative)
Recommended, if you can put a reverse proxy in front of your site.
The snippet uses host-less paths (/s/…, /c/…), so script and beacons
come from your domain. They're first-party and indistinguishable
from your own resources, which means content blockers don't strip them
and your visit counts stay complete. You proxy the two path prefixes to
fastmon. For nginx:
location ~ ^/(s|c)/ { proxy_pass https://fastmon.site; proxy_set_header Host fastmon.site; proxy_set_header X-Forwarded-For $remote_addr;}Any reverse proxy or CDN works the same way: forward /s/ and /c/ to
https://fastmon.site and preserve the client IP header.
Smoxy
If your site runs behind Smoxy, it's two steps in the dashboard, no config file.
- Add fastmon as an origin. Under Backends in your organization,
click Origin hinzufügen and fill in: Name
fastmon, Protokollhttps, Adressefastmon.site, Port443. - Route the two prefixes to it. Under Regeln, create a
Conditional Rule whose condition is URI Entspricht
^/(s|c)/, then open the rule's Einstellungen tab and pick thefastmonorigin under Routing.
Everything else on the zone keeps its normal origin; only /s/ and
/c/ go to fastmon. Matching rules stack, so set stop only if you
deliberately want to skip the rules after this one.
Custom domain
Same first-party benefit, but you point the snippet at a collector host
you control (metrics.example.com) instead of relative paths. Useful
when one application spans several domains and you want a single stable
collector host.
What's next
- Verify it works: a five-second DevTools check.
- Tune what gets collected: presets.
- Privacy: what we don't collect, handy when legal asks.
- Tag deploys for before/after comparisons: Compare releases.