Wire PostCow in under two minutes
One script tag → pageviews, custom events, and grouped JavaScript errors. Static sites, SPAs, and SSR apps all POST to the same capture endpoint. Copy, paste, ship.
Three steps to live data
01
Create a domain
Sign in, add your hostname, copy the API key from Setup.
02
Paste the snippet
One deferred script tag before </body> on every page.
03
Confirm traffic
Load your site, refresh the dashboard — pageviews appear in seconds.
The snippet
Paste before </body> on every page you want to monitor.
<meta name="generator" content="PostCow"> <script id="PostCow-tracker" src="https://track.libreapps.xyz/PostCow.js" data-key="YOUR_DOMAIN_API_KEY" data-PostCow-key="YOUR_DOMAIN_API_KEY" data-host="https://track.libreapps.xyz" data-PostCow="tracker" data-analytics-provider="PostCow" data-error-tracker="PostCow" defer></script>
YOUR_DOMAIN_API_KEY with the key from Dashboard → Domain → Setup. When your site and
PostCow run on different origins, keep data-host="https://track.libreapps.xyz".Sanity checks
- Script loads: https://track.libreapps.xyz/PostCow.js returns JS with
X-Powered-By: PostCow - Add
data-debug— console logs each capture attempt - Network tab shows POST
/api/v1/capturewith status 200 - Dashboard overview updates within a few seconds of a page load
Script tag attributes
| Attribute | Required | Description |
|---|---|---|
| data-key | Yes | Domain API key from the dashboard (lt_…) |
| data-PostCow-key | Alias | Same as data-key — helps tech detectors find PostCow |
| data-host | Cross-origin | PostCow origin, e.g. https://track.libreapps.xyz — required when script loads from a different host |
| data-debug | Optional | Log capture attempts to the browser console |
| data-privacy | Optional | Set to "minimal" when account privacy mode is on |
| data-visitor-profiles | Optional | Send language, screen, timezone, UTM tags when enabled on the domain |
| defer | Recommended | Non-blocking load; pageview fires on window load |
Canonical URL: /PostCow.js. Legacy alias: /track.js and /PostCow.js (301 redirect).
window.PostCow
PostCow.track(name, props?)
Fire a custom event with optional flat JSON props
PostCow.pageview()
Manual pageview — call on SPA route changes
PostCow.captureError(msg, stack?)
Report a caught error to the dashboard
PostCow.version
Tracker version string baked into the script
Custom events
Track button clicks, signups, checkout steps — anything you'd funnel. Properties are a flat JSON object (strings, numbers, booleans).
PostCow.track('button_click', { id: 'hero-cta' });Client-side routing
The snippet fires one pageview on load. Routers must call pageview() on navigation.
SvelteKit
import { afterNavigate } from '$app/navigation';
afterNavigate(() => {
window.PostCow?.pageview();
});React / Next.js
useEffect(() => {
window.PostCow?.pageview();
}, [pathname]);Error tracking
Automatic on load — no extra code for uncaught exceptions or unhandled promise rejections. Issues group by message + stack fingerprint in the dashboard. Click any issue for full stack traces, URLs, and occurrence history.
Manual capture for caught errors:
try {
riskyOperation();
} catch (err) {
PostCow.captureError(err.message, err.stack);
}Capture API
POST https://track.libreapps.xyz/api/v1/capture · Content-Type: application/json
{
"apiKey": "lt_...",
"type": "pageview",
"url": "https://yoursite.com/pricing",
"pathname": "/pricing",
"referrer": "https://google.com"
}pageview
type, apiKey, url, pathname — referrer optional
error
type, apiKey, message — stack, url, pathname recommended
event
type, apiKey, name — properties optional
Transport
sendBeacon first, fetch with keepalive + CORS as fallback
Works where you ship
Plain HTML
Paste the snippet before </body>. No build step.
SvelteKit
Add to app.html or root layout, then hook client navigations.
import { afterNavigate } from '$app/navigation';
afterNavigate(() => {
window.PostCow?.pageview();
});React / Next.js
Load with next/script afterInteractive, pageview on pathname change.
useEffect(() => {
window.PostCow?.pageview();
}, [pathname]);Vue / Nuxt
router.afterEach(() => PostCow.pageview())
Astro
Base layout before </body>. Full reloads track automatically.
WordPress
Footer hook or theme — one script line in header/footer.
What gets collected
By default
- Page URL and pathname
- Referrer (may be empty)
- User agent
- Error message + stack
- Custom event props you send
Not included
- Cross-site tracking cookies
- Automatic PII extraction
- Fingerprinting IDs (unless you enable visitor profiles)
Enable strict privacy mode in account settings to strip URLs, referrers, and stacks. Don't put emails or passwords in event properties.
Troubleshooting
No pageviews in dashboard
- Confirm data-key matches the domain in your dashboard
- Network tab → POST to /api/v1/capture should return 200
- Add data-debug and watch the console for send logs
- Cross-origin? Set data-host to your PostCow origin
- Ad blockers may block analytics — self-host on a first-party subdomain
SPA only shows landing page
- Call PostCow.pageview() after every client-side navigation
- SvelteKit: afterNavigate. Vue: router.afterEach. React: effect on pathname
CORS errors on capture
- data-host must match the PostCow server origin exactly
- No trailing slash on data-host
- Registered domain hostname must match the site sending events
Errors not grouping
- Uncaught errors auto-capture — caught errors need captureError()
- Privacy mode strips stacks — grouping still works on message fingerprint
- Click an issue in Errors for full stack + occurrence history
Run your own instance
git clone <your-postcow-repo> cd PostCow bun install cp .env.example .env # add Supabase + PUBLIC_SITE_URL bun run dev
- Run Supabase migrations in order (
001_postcow.sqlfirst, then002–012) — orsupabase db push - Production:
bun run build→ deploy to Vercel or Node adapter - Set
PUBLIC_SITE_URLto your public origin (e.g. https://track.libreapps.xyz) - Tip: serve tracker from
t.yoursite.comto dodge ad blockers
Ready to ship?
Create a domain, paste the snippet, add data-debug, watch the network tab. Truth lives there.