A self-hosted solution to monitor your WebRTC application, Peermetrics offers fully open source client SDKs, back-ends and dashboards so you can troubleshoot issues, optimize performance, and deliver better user experiences.
For scale, large workloads, production environments, or organizations preferring to focus on their core application rather than infrastructure management, WebRTC.ventures offers both managed service and custom implementations. Reach out to WebRTC.ventures.
- About
- Features
- How it works
- Demo
- Tech stack
- How to run locally
- How to Deploy
- Development
- How to integrate
- Authentication
- Other
- FAQ
Starting with the javascript SDK you can integrate with all the major WebRTC libs (Livekit, Mediasoup, Janus, etc.) or your custom implementation.
This repo contains the services that are used to ingest and visualize those metrics:
The app dashboard is the best way to get an overview of how your users are experiencing your app. On top of the usual metrics (browsers, OS, location, etc) you can see the most common issues overall so you know on what to focus.
Get detailed reports for each participant (how they connected, their devices) and automatically detected issues.

Drilldown into each participant's connection to get insights about how their connection behaved during the whole call.

Try the live DEMO.
peer metrics contains all the components you need to monitor and improve your WebRTC app:
- client SDKs: used for collecting metrics from client devices (right now we only support the JavaScript SDK).
- ingestion endpoint: this is a server where the SDK sends the metrics collected (this is the api service).
- visualization endpoint: used by the dev / customer team to visualize the metrics collected (this is the web service).
The reason for separating into api and web it's because the services have different scaling needs.
Both api and web have the same backend:
- Language: Python 3.8
- Framework: Django
- DB: Postgres
- Template rendering: Jinja2
- Frontend: VueJS
Fastest way to get started is to pull this repo and use docker compose
git clone https://github.com/peermetrics/peermetrics
cd peermetricsOption A: Using Docker Hub images (may have migration issues)
You can start all containers using the pre-built images:
docker compose upOption B: Using development setup (Recommended)
For a more reliable setup that builds from source and includes all migrations:
# First, clone the api and web repos in the same parent directory
git clone https://github.com/peermetrics/api
git clone https://github.com/peermetrics/web
cd peermetrics
# Then use the dev docker-compose file
docker compose -f docker-compose.dev.yaml upThe API service will automatically:
- Run database migrations
- Create the default admin user (username:
admin, password:admin) - Start the application
Note: For production deployments, make sure to change the default admin password via environment variables (see Authentication section).
Because peer metrics consists for two services, both need to be deployed independently.
This also offers the flexibility to scale them separately.
There are multiple ways to deploy peer metrics:
The recommended way for deploying is to use Docker.
There are 2 images on Docker Hub:
- api:
peermetrics/api - web:
peermetrics/web
For inspiration on how to use the images with Docker Compose check the files:
To deploy both containers on the same server look at docker-compose.yaml
You also have the option to deploy the app as a Google App engine service.
Each service repo has a app_engine.yaml file that will help you deploy both services to App engine.
Check the files for web and api.
Both the api and web services are configured via environment variables. The tables below list every available variable, which service uses it, and whether it is required.
| Variable | Required | Default | Description |
|---|---|---|---|
| Django Core | |||
DEBUG |
No | False |
Enable Django debug mode. Set to True for development only. |
DJANGO_SETTINGS_MODULE |
Yes | - | Must be set to api.settings. |
SECRET_KEY |
Yes | - | Django secret key for cryptographic signing. Use a long random string in production. |
ALLOWED_HOSTS |
No | * |
Comma-separated list of allowed hostnames. |
URL_PREFIX |
No | "" |
URL prefix when serving under a subpath (e.g. /peermetrics). Nginx must have matching locations. |
| Authentication | |||
INIT_TOKEN_SECRET |
Yes | - | Secret used to sign JWT tokens returned by the /initialize endpoint. Used by the SDK to authenticate. |
SESSION_TOKEN_SECRET |
Yes | - | Secret used to sign JWT tokens returned by the /sessions endpoint. |
| Admin User | |||
DEFAULT_ADMIN_USERNAME |
No | admin |
Username for the auto-created admin account on first startup. |
DEFAULT_ADMIN_PASSWORD |
No | admin |
Password for the auto-created admin account. Change in production. Must match the web service value. |
DEFAULT_ADMIN_EMAIL |
No | admin@admin.com |
Email for the auto-created admin account. |
| Web Domain | |||
WEB_DOMAIN |
Yes | - | Domain where the web dashboard is hosted (e.g. localhost:8080). Used for CORS and generating links. Do not include the protocol. |
| Database | |||
DATABASE_HOST |
Yes | - | PostgreSQL server hostname. |
DATABASE_PORT |
Yes | - | PostgreSQL server port (typically 5432). |
DATABASE_USER |
Yes | - | PostgreSQL username. |
DATABASE_PASSWORD |
Yes | - | PostgreSQL password. |
DATABASE_NAME |
Yes | - | PostgreSQL database name. |
CONN_MAX_AGE |
Yes | - | Database connection lifetime in seconds (e.g. 600). Set to 0 to close connections after each request. |
| Redis | |||
REDIS_HOST |
No | - | Redis connection URL (e.g. redis://127.0.0.1:6379). If not set, caching is disabled. For TLS use rediss://. |
| GeoIP / Map | |||
USE_EXTERNAL_GEOIP_PROVIDER |
No | False |
Set to True to enable GeoIP lookups for participant location data. Required for the map on the dashboard to show participant locations. |
IPSTACK_URL |
No | - | Base URL for the ipstack API. Set to http://api.ipstack.com. Note: ipstack's free plan only supports HTTP, not HTTPS. Required when USE_EXTERNAL_GEOIP_PROVIDER is True. |
IPSTACK_ACCESS_KEY |
No | - | Your ipstack API access key. Get one at ipstack.com/signup. Required when USE_EXTERNAL_GEOIP_PROVIDER is True. |
| Data Management | |||
POST_CONFERENCE_CLEANUP |
No | False |
If True, deletes raw stats events after a conference ends to save storage. Conference summaries are kept. See FAQ. |
| Google Cloud Tasks | |||
USE_GOOGLE_TASK_QUEUE |
No | False |
Set to True to use Google Cloud Tasks for background processing (App Engine deployments). |
GOOGLE_TASK_QUEUE_NAME |
No | - | Name of the Cloud Tasks queue (e.g. queue-1). Required when USE_GOOGLE_TASK_QUEUE is True. |
APP_ENGINE_LOCATION |
No | - | App Engine location (e.g. us-east1). Required when USE_GOOGLE_TASK_QUEUE is True. |
TASK_QUEUE_DOMAIN |
No | - | Domain for task queue callbacks (e.g. https://api.example.com/). Required when USE_GOOGLE_TASK_QUEUE is True. |
| Google Cloud Logging | |||
USE_GOOGLE_CLOUD_LOGGING |
No | False |
Set to True to send logs to Google Cloud Logging. Only applies when deployed on GCP. |
| Variable | Required | Default | Description |
|---|---|---|---|
DEBUG |
No | False |
Enable Django debug mode. Set to True for development only. |
DJANGO_SETTINGS_MODULE |
Yes | - | Must be set to web.settings. |
SECRET_KEY |
Yes | - | Django secret key. Can be different from the API service key. |
ALLOWED_HOSTS |
No | * |
Comma-separated list of allowed hostnames. |
URL_PREFIX |
No | "" |
URL prefix when serving under a subpath (e.g. /peermetrics). Must match nginx configuration. |
DEFAULT_ADMIN_PASSWORD |
No | admin |
Used to detect if the user is logging in with the default password and prompt for a change. Must match the API service value. |
API_ROOT |
Yes | - | Full URL to the API endpoint including /v1 (e.g. http://localhost:8081/v1). The web service uses this to fetch data from the API. |
COOKIE_DOMAIN |
No | - | Domain for the session cookie. Only needed when API and web are on different subdomains. |
DATABASE_HOST |
Yes | - | PostgreSQL server hostname (same database as the API service). |
DATABASE_PORT |
Yes | - | PostgreSQL server port. |
DATABASE_USER |
Yes | - | PostgreSQL username. |
DATABASE_PASSWORD |
Yes | - | PostgreSQL password. |
DATABASE_NAME |
Yes | - | PostgreSQL database name. |
CONN_MAX_AGE |
Yes | - | Database connection lifetime in seconds. |
| Variable | Required | Default | Description |
|---|---|---|---|
POSTGRES_USER |
Yes | - | PostgreSQL superuser username (used by the postgres container). |
POSTGRES_PASSWORD |
Yes | - | PostgreSQL superuser password (used by the postgres container). |
POSTGRES_DB |
Yes | - | PostgreSQL database name to create on startup (used by the postgres container). |
To start developing peer metrics locally:
Clone this repo:
git clone https://github.com/peermetrics/peermetrics && cd peermetricsThen clone api and web:
git clone https://github.com/peermetrics/webgit clone https://github.com/peermetrics/apiTo start development start Docker using the special dev file:
docker compose -f docker-compose.dev.yaml upThe API service will automatically run migrations and create the default admin user on first startup.
Note: For development with local code changes, you may need to run migrations manually if you modify models:
docker compose -f docker-compose.dev.yaml exec api python manage.py makemigrations app
docker compose -f docker-compose.dev.yaml exec api python manage.py migrateStart the watcher for the vue files:
cd web
npm install
npm run watchTo integrate peer metrics into your WebRTC app you need to follow these steps:
- Deploy the api / web images using Docker or any of the options found in How to deploy.
- Access the web service, create a new organization and app. There will be an API key associated with the new app.
- Integrate the Javascript SDK following the steps listed here.
- When initializing the JS SDK, use an additional attribute
apiRootto start using your custom API endpoint.
For example, if you deployed the api endpoint at api.example.com, the initializing object will become:
let peerMetrics = new PeerMetrics({
apiRoot: 'https://api.example.com/v1',
apiKey: '7090df95cd247f4aa735779636b202', // api key from the newly created app
userId: '1234',
userName: 'My user',
conferenceId: 'conference-1',
conferenceName: 'Conference from 4pm',
appVersion: '1.0.1'
})Note: very important that apiRoot is a valid URL and ends with /v1
- Follow the instructions in the SDK repo to start collecting metrics.
Peermetrics includes an authentication system that helps ensure secure access to your monitoring dashboards while maintaining ease of use during initial setup.
When you first start Peermetrics, a default admin account is automatically created:
- Username:
admin - Password:
admin
You can log in to the web interface at http://localhost:8080/login using these credentials.
-
Automatic Detection: When you log in with the default password (
admin), you'll be automatically redirected to a password change page with a security warning. -
Password Change Prompt: You'll see a clear message indicating you're using the default password and should change it.
-
Skip Option: During development, you can skip the password change, but you'll be prompted again on your next login.
-
Password Requirements: New passwords must be at least 8 characters long and pass Django's password validation checks.
To change your password:
- Log in with default credentials
- You'll be redirected to the password change page
- Enter your new password twice
- Click "Change Password"
Alternatively, navigate to /change-password anytime while logged in.
- Backup Recovery: If you lose admin access:
# Access the API container docker compose exec api sh # Create a new superuser or reset password python manage.py createsuperuser # or python manage.py changepassword admin
For production deployments, you should customize the default admin credentials using environment variables. This is especially important when deploying with Docker.
Set these environment variables in your docker-compose.yaml or .env files:
For API Service (creates the admin user):
environment:
DEFAULT_ADMIN_USERNAME: "admin" # Default: admin
DEFAULT_ADMIN_PASSWORD: "your_secure_password" # Default: admin
DEFAULT_ADMIN_EMAIL: "admin@yourcompany.com" # Default: admin@admin.comFor Web Service (detects default password on login):
environment:
DEFAULT_ADMIN_PASSWORD: "your_secure_password" # Must match API serviceservices:
api:
image: peermetrics/api:latest
environment:
DEFAULT_ADMIN_USERNAME: "superadmin"
DEFAULT_ADMIN_PASSWORD: "MySecureP@ssw0rd123!"
DEFAULT_ADMIN_EMAIL: "admin@mycompany.com"
# ... other environment variables
web:
image: peermetrics/web:latest
environment:
DEFAULT_ADMIN_PASSWORD: "MySecureP@ssw0rd123!" # Must match!
# ... other environment variablesImportant Notes:
- The
DEFAULT_ADMIN_PASSWORDmust be the same in both web and API services for the default password detection to work correctly - The admin user is created only once during the first startup (idempotent operation)
- If the admin user already exists, the initialization script will skip creation
- Change these values before your first deployment to production
To protect against brute force attacks, the login endpoint includes rate limiting:
- Limit: 5 login attempts per 5 minutes per IP address
- Behavior: After exceeding the limit, users will see an error message: "Too many login attempts. Please try again in a few minutes."
- Scope: Rate limiting applies per IP address, so multiple users behind the same NAT won't interfere with each other excessively
The rate limiting is implemented using django-ratelimit.
To run migration for the DB you need to use the api container:
docker compose run api python manage.py migrateIn order to debug conferences, events, etc you can use the Admin section in the api container.
For that, you need to create a superuser:
# sh into the api container
docker compose run api sh
# run the createsuperuser command
python manage.py createsuperuser --username admin --email admin@admin.com
# it will ask for you to choose a passwordYou'll also need to collectstatic:
python manage.py collectstatic --clear --noinputIf you want to add some dummy data while developping, run this script (last number is the number of past days to populate):
docker compose -f docker-compose.dev.yaml run api python populate_db.py 5For web you have the following commands:
- compile CSS
npm run css- start CSS watcher
npm run css-watchWe believe PostgreSQL is more than suited for the job. It is a very powerful DB and you can get a lot out of it with just vertical scaling. We use PostgreSQL for our production environment and we've been really happy with it.
The big advantage with this option is that it a well-understood technology, widely supported, cheap to scale, etc.
If your team reaches a point where the limiting factor is PostgreSQL, we would love to offer support for other options.
The GenericEvent model takes a big percentage of the data stored in the DB. Drilling down, a big percentage of that is made of stats events. At the end of the conference, we go through all of those events and create a summary, so the events are not really needed afterwards.
This flag will delete all the stats events for the just ended conference.


