A minimal, self-hosted visitor tracking API that shows both total visitor count and real-time visitor counts per webpage.
Hosted original and example available at herenow.fyi.
- Real-time visitor tracking - See current active visitors on a page
- Total visitor counts - Track all-time unique visitors on a page
- Self-hosted - Full control over your data
- Lightweight widget - Single script tag integration
- Dark/light theme detection - Automatic theme matching
- SPA support - Works with React, Vue, Next.js, etc.
- CORS enabled - Works from any website (domain filtering via allowlist)
Keeping a link to herenow.fyi in your implementation is appreciated but not required, as this helps others discover how to implement here/now.
The easiest way to self-host here/now is with Docker. This bundles everything you need (app + database) in one command.
Prerequisites: Docker installed on your machine.
# Clone the repository
git clone https://github.com/fredrivett/here-now.git
cd here-now
# Configure environment
cp .env.docker.example .env
# Edit .env and set:
# POSTGRES_PASSWORD - any password (e.g., "herenow" for local, strong password for production)
# ALLOWED_DOMAINS - leave as "localhost" for local development, or set to your domain(s) for production
# Start everything
docker compose up -d
# Your API is now running at https://localhost:3210Deploying to production: The same Docker setup works on any server with Docker installed (e.g., DigitalOcean, AWS, your own VPS). Just clone, configure .env with a strong password and your domain, and run docker compose up -d.
Useful commands:
docker compose logs -f # View logs
docker compose down # Stop services
docker compose down -v # Stop and remove database data
docker compose up -d --build # Rebuild after code changes
docker compose exec db psql -U herenow # Access database directlyUse this option if you want to:
- Deploy to serverless platforms (Vercel, Netlify, Cloudflare Workers, etc.)
- Use a managed database service (Supabase, Neon, Railway, etc.)
- Run locally for development
git clone https://github.com/fredrivett/here-now.git
cd here-now
npm installYou can use any database setup you choose, this guide works with Supabase (postgres).
Copy the environment variables:
cp .env.example .envSet up your database:
- Create a free PostgreSQL database at supabase.com
- Go to Connect β Connection String and copy both connection strings
- Update
.envwith your Supabase URLs:DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.[YOUR-DB].supabase.co:6543/postgres?pgbouncer=true" # Transaction Pooler DIRECT_URL="postgresql://postgres:[YOUR-PASSWORD]@db.[YOUR-DB].supabase.co:5432/postgres" # Direct connection
Initialize database:
npm run db:generate # Generates types
npm run db:push # Creates tables in your databaseAdd your allowed domains to .env:
ALLOWED_DOMAINS="localhost,yourdomain.com,yourotherdomain.com"npm run devYour API will be available at https://localhost:3210
Once your server is running (via Docker or local development), add this single line to any webpage where you wish the widget to display:
<div data-herenow></div>Then include the script before the closing </body> tag:
<script src="https://localhost:3210/widget.js" async></script>Replace localhost:3210 with your production URL when deploying.
here-now/
βββ api/
β βββ index.ts # Vercel serverless entry point
βββ src/
β βββ app.ts # Express app configuration
β βββ server.ts # Standalone server entry point
β βββ controllers/ # Request handlers
β β βββ trackController.ts
β β βββ statsController.ts
β β βββ widgetController.ts
β βββ routes/ # Route definitions
β β βββ track.ts
β β βββ stats.ts
β β βββ widget.ts
β βββ middleware/ # Custom middleware
β β βββ cors.ts
β βββ lib/ # Utilities & external services
β β βββ prisma.ts
β β βββ constants.ts
β βββ types/ # TypeScript type definitions
β βββ index.ts
βββ prisma/
β βββ schema.prisma # Database schema
βββ Dockerfile # Multi-stage Docker build config
βββ docker-compose.yml # Docker orchestration (app + database)
βββ package.json
βββ tsconfig.json
βββ vercel.json # Vercel deployment config
βββ .env.example # Environment variables for Node.js setup
βββ .env.docker.example # Environment variables for Docker setup
The widget automatically calls these on page load so you don't need to implement them, but these are the API endpoints available:
POST /api/track
Content-Type: application/json
{
"domain": "yourdomain.com",
"path": "/blog/post-1",
"user_id": "optional-user-id",
"session_id": "optional-session-id"
}GET /api/stats?domain=yourdomain.com&path=/blog/post-1Response:
{
"here": 42,
"now": 3,
"domain": "yourdomain.com",
"path": "/blog/post-1"
}GET /widget.jsReturns the JavaScript widget code.
GET /healthReturns { "status": "ok", "service": "here-now-api" } - used for health monitoring and Docker healthchecks.
This project works great with serverless platforms. Here are some options:
The project includes Vercel configuration out of the box (vercel.json and api/index.ts).
- Push your code to GitHub
- Import the repo in Vercel
- Add environment variables (
DATABASE_URL,DIRECT_URL,ALLOWED_DOMAINS) - Deploy
Netlify, Railway, Render: These platforms can run the Node.js server directly. Set environment variables and use npm run build && npm start as your start command.
Database options: Any PostgreSQL provider works - Supabase, Neon, Railway, or your own PostgreSQL instance.
When using Docker (Option A), configure these in your .env file:
| Variable | Required | Description |
|---|---|---|
POSTGRES_PASSWORD |
β | Database password (any password for local, strong for production) |
ALLOWED_DOMAINS |
β | Comma-separated list of allowed domains |
API_BASE_URL |
β | Base URL for widget API calls (auto-detected from request) |
Note: DATABASE_URL and DIRECT_URL are automatically configured by docker-compose.
When using Node.js with an external database (Option B), configure these in your .env file:
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
β | PostgreSQL connection string (with pgbouncer for pooling) |
DIRECT_URL |
β | Direct database connection (for migrations) |
ALLOWED_DOMAINS |
β | Comma-separated list of allowed domains |
API_BASE_URL |
β | Base URL for widget API calls (auto-detected from request) |
Contributions welcome! Please read our contributing guidelines and submit pull requests.
MIT License - see LICENSE file for details.
- Hosted Version: herenow.fyi
- Issues: GitHub Issues