# Installation (/docs/installation)



This page is the shortest install path. For a guided decision tree across runtime and data options, start with [Getting started](/docs/getting-started). If you only want to instrument a service with an SDK, jump to [SDKs](/docs/sdks).

## Prerequisites [#prerequisites]

* **Docker** for the all-in-one local image and the Astronomy Shop demo.
* **Node.js 22+ and pnpm 10+** for local repo development and scripts.
* A POSIX shell such as bash or zsh.

## Fastest first run: prebuilt image [#fastest-first-run-prebuilt-image]

The release image is published to GitHub Container Registry as
[`ghcr.io/dev-sawan-ruparel/obs-unified`](https://github.com/users/dev-sawan-ruparel/packages/container/package/obs-unified).
It packages the Node collector, the dashboard, embedded Postgres, and filesystem
blob storage in one container. No clone or Node.js toolchain is needed.

The image fails closed: it refuses to start unless you supply your own ingest
key and dashboard password.

```bash
export INGEST_KEY="pick-a-long-random-ingest-key"
export DASHBOARD_PASSWORD="pick-a-dashboard-password"
export DASHBOARD_TOKEN="pick-a-read-token-for-mcp-and-cli"

docker run --rm \
  -p 5173:5173 \
  -p 8790:8790 \
  -e INGEST_KEY \
  -e DASHBOARD_PASSWORD \
  -e DASHBOARD_TOKEN \
  -e OBS_LOCAL_SEED=true \
  -v obs-unified-db:/var/lib/postgresql \
  -v obs-unified-blobs:/data \
  ghcr.io/dev-sawan-ruparel/obs-unified:latest
```

| Interface        | URL                     |
| ---------------- | ----------------------- |
| Dashboard        | `http://localhost:5173` |
| Collector ingest | `http://localhost:8790` |

Log in to the dashboard with `DASHBOARD_PASSWORD`, point SDKs or OTLP
exporters at `http://localhost:8790` with `INGEST_KEY`, and pass `DASHBOARD_TOKEN`
to `@obsunified/mcp-server` or `@obsunified/cli`. Scripted login (`POST /auth/login`) and logout semantics are in [Identity and external access](/docs/ops/identity-access).

To check the image without a browser, pull it or inspect its manifest (both work anonymously):

```bash
docker pull ghcr.io/dev-sawan-ruparel/obs-unified:latest
docker manifest inspect ghcr.io/dev-sawan-ruparel/obs-unified:latest
```

Tags: `latest`, a version tag that tracks the collector release
(for example `2.2.0`), and an immutable `sha-<commit>` tag. Pin a version or
sha tag for anything you intend to keep running. Omit `-e OBS_LOCAL_SEED=true`
(the default is `false`) when you want a clean database before sending your own
telemetry. Runtime variables, volumes, and rollback notes are in the
[Docker release guide](https://github.com/dev-sawan-ruparel/obs-unified/blob/main/docs/ops/docker-release.md).

## Local image with sample data [#local-image-with-sample-data]

Build and run the local image from a clone:

```bash
pnpm local:image
pnpm local:run
```

This starts Postgres, the collector, the dashboard, a filesystem blob store, and seeded sample data in one container. It uses fixed development credentials, so keep it on your own machine.

| Interface        | URL                     |
| ---------------- | ----------------------- |
| Dashboard        | `http://localhost:5173` |
| Collector ingest | `http://localhost:8790` |

Credentials for the locally built image (`pnpm local:run` only; the prebuilt GHCR image rejects these values and requires your own, see the prebuilt image section above):

| Credential         | Environment Variable               | Local image value     |
| ------------------ | ---------------------------------- | --------------------- |
| Ingest write key   | `INGEST_KEY` / `OBS_INGEST_KEY`    | `dev-ingest-key`      |
| Dashboard password | `DASHBOARD_PASSWORD`               | `e2e-test-pass`       |
| Read bearer token  | `DASHBOARD_TOKEN` on the collector | `e2e-dashboard-token` |

#### Tokens and env vars [#tokens-and-env-vars]

| Where              | Variable                           | Purpose                                                                                                                                                  |
| ------------------ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Collector          | `INGEST_KEY`                       | Write-only key that SDKs and exporters present to ingest telemetry.                                                                                      |
| Collector          | `DASHBOARD_PASSWORD`               | Browser login for the dashboard (`POST /auth/login`).                                                                                                    |
| Collector          | `DASHBOARD_TOKEN`                  | Read bearer token for `/internal/*`, the CLI, and MCP.                                                                                                   |
| Client (CLI, MCP)  | `OBS_DASHBOARD_TOKEN`              | Canonical name for the value of the collector's `DASHBOARD_TOKEN`. Accepted by the CLI (`doctor`, `keys`, `changes list`), and `@obsunified/mcp-server`. |
| Client (CLI)       | `OBS_ADMIN_TOKEN`, `OBS_API_TOKEN` | Aliases for `OBS_DASHBOARD_TOKEN` (verified against CLI 1.1.3 with `doctor`, `keys list`, and `changes list`).                                           |
| Client (SDKs, CLI) | `OBS_INGEST_KEY`                   | The collector's `INGEST_KEY`, used by the SDKs and `obs-unified changes record` (`OBS_API_KEY` is also accepted by the CLI).                             |

Run the local image smoke test when you want a full outside-the-container verification:

```bash
pnpm smoke:local-image
```

## Editable local install [#editable-local-install]

Use this when you are changing collector, dashboard, or SDK code.

```bash
git clone https://github.com/dev-sawan-ruparel/obs-unified.git
cd obs-unified
pnpm install
pnpm run setup
pnpm run dev
```

`pnpm run setup` creates `apps/collector/.dev.vars` from
`apps/collector/.dev.vars.example` if needed, then runs local migrations. The
sample-data seeder reads that same file, so custom local credentials do not need
to be exported in every shell.

The local dev stack exposes:

| Service     | Port   | Purpose                                   |
| ----------- | ------ | ----------------------------------------- |
| `collector` | `8790` | OTLP ingest and dashboard read API        |
| `web`       | `5173` | React dashboard                           |
| `demo`      | `8787` | Synthetic demo API for end-to-end testing |

## Seed sample data [#seed-sample-data]

The Docker image seeds sample data automatically. For the editable local install, run:

```bash
pnpm run seed
```

This populates traces, logs, AI calls, usage events, issues, users, and alert rules. Replays require a real browser interaction, so use the dashboard Playground tab to capture one.

## Astronomy Shop demo [#astronomy-shop-demo]

For realistic microservice traffic and service-map edges:

```bash
pnpm demo:setup
pnpm demo:preflight
pnpm demo:up
```

Open the demo shop at `http://localhost:8080` and the dashboard at `http://localhost:5173`.

Stop it with:

```bash
pnpm demo:down
```

## Standalone Node collector [#standalone-node-collector]

If you only want the collector service with Postgres and RustFS/S3:

```bash
cd apps/collector-node
docker compose up -d
docker compose logs -f collector
```

## Packages and registries [#packages-and-registries]

Everything a client needs is published; cloning the repo is only required for
the editable install and the seeded local image.

| Artifact                    | Where                                                                                                                                                                                           | Install                                                          |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| All-in-one container image  | [GHCR: `dev-sawan-ruparel/obs-unified`](https://github.com/users/dev-sawan-ruparel/packages/container/package/obs-unified)                                                                      | `docker pull ghcr.io/dev-sawan-ruparel/obs-unified:latest`       |
| Collector (Workers runtime) | [npm: `@obsunified/collector`](https://www.npmjs.com/package/@obsunified/collector)                                                                                                             | `pnpm add @obsunified/collector`                                 |
| Dashboard components        | [npm: `@obsunified/dashboard`](https://www.npmjs.com/package/@obsunified/dashboard)                                                                                                             | `pnpm add @obsunified/dashboard`                                 |
| Browser SDK                 | [npm: `@obsunified/analytics-sdk`](https://www.npmjs.com/package/@obsunified/analytics-sdk)                                                                                                     | `pnpm add @obsunified/analytics-sdk`                             |
| TypeScript server SDK       | [npm: `@obsunified/telemetry-sdk`](https://www.npmjs.com/package/@obsunified/telemetry-sdk)                                                                                                     | `pnpm add @obsunified/telemetry-sdk`                             |
| Node OTel wrapper           | [npm: `@obsunified/sdk`](https://www.npmjs.com/package/@obsunified/sdk)                                                                                                                         | `pnpm add @obsunified/sdk`                                       |
| Agent framework adapters    | [npm: `@obsunified/agents-langgraph`](https://www.npmjs.com/package/@obsunified/agents-langgraph), [`@obsunified/agents-vercel-ai`](https://www.npmjs.com/package/@obsunified/agents-vercel-ai) | `pnpm add @obsunified/agents-langgraph`                          |
| MCP server                  | [npm: `@obsunified/mcp-server`](https://www.npmjs.com/package/@obsunified/mcp-server)                                                                                                           | `pnpm add -g @obsunified/mcp-server`                             |
| CLI                         | [npm: `@obsunified/cli`](https://www.npmjs.com/package/@obsunified/cli)                                                                                                                         | `pnpm dlx @obsunified/cli doctor`                                |
| Shared types and schemas    | [npm: `@obsunified/types`](https://www.npmjs.com/package/@obsunified/types)                                                                                                                     | `pnpm add @obsunified/types`                                     |
| Go SDK                      | [pkg.go.dev: `sdks/go`](https://pkg.go.dev/github.com/dev-sawan-ruparel/obs-unified/sdks/go)                                                                                                    | `go get github.com/dev-sawan-ruparel/obs-unified/sdks/go@latest` |
| Rust SDK                    | [crates.io: `obs-unified`](https://crates.io/crates/obs-unified)                                                                                                                                | `cargo add obs-unified`                                          |
| Agent skills                | [GitHub Releases](https://github.com/dev-sawan-ruparel/obs-unified/releases) (`skills-v*` tags)                                                                                                 | Download the `.skill` bundles                                    |

All npm packages live under the [`@obsunified` organization](https://www.npmjs.com/org/obsunified).

## Production deployment [#production-deployment]

For production deployment details, see [Production operations](/docs/ops/production). At minimum, set a real `INGEST_KEY`, set `DASHBOARD_PASSWORD`, point `VITE_OBS_COLLECTOR_URL` at your collector, configure CORS for browser origins, and run migrations before accepting traffic.

<Callout type="warn">
  Do not use `ALLOW_UNAUTHENTICATED=true` or the default local credentials in production.
</Callout>
