Install Graytower
Add your Website's tracking snippet, deploy it, and confirm the first pageview.
Install the tracker on the pages you want to measure.
Before you start
You need a Graytower Website and access to edit your site's shared layout or HTML template.
Copy your tracking details
Open Website → Settings → Tracking and select Copy snippet. The single script tag already includes your registered domain and browser write key.
Choose Visitor identity first. The default snippet uses /js/script.js; cookieless tracking uses /js/script.cookieless.js. After switching modes, redeploy the newly generated snippet.
Add Graytower to your site
Choose how your site is built. Install Graytower once in the shared layout so it loads on every page you want to measure. Install the tracker once per page. Subdomains need the same Website's snippet on each host you want to measure.
<script
defer
src="https://graytower.app/js/script.js"
data-domain="northstar.app"
data-write-key="YOUR_BROWSER_WRITE_KEY"
></script>Place the tag in your shared <head> before </head>.
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<Script
src="https://graytower.app/js/script.js"
strategy="afterInteractive"
data-domain="northstar.app"
data-write-key="YOUR_BROWSER_WRITE_KEY"
/>
</head>
<body>{children}</body>
</html>
);
}Add the script to your root layout so Graytower loads on every route. Do not paste the HTML tag directly into TSX. If your root layout already contains a <head>, add the script there instead of creating a second one.
Calls before the tracker loads
The single tag handles automatic pageviews, route changes, and HTML events. It defines window.graytower when the external script executes. If your app calls the JavaScript API before then, add this optional queue before the tracker tag:
<script>
window.graytower = window.graytower || function () {
(window.graytower.q = window.graytower.q || []).push(arguments);
};
</script>The tracker replays queued calls in order after its initial pageview. In a Next.js App Router root layout, put the same bootstrap in an inline next/script with strategy="beforeInteractive" before the external script. This inline bootstrap needs a CSP nonce, hash, or permission for inline scripts if you use a strict Content Security Policy.
Consent and Content Security Policy
If your laws or policies require consent, configure your consent manager to block the Graytower script until consent is granted.
For a strict Content Security Policy, allow https://graytower.app in both script-src and connect-src. If you use the optional inline queue, also authorize that inline script with a nonce or hash. Ad blockers or blocked scripts reduce tracking coverage.
Content-Security-Policy: script-src 'self' https://graytower.app; connect-src 'self' https://graytower.appThe first-party _gt_id cookie is set on load. Reloads of the same path within 60 seconds are not stored and do not count toward the Workspace's tracked-event allowance. Client-side route changes that update the pathname send a pageview.
Deploy your changes
Deploy the updated site before verifying. Graytower cannot verify code that only exists locally.
Verify tracking
Visit a page on your deployed domain. Return to Website → Settings → Tracking. The status should change from Waiting for tracking activity to Receiving events and show a last stored pageview time. Select Verify installation if it still says Waiting. See Verify tracking for the status meanings and a short diagnostic path.
If Graytower isn't detected
If verification fails, these are the most common causes:
- Changes have not been deployed
- The Website or write key is incorrect
- A Content Security Policy is blocking the tracker
- A consent manager has not allowed it
- A browser extension is blocking analytics