Self Host
Local Setup

Local Setup

This guide walks you through setting up Traceway on your local machine for development.

Prerequisites

  • Go 1.26 (the toolchain line in backend/go.mod is the exact version)
  • Node.js 22 and npm (frontend/package.json pins 22.x and the repo sets engine-strict)
  • Nothing else for the default build: both databases are SQLite files created on first start
  • ClickHouse and PostgreSQL only when building with -tags "transactional_pg telemetry_ch"

Database Setup

ClickHouse

  1. Install ClickHouse following the official installation guide (opens in a new tab)

  2. Start ClickHouse server

  3. Create a database:

CREATE DATABASE traceway
  1. The default user (default with empty password) works for local development

PostgreSQL

  1. Install PostgreSQL following the official installation guide (opens in a new tab)

  2. Create a user and database:

CREATE USER traceway WITH PASSWORD 'your_password';
CREATE DATABASE traceway OWNER traceway;

Backend Setup

  1. Navigate to the backend folder:
cd backend
  1. Create a .env file with your configuration:
JWT_SECRET=your-secret-key-minimum-32-characters-long
CLICKHOUSE_SERVER=localhost:9000
CLICKHOUSE_DATABASE=traceway
CLICKHOUSE_USERNAME=default
CLICKHOUSE_PASSWORD=
CLICKHOUSE_TLS=false
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DATABASE=traceway
POSTGRES_USERNAME=traceway
POSTGRES_PASSWORD=your_password
POSTGRES_SSLMODE=disable

Environment Variables

VariableDescription
JWT_SECRETSigns all authentication tokens (dashboard sessions and CLI/MCP device logins). Must be at least 32 characters; use a strong, unique secret and keep it stable. See CLI Authentication.
CLICKHOUSE_SERVERClickHouse server address (host:port)
CLICKHOUSE_DATABASEClickHouse database name
CLICKHOUSE_USERNAMEClickHouse username
CLICKHOUSE_PASSWORDClickHouse password (empty for default)
CLICKHOUSE_TLSEnable TLS for ClickHouse connection
POSTGRES_HOSTPostgreSQL server host
POSTGRES_PORTPostgreSQL server port
POSTGRES_DATABASEPostgreSQL database name
POSTGRES_USERNAMEPostgreSQL username
POSTGRES_PASSWORDPostgreSQL password
POSTGRES_SSLMODEPostgreSQL SSL mode (disable, require, etc.)
APP_BASE_URLPublic URL of your Traceway instance. Used for SDK connection instructions, email links, deep links in notifications, OAuth callback URLs, and the CLI/MCP OAuth issuer plus device-login verification URL. For local dev set this to http://localhost:5173 so OAuth callbacks land on the Vite dev server (which proxies /api back to the Go backend).
GOOGLE_CLIENT_IDOptional. Google OAuth client ID. Setting both Google variables enables the Continue with Google button. See the SSO guide.
GOOGLE_CLIENT_SECRETOptional. Google OAuth client secret.
GITHUB_CLIENT_IDOptional. GitHub OAuth App client ID. Setting both GitHub variables enables the Continue with GitHub button. See the SSO guide.
GITHUB_CLIENT_SECRETOptional. GitHub OAuth App client secret.
OAUTH_SESSION_SECRETOptional. Cookie signing secret for the OAuth round-trip. Falls back to JWT_SECRET when unset.
SESSION_RECORDING_RETENTION_DAYSOptional. Days to keep session recording files on disk under STORAGE_PATH/recordings/. Defaults to 30. Worker runs hourly and on startup. 0 disables; no effect when STORAGE_TYPE=s3.
SQLITE_RETENTION_DAYSOptional. Days to keep SQLite telemetry rows. Defaults to 30. 0 disables. Only applies when running with DB_TYPE=sqlite.
DUCKDB_RETENTION_DAYSOptional. Days to keep telemetry rows on the DuckDB backend (-tags telemetry_duckdb build). Defaults to 30, falling back to SQLITE_RETENTION_DAYS when unset. 0 disables. Pruning runs hourly, so expired rows can linger between runs.
LOG_RECORDS_MAX_ROWSOptional. Caps the log table via a cleanup task that runs every minute and keeps only the newest N rows. Not a hard limit: ingesting more than N rows within a minute exceeds the cap until the next run. Unset or 0 disables. Only applies when running with DB_TYPE=sqlite (SQLite or DuckDB telemetry).

For local OAuth testing, register the provider's callback URL as http://localhost:5173/api/auth/callback/github (or .../google).

  1. Run the backend with the standalone build tags. Without them you get the embedded build, which ignores the ClickHouse and PostgreSQL variables above and opens a local SQLite database instead:
go run -tags "transactional_pg telemetry_ch" ./cmd/traceway

The backend will start on port 8082 and automatically run database migrations.

Frontend Setup

  1. Navigate to the frontend folder:
cd frontend
  1. Install dependencies:
npm install
  1. Start the development server:
npm run dev

The frontend will start on port 5173 and proxy API requests to the backend.

First-Time Registration

When running locally for the first time:

  1. Open your browser to http://localhost:5173 (opens in a new tab)
  2. The login page will automatically redirect you to registration (since no users exist)
  3. Create your user account with email and password
  4. After registration, create your first organization
  5. Create your first project to get a project token

The project token is used by the SDK to send telemetry data.

Connecting Your Application

Once you have a project token, point your application's OpenTelemetry exporter at the local instance. The endpoint is http://localhost:8082/api/otel and the token goes on the Authorization header:

export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:8082/api/otel
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your_project_token"
export OTEL_SERVICE_NAME=my-service

See OpenTelemetry for the full setup, including the per-framework guides.

Troubleshooting

Backend won't start

  • Verify ClickHouse is running: clickhouse-client --query "SELECT 1"
  • Verify PostgreSQL is running: psql -U traceway -d traceway -c "SELECT 1"
  • Check that all environment variables are set correctly

Frontend can't connect to backend

  • Ensure the backend is running on port 8082
  • Check the browser console for CORS or network errors
  • Verify the proxy configuration in vite.config.ts

No data appearing in dashboard

  • Verify your project token matches the one in the SDK configuration
  • Check that your application is making requests
  • Look at the backend logs for any ingestion errors