Installing the snippet
Add one tag to the layout that wraps every page, near the end of <body>, exactly once. Your board shows it with your key filled in.
The tag
Snippet
<script defer src="https://pagehum.com/pagehum.js" data-site="your-site-key"></script>
- Keep
deferanddata-siteas written. The key is public and belongs in your page source. - Put it in the shared layout, not on individual pages, so every page and route counts.
- Load it once. Two copies count every pageview twice.
- Don’t load it inside an iframe, or through a tag manager that drops
data-attributes.
Where it goes in your stack
| Stack | Where |
|---|---|
| Next.js (App Router) | in app/layout.tsx, inside <body>: import Script from "next/script" and render <Script src="https://pagehum.com/pagehum.js" data-site="your-site-key" strategy="afterInteractive" />. |
| Next.js (Pages Router) | in pages/_app.tsx (or _document.tsx), the same <Script … strategy="afterInteractive" />. |
| React with Vite or Create React App | in index.html, just before </body>. |
| Vue / Nuxt | Nuxt: app.head.script in nuxt.config with { src: "https://pagehum.com/pagehum.js", defer: true, "data-site": "your-site-key" }. Plain Vue: index.html. |
| SvelteKit | in src/app.html, just before </body>. |
| Astro | in the base layout every page uses, just before </body>. |
| Plain HTML or a static site generator | in the shared footer or base template, just before </body> (every page, not only the homepage). |
| Rails, Django, Laravel, and other server templates | in the base layout (application.html.erb, base.html, app.blade.php), just before </body>. |
| WordPress | the theme's footer.php just before wp_footer(), or a header-and-footer code plugin's footer section. |
| Shopify | layout/theme.liquid, just before </body>. |
| Webflow, Framer, Squarespace, Wix | site settings → custom code → footer (or "end of body"), applied site-wide. |
Let an AI assistant install it
Each site’s board has a ready-to-copy prompt for Claude, ChatGPT, Cursor, or Copilot: it leads the board of a site that has heard nothing yet and sits under the snippet on live boards. It carries your key and the exact tag, says where it goes for your stack, how to mark success, what not to add, and how to check it worked.
Single-page apps
Nothing extra. The snippet counts a pageview whenever the URL changes through history.pushState or the back and forward buttons, so Next.js, React Router, Vue Router, and SvelteKit routes count on their own.
Content Security Policy
If your site sends a Content-Security-Policy header, allow PageHum in two places: script-src https://pagehum.com to load the snippet, and connect-src https://pagehum.com so it can send counts to https://pagehum.com/api/ingest.
More than one domain
A site key counts beacons from wherever the tag runs. The checked host, the address PageHum checks every five minutes for uptime, is set from the first public host that sends a beacon, and later beacons from other hosts don’t move it. Change it on the board next to the site’s name. For two separate sites, make two site keys.
Check it worked
Open the live site and visit a few pages. In your browser’s network tab, requests to /api/ingest on pagehum.com should succeed, and the console should show no message starting with “PageHum:”. The board fills in within a few minutes. The board’s Send a test beacon button fires counts from PageHum itself, if you want to see the board move before your site is live. More in Troubleshooting.