Skip to content

Repository files navigation

Shepherd

An unofficial Progressive Web App (PWA) for GoatCounter analytics. Track your website analytics on the go with a mobile-friendly interface that works against the official goatcounter.com SaaS, self-hosted GoatCounter instances, and custom domains.

Features

  • Real-time analytics from multiple GoatCounter sites in one place
  • Trend chart of visitors over the selected range, built from the /stats/total time-series (hourly buckets for sub-day ranges, daily otherwise)
  • Top pages with referrer drill-down — tap any page to see where its visits came from
  • Browser + OS breakdowns
  • Visitor map with country flags and color-coded intensity bars
  • Flexible date ranges: hourly (1H, 6H, 12H) and daily (1D, 7D, 30D, all-time)
  • Adaptive rate limiting — respects GoatCounter's X-Rate-Limit-* response headers, so it works correctly under any rate-limit configuration without code changes
  • Self-hosted & custom-domain support — enter a full URL like https://stats.example.com; bare codes like myblog are also accepted and expanded to myblog.goatcounter.com
  • Offline support with smart caching
  • PWA: installable on mobile and desktop
  • Android APK companion — distributed via GitHub Releases for Obtainium pickup (see docs/ANDROID.md)

Getting Started

A free hosted version may be available; for production use, please self-host or fork.

Prerequisites

  • Node.js 18 or higher
  • pnpm (recommended) — npm install -g pnpm
  • A GoatCounter account with API access

Installation

git clone https://github.com/serrodneyrich/Shepherd.git
cd Shepherd
pnpm install
pnpm dev

Open http://localhost:3000.

Configuration

Option 1: UI Configuration (recommended for public instances)

  1. Open the app and navigate to Settings.
  2. Enter your GoatCounter API key.
    • GoatCounter dashboard → click @Username (top-right) → Settings → API
    • Generate an API key with Read Sites and Read Statistics permissions only
    • ⚠️ Never use a key with write permissions — the API key is stored in browser localStorage and is visible to anyone with device access
  3. Click Save & Validate API Key. If your GoatCounter instance is v2.7 or newer, Shepherd verifies the key against /api/v0/me and shows a green checkmark with your account email. Older instances skip validation (the key is still saved).
  4. Add your sites. The "Site URL" field accepts:
    • Full URLs for self-hosted GoatCounter or custom domains: https://stats.example.com
    • Bare codes (legacy, automatic): mybloghttps://myblog.goatcounter.com

⚠️ Security note: Your API key is stored in browser localStorage. Anyone with device access can retrieve it. Use only on trusted devices.

Option 2: Environment Variable (self-hosted deployments only)

⚠️ WARNING: For self-hosted/forked deployments only. Do NOT use this for public instances — NEXT_PUBLIC_* variables are embedded in the client bundle and visible to all visitors.

echo "NEXT_PUBLIC_GOATCOUNTER_API_KEY=your_read_only_api_key" > .env.local

Use read-only API keys only.

Rate Limiting

Shepherd reads GoatCounter's X-Rate-Limit-Remaining and X-Rate-Limit-Reset response headers and paces requests adaptively. There is no fixed delay — when the budget runs low, Shepherd waits until the window refills; when there's plenty of budget, requests fire as fast as needed (with a 100ms floor between consecutive requests to avoid bursts).

This means Shepherd correctly handles GoatCounter's:

  • v2.5 and earlier: 4 req / 10 sec
  • v2.6.0+: 4 req / sec
  • Future increases: handled automatically with no code change
  • Self-hosted with custom -ratelimit: also handled automatically

On 429, Shepherd backs off using X-Rate-Limit-Reset and retries up to 3 times. On 5xx, it retries with exponential backoff and jitter.

Rate-limit state is shared across browser tabs via BroadcastChannel so multiple open tabs never together exceed the budget.

Caching

  • 5-minute in-memory cache for API responses (LRU, max 100 entries)
  • In-flight request deduplication: simultaneous requests for the same data share a single network call
  • Service-worker NetworkFirst cache for offline support (5-minute TTL)
  • Per-site, per-range cache layered on top of all the above, configurable via the auto-fetch interval setting

Android APK

The repo ships a companion Android APK built via Bubblewrap (Trusted Web Activity). Tagging a release on GitHub triggers a CI build that signs and attaches shepherd-X.Y.Z.apk to the GitHub Release.

To install via Obtainium:

  1. Open Obtainium → Add App
  2. URL: https://github.com/serrodneyrich/Shepherd
  3. Source: GitHub
  4. Obtainium picks up the latest .apk and offers updates as new releases tag.

For maintainer setup (keystore, GitHub Secrets, assetlinks), see docs/ANDROID.md.

Security

Client-side architecture

Shepherd is a client-side PWA — all code runs in your browser, API calls go directly from your device to GoatCounter, no Shepherd backend is involved.

API key best practices

  1. Use read-only API keys (Read Sites + Read Statistics only)
  2. Never share API keys
  3. Use only on trusted devices
  4. Self-host for production

Limitations

  • API keys are stored in browser localStorage (unencrypted)
  • Anyone with device or DevTools access can read the key
  • This is inherent to client-side PWA architecture

Reporting security issues

Do not open a public GitHub issue. Use GitHub's private security advisory feature or email the maintainer.

Contributing

PRs welcome. Run pnpm lint before submitting. The dashboard styling is intentionally minimal and dark-themed — if you see things you'd improve in the GoatCounter web UI itself, those PRs probably belong upstream (github.com/arp242/goatcounter).

License

MIT.

Acknowledgments

  • GoatCounter — the privacy-friendly analytics platform Shepherd is built for. Thanks to Martin Tournoij for the helpful feedback that shaped this revision.
  • The open-source community for the tools and libraries.

Disclaimer

Unofficial third-party application. Not affiliated with or endorsed by GoatCounter.

About

Unofficial Goat Counter PWA

Resources

Stars

4 stars

Watchers

1 watching

Forks

Contributors

Languages