Integration guide

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.

~2 KB tracker POST /api/v1/capture CORS-ready Self-hostable
Quick start

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.

Install

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>
Replace 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".
Verify

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/capture with status 200
  • Dashboard overview updates within a few seconds of a page load
Reference

Script tag attributes

AttributeRequiredDescription
data-keyYesDomain API key from the dashboard (lt_…)
data-PostCow-keyAliasSame as data-key — helps tech detectors find PostCow
data-hostCross-originPostCow origin, e.g. https://track.libreapps.xyz — required when script loads from a different host
data-debugOptionalLog capture attempts to the browser console
data-privacyOptionalSet to "minimal" when account privacy mode is on
data-visitor-profilesOptionalSend language, screen, timezone, UTM tags when enabled on the domain
deferRecommendedNon-blocking load; pageview fires on window load

Canonical URL: /PostCow.js. Legacy alias: /track.js and /PostCow.js (301 redirect).

API

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

Events

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' });
SPAs

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]);
Errors

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);
}
HTTP

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

Frameworks

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.

Privacy

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.

Debug

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
Self-host

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.sql first, then 002012) — or supabase db push
  • Production: bun run build → deploy to Vercel or Node adapter
  • Set PUBLIC_SITE_URL to your public origin (e.g. https://track.libreapps.xyz)
  • Tip: serve tracker from t.yoursite.com to dodge ad blockers
Get started

Ready to ship?

Create a domain, paste the snippet, add data-debug, watch the network tab. Truth lives there.