Traffic Analytics Service - A web analytics proxy for Ghost that processes and enriches traffic data before forwarding it to Tinybird's analytics API.
- User agent parsing for OS, browser, and device detection
- Referrer URL parsing and categorization
- Privacy-preserving user signatures with daily-rotating salts
- Configurable salt storage (in-memory or Firestore)
- Docker-first development with Firestore emulator support
Copy config.example.json
to config.development.json
and configure as needed:
{
"SALT_STORE_TYPE": "memory",
"GOOGLE_CLOUD_PROJECT": "traffic-analytics-dev",
"PORT": 3000,
"LOG_LEVEL": "info",
"PROXY_TARGET": "http://localhost:3000/local-proxy",
"LOG_PROXY_REQUESTS": "true",
"ENABLE_SALT_CLEANUP_SCHEDULER": "true",
"FIRESTORE_DATABASE_ID": "",
"PUBSUB_TOPIC_PAGE_HITS_RAW": "",
"TRUST_PROXY": "true"
}
git clone
this repo &cd
into it as usual- Run
yarn
to install top-level dependencies.
yarn build
to transpile Typescript to JSdocker compose build
oryarn docker:build
to build docker image
yarn dev
start development server locallydocker compose up
oryarn docker:dev
start development server in docker compose (includes Firestore emulator)- View: http://localhost:3000
Sometimes it's useful to test the full setup with Ghost pointing its tracker script to this analytics service running locally. This can be acheived relatively easily with Docker Compose:
- Set the
tinybird:tracker:endpoint
tohttp://localhost/.ghost/analytics/tb/web_analytics
in your Ghost config - Run
docker compose --profile=split up
in your Ghost clone - If you want to test the full e2e flow to Tinybird, set the
PROXY_TARGET=https://api.tinybird.co/v0/events
value in your.env
file in this repo. Otherwise the analytics service will use the/local-proxy
mock endpoint, which does not forward events to Tinybird. - Run
yarn docker:dev:ghost
in the root of this repo - Visit your Ghost site's homepage at
http://localhost
and you should see a successful request in the network tab.
yarn test
run all tests locallydocker compose run --rm test
oryarn docker:test
run all tests in docker compose
yarn lint
run eslint locallydocker compose run --rm lint
oryarn docker:lint
run eslint in docker compose
This project supports running multiple worktrees simultaneously using Docker Compose. Each worktree can run its own isolated development environment with unique ports and container names.
- Create worktrees as usual with git worktree
- Configure each worktree with a unique
.env
file:
# main worktree (.env) - uses defaults
NODE_ENV=development
# work worktree (.env)
NODE_ENV=development
COMPOSE_PROJECT_NAME=traffic-analytics-work
ANALYTICS_PORT=3001
FIRESTORE_PORT=8081
# scratch worktree (.env)
NODE_ENV=development
COMPOSE_PROJECT_NAME=traffic-analytics-scratch
ANALYTICS_PORT=3002
FIRESTORE_PORT=8082
Each worktree runs completely isolated:
- Unique ports: No conflicts between worktrees
- Isolated containers: Auto-generated names like
traffic-analytics-work-analytics-service-1
- Separate volumes: Each worktree has its own
node_modules
volume - Independent projects: Services can run simultaneously
# Start development in any worktree
cd /path/to/worktree
docker compose up
# Each worktree accessible on its configured port
# main: http://localhost:3000
# work: http://localhost:3001
# scratch: http://localhost:3002
Merging to main
automatically deploys to staging. Production deployments only happen when the version in package.json
changes.
To ship to production:
yarn ship
- creates a release branch with version bump- Create PR using the provided link
- Merge the PR - this triggers production deployment
Copyright (c) 2013-2025 Ghost Foundation - Released under the MIT license.