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 http://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 http://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="http://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