> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# HackerNews Analyzer demo

> Instrument a Node.js app with an agent and send logs, traces, metrics, and session replay to fully managed ClickHouse Observability

> [tab] Fully managed
>
> [Beta offering](https://clickhouse.com/docs/reference/settings/beta-and-experimental-features.md#beta-features)
>
> > [!NOTE]
> >
> > **TL;DR**
> >
> > Clone the [HackerNews Analyzer](https://github.com/ClickHouse/hn-news-analyzer), fill `.env` with your managed OTLP HTTP endpoint and API key, then paste the agent prompt. The backend needs no OpenTelemetry imports; the agent wires `@hyperdx/node-opentelemetry` at process start.
> >
> > Time required: about 10 minutes
>
> The HackerNews Analyzer is a Node.js app that queries the HackerNews dataset hosted in the public ClickHouse demo. Dashboard interactions produce requests to the backend. Requests that miss the app's cache also query ClickHouse, adding an outbound HTTPS span to the trace.
>
> This demo combines backend auto-instrumentation, ClickHouse query spans, and browser session replay in one app.
>
> ## Prerequisites
>
> * Node.js and npm versions compatible with the [HackerNews Analyzer and its dependencies](https://github.com/ClickHouse/hn-news-analyzer#readme).
> * An existing fully managed ClickHouse Observability service. See the [fully managed Getting Started guide](https://clickhouse.com/docs/clickstack/observability/getting-started.md).
> * Network access to the managed telemetry endpoint from both the app server and your browser.
>
> ## Clone the repository
>
> Clone [HackerNews Analyzer](https://github.com/ClickHouse/hn-news-analyzer), install dependencies, and copy the env template:
>
> ```bash theme={null}
> git clone https://github.com/ClickHouse/hn-news-analyzer.git
> cd hn-news-analyzer
> npm install
> cp .env.example .env
> ```
>
> You'll fill `.env` in the next steps, then instrument from this directory.
>
> ## Instrument the application
>
> **1. Run the application**
>
> From the cloned `hn-news-analyzer` directory, start the app. The ClickHouse data source defaults to the public read-only demo cluster, so it runs without any further configuration:
>
> ```bash theme={null}
> ./run.sh
> ```
>
> Open [http://localhost:5001](http://localhost:5001). You will see a year selector, summary statistics, an activity chart, top users and domains tables, and a search box. Click around: switch years, drill into stories.
>
> ![The HackerNews Analyzer application running locally](https://mintcdn.com/private-7c7dfe99/LCIbqddLfKHZZnfk/images/clickstack/getting-started/hackernews_main.webp?fit=max\&auto=format\&n=LCIbqddLfKHZZnfk\&q=85\&s=5587ba7b6d7c6595e7782e5060586629)
>
> At this point the application is running but uninstrumented. The app will send telemetry after you complete the instrumentation steps below.
>
> **2. Configure environment**
>
> Open your ClickHouse Observability service and go to **Team Settings → Managed Telemetry**. Copy the **OTLP HTTP endpoint** and **API key**.
>
> ![Managed Telemetry in Team Settings showing the masked OTLP HTTP endpoint and API key](https://mintcdn.com/private-7c7dfe99/Zk1feNn6fCQBpold/images/clickstack/getting-started/observability-managed-telemetry.png?fit=max\&auto=format\&n=Zk1feNn6fCQBpold\&q=85\&s=e63a2ac2e6ab996d3fc360ebe0f487a5)
>
> In the app's `.env` file, set the following values, replacing the endpoint and API key placeholders:
>
> ```bash theme={null}
> OTEL_SERVICE_NAME=hn-analyzer-api
> OTEL_EXPORTER_OTLP_ENDPOINT=https://YOUR_OTEL_ENDPOINT:4318
> OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
> OTEL_EXPORTER_OTLP_HEADERS=authorization=<your-api-key>
> OTEL_TRACES_EXPORTER=otlp
> OTEL_METRICS_EXPORTER=otlp
> OTEL_LOGS_EXPORTER=otlp
> ```
>
> Keep the `https://` prefix in `OTEL_EXPORTER_OTLP_ENDPOINT` and do not append `/v1/logs`, `/v1/traces`, or `/v1/metrics`. The SDKs append the signal paths. Set `OTEL_EXPORTER_OTLP_HEADERS` to `authorization=<your-api-key>` without a `Bearer` prefix; the app also passes this key directly to the browser SDK.
>
> The browser SDK uses the same endpoint and API key. `vite.config.ts` embeds them in the browser bundle, where visitors can inspect them. Use a service intended for testing this demo and keep `.env` out of version control.
>
> **3. Instrument the application**
>
> Pick one path. All three end at the same instrumented app.
>
> > [tab] Agent instrumentation
> >
> > With the repo cloned and `.env` filled in, paste this prompt into a coding agent **in that directory** to instrument the application.
> >
> > Agent-Assisted Setup
> >
> > `Use curl to download, read and follow: https://raw.githubusercontent.com/ClickHouse/hn-news-analyzer/main/agent.md`
> >
> > Copy Prompt
> >
> > Copied
> >
> > After you clone hn-news-analyzer and fill .env, run this prompt from that directory. Works with Claude Code, Cursor, Codex, and other coding agents.
>
> > [tab] Manual instrumentation
> >
> > Instrumentation has three parts: install the SDKs, switch the launch command, and enable the browser SDK. None of it changes the application's business logic.
> >
> > ### Install the Node SDK
> >
> > ```bash theme={null}
> > npm install @hyperdx/node-opentelemetry
> > ```
> >
> > ### Enable the wrapper in run.sh
> >
> > The bottom of `run.sh` has two `exec` lines. Comment the plain `node` line and uncomment the instrumented one:
> >
> > ```diff theme={null}
> >  # BEFORE: plain node, no instrumentation:
> > -exec node scripts/entrypoint.js
> > +# exec node scripts/entrypoint.js
> >
> >  # AFTER: same source, wrapped by opentelemetry-instrument:
> > -# exec npx opentelemetry-instrument scripts/entrypoint.js
> > +exec npx opentelemetry-instrument scripts/entrypoint.js
> > ```
> >
> > Keep launching through `scripts/entrypoint.js`. That shim calls `require('console')` so console capture wraps `console.log`. Pointing `opentelemetry-instrument` at `dist/server/index.js` directly ships traces but silently drops logs.
> >
> > ### Enable the browser SDK
> >
> > ```bash theme={null}
> > npm install @hyperdx/browser
> > ```
> >
> > In `src/web/telemetry.ts`, uncomment the import, the `HyperDX.init` block, and `HyperDX.addAction` in `recordAction`:
> >
> > ```diff theme={null}
> > -// import HyperDX from '@hyperdx/browser';
> > +import HyperDX from '@hyperdx/browser';
> >
> >  export function initTelemetry(): void {
> > -  // HyperDX.init({
> > -  //   url: __OTLP_ENDPOINT__,
> > -  //   apiKey: __OTLP_AUTH_TOKEN__,
> > -  //   service: 'hn-analyzer-web',
> > -  //   tracePropagationTargets: [/localhost:5001/i, /\/api\//i],
> > -  //   consoleCapture: true,
> > -  //   advancedNetworkCapture: true,
> > -  // });
> > +  HyperDX.init({
> > +    url: __OTLP_ENDPOINT__,
> > +    apiKey: __OTLP_AUTH_TOKEN__,
> > +    service: 'hn-analyzer-web',
> > +    tracePropagationTargets: [/localhost:5001/i, /\/api\//i],
> > +    consoleCapture: true,
> > +    advancedNetworkCapture: true,
> > +  });
> >  }
> > ```
> >
> > `__OTLP_ENDPOINT__` and `__OTLP_AUTH_TOKEN__` are compile-time constants injected by `vite.config.ts` from the same `OTEL_EXPORTER_OTLP_*` values the backend uses.
>
> > [tab] Use a pre-instrumented branch
> >
> > To skip instrumentation and start with an already instrumented application, check out the [`instrumented` branch](https://github.com/ClickHouse/hn-news-analyzer/tree/instrumented).
> >
> > ```bash theme={null}
> > git checkout instrumented
> > npm install
> > ```
> >
> > Don't run `./reset.sh` on this branch unless you want to strip the SDKs.
>
> **4. Generate traffic and view telemetry**
>
> Restart the application so the new launch command and freshly built browser bundle take effect:
>
> ```bash theme={null}
> # Ctrl-C the previous run, then:
> ./run.sh
> ```
>
> Confirm the startup banner prints three `Health check passed` lines for `/v1/traces`, `/v1/metrics`, and `/v1/logs`. Reload the browser tab so Vite serves the updated bundle, then switch years and click into stories to generate traffic.
>
> Open your ClickHouse Observability service:
>
> 1. Go to **Search**, select the **Logs** source, and set the time range to **Last 15 minutes**. Filter `ServiceName` to `hn-analyzer-api` to find the backend logs.
>
> ![ClickHouse Observability Search showing backend logs filtered to hn-analyzer-api](https://mintcdn.com/private-7c7dfe99/Zk1feNn6fCQBpold/images/clickstack/getting-started/observability-hackernews-logs.png?fit=max\&auto=format\&n=Zk1feNn6fCQBpold\&q=85\&s=da20fb918b5db9018f185a9e93ff27d3)
>
> 2. Select the **Traces** source and open a request from `hn-analyzer-api`. You will see the Express handler span, a child HTTP span pointing at `sql-clickhouse.clickhouse.com` with real network duration, and correlated `console.log` records on the same trace.
>
> ![ClickHouse Observability trace showing the browser request, backend spans, correlated logs, and an HTTP request to ClickHouse](https://mintcdn.com/private-7c7dfe99/Zk1feNn6fCQBpold/images/clickstack/getting-started/observability-hackernews-traces.png?fit=max\&auto=format\&n=Zk1feNn6fCQBpold\&q=85\&s=24e3e1ebdd748ce9055c46a30b2907a1)
>
> 3. Open **Client Sessions**, select a session from `hn-analyzer-web`, and open **Session Replay** to review the browser interactions.
>
> ![ClickHouse Observability session replay showing the HackerNews Analyzer with dashboard refresh and search events](https://mintcdn.com/private-7c7dfe99/Zk1feNn6fCQBpold/images/clickstack/getting-started/observability-hackernews-sessions.png?fit=max\&auto=format\&n=Zk1feNn6fCQBpold\&q=85\&s=be340ae1c314e0dadc200bbaeaa6061c)
>
> 4. Open **Chart Explorer**, select **Time Series** and the **Metrics** source, and choose a metric emitted by the app. Filter by `ResourceAttributes.service.name:"hn-analyzer-api"`, select a time range covering your test, and select **Run** to confirm metric data is present.
>
> ## Learn more
>
> * [HackerNews Analyzer](https://github.com/ClickHouse/hn-news-analyzer): the demo repository this guide instruments.
> * [Session Replay](https://clickhouse.com/docs/clickstack/observability/features/session-replay.md): feature overview, SDK options, and privacy controls.
> * [Fully managed Getting Started](https://clickhouse.com/docs/clickstack/observability/getting-started.md): connect your first data source.
> * [All Sample Datasets](https://clickhouse.com/docs/clickstack/observability/example-datasets): other example datasets and guides.

> [tab] Self-managed
>
> > [!NOTE]
> >
> > This demo requires a running OpenTelemetry collector configured to send data to your self-managed ClickHouse Observability service. If you have not deployed one, follow the [collector setup guide](https://clickhouse.com/docs/clickstack/self-configured/ingesting-data/collector.md#configuring-the-collector-self-configured) before continuing. Use its OTLP HTTP endpoint and, if configured, its [ingestion authentication token](https://clickhouse.com/docs/clickstack/self-configured/ingesting-data/collector.md#securing-the-collector-self-configured) in the steps below.
>
> > [!NOTE]
> >
> > **TL;DR**
> >
> > Clone the [HackerNews Analyzer](https://github.com/ClickHouse/hn-news-analyzer), fill `.env` with your OTLP endpoint and token, then paste the agent prompt. The backend needs no OpenTelemetry imports; the agent wires `@hyperdx/node-opentelemetry` at process start.
> >
> > Time required: about 10 minutes
>
> The HackerNews Analyzer is a Node.js app that queries the HackerNews dataset hosted in the public ClickHouse demo. Every chart, table, and search box is a real ClickHouse query, so every interaction produces a trace whose main span is the HTTPS call from the backend out to ClickHouse.
>
> This is a different job from the [session replay demo](https://clickhouse.com/docs/clickstack/observability/example-datasets/session-replay.md), which instruments a browser-only app and sends telemetry to ClickHouse Observability. Here you get backend auto-instrumentation, ClickHouse query spans, and session replay from the same app.
>
> ## Prerequisites
>
> * Node 18+ and npm
> * An existing self-managed ClickHouse Observability service and a running ingestion collector.
> * The collector’s OTLP HTTP endpoint, reachable from both the app server and your browser. Use `http://localhost:4318` only when the collector runs on the same machine.
> * The collector’s `OTLP_AUTH_TOKEN`, if configured. Set headers to `authorization=<token>` without a `Bearer` prefix. If the collector does not require authentication, leave `authorization=` empty. These are collector ingestion credentials, not your ClickHouse database credentials.
>
> ## Clone the repository
>
> Clone [HackerNews Analyzer](https://github.com/ClickHouse/hn-news-analyzer), install dependencies, and copy the env template:
>
> ```bash theme={null}
> git clone https://github.com/ClickHouse/hn-news-analyzer.git
> cd hn-news-analyzer
> npm install
> cp .env.example .env
> ```
>
> You'll fill `.env` in the next steps, then instrument from this directory.
>
> ## Instrument the application
>
> **1. Run the application**
>
> From the cloned `hn-news-analyzer` directory, start the app. The ClickHouse data source defaults to the public read-only demo cluster, so it runs without any further configuration:
>
> ```bash theme={null}
> ./run.sh
> ```
>
> Open [http://localhost:5001](http://localhost:5001). You will see a year selector, summary statistics, an activity chart, top users and domains tables, and a search box. Click around: switch years, drill into stories.
>
> ![The HackerNews Analyzer application running locally](https://mintcdn.com/private-7c7dfe99/LCIbqddLfKHZZnfk/images/clickstack/getting-started/hackernews_main.webp?fit=max\&auto=format\&n=LCIbqddLfKHZZnfk\&q=85\&s=5587ba7b6d7c6595e7782e5060586629)
>
> At this point the application is running but uninstrumented. ClickStack shows no data: it is waiting for telemetry.
>
> **2. Configure environment**
>
> The SDKs read standard OpenTelemetry exporter variables. They are not hardcoded in source. Open `.env` and set:
>
> ```bash theme={null}
> OTEL_SERVICE_NAME=hn-analyzer-api
> OTEL_EXPORTER_OTLP_ENDPOINT=<your-otlp-http-endpoint>
> OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
> OTEL_EXPORTER_OTLP_HEADERS=authorization=<your-ingestion-token>
> OTEL_TRACES_EXPORTER=otlp
> OTEL_METRICS_EXPORTER=otlp
> OTEL_LOGS_EXPORTER=otlp
> ```
>
> `OTEL_EXPORTER_OTLP_ENDPOINT` is the OTLP/HTTP endpoint (port `4318`). `OTEL_EXPORTER_OTLP_HEADERS` is the authorization header, in the form `authorization=<token>` with no `Bearer` prefix.
>
> If the collector does not enforce auth, leave the token empty (`OTEL_EXPORTER_OTLP_HEADERS=authorization=`). The variable must still be present; the SDK skips initialization if it is unset or fully empty.
>
> The browser SDK reuses these same values. `vite.config.ts` bakes the endpoint and token into the public bundle at build time, so use a throwaway ingestion token, not a production one.
>
> **3. Instrument the application**
>
> Pick one path. All three end at the same instrumented app.
>
> > [tab] Agent instrumentation
> >
> > With the repo cloned and `.env` filled in, paste this prompt into a coding agent **in that directory** to instrument the application.
> >
> > Agent-Assisted Setup
> >
> > `Use curl to download, read and follow: github.com/ClickHouse/hn-news-analyzer/blob/main/agent.md`
> >
> > Copy Prompt
> >
> > Copied
> >
> > After you clone hn-news-analyzer and fill .env, run this prompt from that directory. Works with Claude Code, Cursor, Codex, and other coding agents.
>
> > [tab] Manual instrumentation
> >
> > Instrumentation has three parts: install the SDKs, switch the launch command, and enable the browser SDK. None of it changes the application's business logic.
> >
> > ### Install the Node SDK
> >
> > ```bash theme={null}
> > npm install @hyperdx/node-opentelemetry
> > ```
> >
> > ### Enable the wrapper in run.sh
> >
> > The bottom of `run.sh` has two `exec` lines. Comment the plain `node` line and uncomment the instrumented one:
> >
> > ```diff theme={null}
> >  # BEFORE: plain node, no instrumentation:
> > -exec node scripts/entrypoint.js
> > +# exec node scripts/entrypoint.js
> >
> >  # AFTER: same source, wrapped by opentelemetry-instrument:
> > -# exec npx opentelemetry-instrument scripts/entrypoint.js
> > +exec npx opentelemetry-instrument scripts/entrypoint.js
> > ```
> >
> > Keep launching through `scripts/entrypoint.js`. That shim calls `require('console')` so console capture wraps `console.log`. Pointing `opentelemetry-instrument` at `dist/server/index.js` directly ships traces but silently drops logs.
> >
> > ### Enable the browser SDK
> >
> > ```bash theme={null}
> > npm install @hyperdx/browser
> > ```
> >
> > In `src/web/telemetry.ts`, uncomment the import, the `HyperDX.init({...})` block, and `HyperDX.addAction` in `recordAction()`:
> >
> > ```diff theme={null}
> > -// import HyperDX from '@hyperdx/browser';
> > +import HyperDX from '@hyperdx/browser';
> >
> >  export function initTelemetry(): void {
> > -  // HyperDX.init({
> > -  //   url: __OTLP_ENDPOINT__,
> > -  //   apiKey: __OTLP_AUTH_TOKEN__,
> > -  //   service: 'hn-analyzer-web',
> > -  //   tracePropagationTargets: [/localhost:5001/i, /\/api\//i],
> > -  //   consoleCapture: true,
> > -  //   advancedNetworkCapture: true,
> > -  // });
> > +  HyperDX.init({
> > +    url: __OTLP_ENDPOINT__,
> > +    apiKey: __OTLP_AUTH_TOKEN__,
> > +    service: 'hn-analyzer-web',
> > +    tracePropagationTargets: [/localhost:5001/i, /\/api\//i],
> > +    consoleCapture: true,
> > +    advancedNetworkCapture: true,
> > +  });
> >  }
> > ```
> >
> > `__OTLP_ENDPOINT__` and `__OTLP_AUTH_TOKEN__` are compile-time constants injected by `vite.config.ts` from the same `OTEL_EXPORTER_OTLP_*` values the backend uses.
> >
> > > [!WARNING]
> > >
> > > The ingestion token is baked into the public browser bundle and is readable by anyone inspecting the network tab. Use a throwaway token.
>
> > [tab] Use a pre-instrumented branch
> >
> > To skip instrumentation and start with an already instrumented application, check out the [`instrumented` branch](https://github.com/ClickHouse/hn-news-analyzer/tree/instrumented).
> >
> > ```bash theme={null}
> > git checkout instrumented
> > npm install
> > ```
> >
> > Don't run `./reset.sh` on this branch unless you want to strip the SDKs.
>
> **4. Generate traffic and view telemetry**
>
> Restart the application so the new launch command and freshly built browser bundle take effect:
>
> ```bash theme={null}
> # Ctrl-C the previous run, then:
> ./run.sh
> ```
>
> Confirm the startup banner prints three "Health check passed" lines for `/v1/traces`, `/v1/metrics`, and `/v1/logs`. Reload the browser tab so Vite serves the updated bundle, then switch years and click into stories to generate traffic.
>
> Open the ClickStack UI:
>
> 1. Go to **Search** and filter to the last 5 minutes. Logs for `hn-analyzer-api` stream in.
>
> ![ClickStack search showing hn-analyzer-api logs from the last five minutes](https://mintcdn.com/private-7c7dfe99/LCIbqddLfKHZZnfk/images/clickstack/getting-started/instrument_app_clickstack_logs.webp?fit=max\&auto=format\&n=LCIbqddLfKHZZnfk\&q=85\&s=5fb0cdc33e97610f1f7f1c264f349aa0)
>
> 2. Click into a request and walk up the trace. You will see the Express handler span, a child HTTP span pointing at `sql-clickhouse.clickhouse.com` with real network duration, and correlated `console.log` records on the same trace.
>
> ![ClickStack trace with an Express handler span and a child HTTP span to ClickHouse](https://mintcdn.com/private-7c7dfe99/LCIbqddLfKHZZnfk/images/clickstack/getting-started/instrument_app_clickstack_traces.webp?fit=max\&auto=format\&n=LCIbqddLfKHZZnfk\&q=85\&s=77cefc89163e1e45a8475dd815ff95bd)
>
> 3. Open **Session Replay** to play back a scrubbable video of a browser session, synced to the trace timeline.
>
> ![ClickStack session replay synced to the trace timeline](https://mintcdn.com/private-7c7dfe99/LCIbqddLfKHZZnfk/images/clickstack/getting-started/instrument_app_clickstack_sessions.webp?fit=max\&auto=format\&n=LCIbqddLfKHZZnfk\&q=85\&s=c80327d0ed8a5ac088bfa5979febf452)
>
> Logs, metrics, traces, and session replays land in the same UI, share the same query language, and are correlated automatically.
>
> ## Learn more
>
> * [HackerNews Analyzer](https://github.com/ClickHouse/hn-news-analyzer): the demo repository this guide instruments.
> * [Session Replay](https://clickhouse.com/docs/clickstack/observability/features/session-replay.md): feature overview, SDK options, and privacy controls.
> * [Session Replay Demo](https://clickhouse.com/docs/clickstack/observability/example-datasets/session-replay.md): a browser-only demo that sends telemetry to ClickHouse Observability.
> * [Getting started with Self-managed](https://clickhouse.com/docs/clickstack/self-configured/getting-started/managed.md): set up your service and ingest your first data.
> * [All Sample Datasets](https://clickhouse.com/docs/clickstack/observability/example-datasets): other example datasets and guides.
