# Angular (/docs/javascript/angular)

Tracepanel records the pages of an Angular app in the browser. Each view and
each click is a trace, with the API calls it made, its errors and its console
output. The panel sits on the app's pages, and lists each click with its
calls under it.

## Add it to your app [#add-it-to-your-app]

Install `@tracepanel/js` in the Angular app:

```bash
npm install @tracepanel/js
```

Add `provideTracepanel()` to the app's providers:

```ts
// src/app/app.config.ts
import type { ApplicationConfig } from "@angular/core";
import { provideHttpClient } from "@angular/common/http";
import { provideRouter } from "@angular/router";
import { provideTracepanel } from "@tracepanel/js/angular";
import { routes } from "./app.routes";

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideHttpClient(),
    provideTracepanel({ service: "shop-web" }),
  ],
};
```

`service` names the app in the console. It is `browser` by default.
Tracepanel supports Angular 20 and newer.

The recording starts as Angular makes the app's injector, before any of your
services. So it sees every call HttpClient makes, on `fetch()` or on
`XMLHttpRequest`. It also puts the panel's script into the page.

## Send the console on [#send-the-console-on]

The panel and the recording talk to the console at `/__tracepanel__/` on the
page's origin. `ng serve` sends it on with its proxy, as it does your API.

A backend in Python or Java, or a Next.js app, serves its own console. Send
both paths to it:

```json
{
  "/api": { "target": "http://127.0.0.1:8000" },
  "/__tracepanel__": { "target": "http://127.0.0.1:8000" }
}
```

Save it as `proxy.conf.json` and start the dev server with it. The
`proxyConfig` option of `ng serve` in `angular.json` does the same:

```bash
ng serve --proxy-config proxy.conf.json
```

An Express, Fastify or other Node.js backend serves no console. Its agent
does. Start the agent with `tracepanel dev` in the backend's directory,
before the backend:

```bash
npx @tracepanel/js dev
```

It serves the console on `http://127.0.0.1:8765/`. The backend finds the
agent and sends its traces to it. Send `/__tracepanel__/` there, with the
prefix taken off:

```json
{
  "/api": { "target": "http://127.0.0.1:3000" },
  "/__tracepanel__": {
    "target": "http://127.0.0.1:8765",
    "pathRewrite": { "^/__tracepanel__": "" }
  }
}
```

## Read what users do [#read-what-users-do]

Each view of a page is a trace: its load, or a route change. So is each
action on it:

- a click or a submit that called the API or threw, named after its control,
  such as `click "Borrow"`
- calls the page made in the background, which no one started

A view is named by the route the router matched, such as `/books/:id`, so
every book's page is one page in the console. Its path, such as `/books/2`,
stays with it. An action is named on its route, such as
`/books/:id › click "Borrow"`.

A view or an action keeps its calls, its errors and its console output, with
the line that logged each record. It lasts until its last call answered. The
console lists them in **Pages**. See
[Pages in the browser](/docs/javascript/browser#read-what-users-do).

An error in an event handler or a component never reaches `window`. Angular
catches it and hands it to its `ErrorHandler`. Tracepanel takes each error
from the app's `ErrorHandler` first, whichever it is, and the click that
threw it fails. Your handler gets the error as before.

An error your code catches itself stays out. Pass it to `report()` to fail
the click it happened in:

```ts
import { report } from "@tracepanel/js/angular";

this.api.borrow(id).subscribe({ error: (error) => report(error) });
```

## Call an API on another origin [#call-an-api-on-another-origin]

A call to the page's own origin, such as `/api/` through the proxy, carries a
W3C `traceparent`. The console links it to the API's trace. To link calls to
another origin too, name it in `propagateTo`:

```ts
provideTracepanel({ service: "shop-web", propagateTo: ["http://127.0.0.1:8000"] });
```

That origin's CORS must allow the `traceparent` and `X-Tracepanel-Profile`
headers. See
[Pages in the browser](/docs/javascript/browser#call-an-api-on-another-origin).

## Development only [#development-only]

`provideTracepanel()` works in a development build, such as `ng serve`'s. In
a production build it does nothing, and the build leaves it out of the
bundle.

The console answers only this machine when a backend serves it. Through the
dev server's proxy, the backend sees the proxy's address. Keep `ng serve` on
`localhost`, its default, so no other machine reaches the console.
