# Frontend observability

Nais provides frontend observability through the [Grafana Faro Web SDK](https://www.npmjs.com/package/@grafana/faro-web-sdk). Faro runs in the browser and instruments your app, shipping telemetry through the platform collector (**Alloy**) into the shared observability stores: errors and events land in **Loki**, browser spans in **Tempo**, and Core Web Vitals in **Mimir**. You then view and triage it all in [Nais APM](https://grafana.nav.cloud.nais.io/a/nais-apm-app).

With 95+ applications already using Faro, it's the standard way to monitor frontend applications on Nais.

> **Recommended: instrument with `@nais/apm`**
> The recommended way to add Faro to a browser app is the
> [`@nais/apm`](/observability/apm/reference/apm-client-api.md) SDK — a thin Faro wrapper
> with **zero-config `init()`**, **mandatory PII scrubbing**, a required
> `namespace`, and a fixed console instrumentation that keeps real stack
> traces. It's the *instrument* half of Nais APM: add `@nais/apm`, then
> **view and triage** the results on the APM [Frontend](/observability/apm/tutorials/get-started.md#4-look-at-backend-database-and-frontend)
> and [Issues](/observability/apm/tutorials/get-started.md#3-check-the-issues-tab) tabs.

> Start with [Track frontend errors with `@nais/apm`](/observability/apm/tutorials/track-frontend-errors.md).
> Reach for raw Faro (the guides below) only when you need the lower-level SDK
> directly — everything the platform recommends, including
> [trace propagation](/observability/frontend/how-to/trace-propagation.md)
> (`init({ tracing: true })`), is available through `@nais/apm`.

## What you get

- **[Core Web Vitals](https://web.dev/vitals/)** — TTFB, FCP, CLS, LCP, INP (collected automatically)
- **Logging** — `console.info`, `console.warn`, and `console.error` messages
- **Exceptions** — stack traces with [automatic sourcemap deobfuscation](/observability/frontend/how-to/sourcemaps.md)
- **Custom events and metrics** — anything you want to track
- **[Tracing](/observability/frontend/how-to/trace-propagation.md)** — OpenTelemetry-based browser traces, optionally connected to backend spans

## Get started

1. **Recommended — errors as issues in APM:** [🎯 Track frontend errors with `@nais/apm`](/observability/apm/tutorials/track-frontend-errors.md)
2. **Next.js (App Router or Pages Router):** [:simple-nextdotjs: Next.js quickstart with `@nais/apm`](/observability/frontend/how-to/quickstart-nextjs.md)
3. **React SPA + Vite:** [:simple-react: React + Vite quickstart with `@nais/apm`](/observability/frontend/how-to/quickstart-react-vite.md)
4. **Coming from Sentry?** [Migrate from Sentry to `@nais/apm`](/observability/frontend/how-to/migrate-from-sentry.md)
5. **Need the lower-level SDK directly?** [Set up Faro](/observability/frontend/how-to/setup-faro.md) · [Next.js with raw Faro](/observability/frontend/how-to/setup-nextjs.md)
6. **Want end-to-end traces?** [Connect frontend to backend](/observability/frontend/how-to/trace-propagation.md)
7. **Stack traces look minified?** [Sourcemaps](/observability/frontend/how-to/sourcemaps.md) · [Troubleshooting](/observability/frontend/reference/troubleshooting.md)

## Recommended configuration

After the basic setup, check that you have these configured:

| Setting | Why it matters | Guide |
| --- | --- | --- |
| `beforeSend` PII filtering | Faro captures URLs and console output that may contain fødselsnummer or tokens | [Privacy and sensitive data](/observability/frontend/how-to/setup-faro.md#privacy-and-sensitive-data) |
| `propagateTraceHeaderCorsUrls` | Without this, browser traces never connect to your backend spans | [Trace propagation](/observability/frontend/how-to/trace-propagation.md) |
| `paused` on localhost | Prevents local development noise from polluting production dashboards | [Local development](/observability/frontend/how-to/setup-faro.md#local-development) |
| `app.version` | Lets you filter errors and metrics by deploy | [Setting app.version](/observability/frontend/how-to/setup-faro.md#setting-appversion) |
| Error boundary | Catches React rendering errors that are otherwise silently lost | [React error boundaries](/observability/frontend/how-to/setup-faro.md#react-error-boundaries) |

## Collector endpoints

The collector URL tells Faro where to send telemetry data. If you use the [auto-configuration](/observability/frontend/how-to/setup-faro.md#auto-configuration) in `nais.yaml`, this is set for you.

| Collector endpoint | Environment |
| --- | --- |
| `https://telemetry.nav.no/collect` | `prod` |
| `https://telemetry.ekstern.dev.nav.no/collect` | `dev` |

On-premises clusters are not supported.

## Inspecting frontend data in Grafana

Find your app in the [Nais APM](https://grafana.nav.cloud.nais.io/a/nais-apm-app/services) service inventory and open it. Browser telemetry surfaces on two tabs:

- **Frontend** — Core Web Vitals, pageloads, sessions, per-page performance, browser breakdown, and web-vitals attribution (what's driving LCP, INP, and CLS).
- **Issues** — browser exceptions grouped into issues, side by side with backend errors. Filter the source to **Browser** to isolate frontend errors, then open an issue for its stack trace and impact.

![Nais APM Issues tab filtered to browser-sourced exceptions](/assets/nais-apm-service-navno-issues-frontend.png)

For a full tour of the tabs, see [Get started with Nais APM](/observability/apm/tutorials/get-started.md); for capturing errors from your own code, see [Track frontend errors with `@nais/apm`](/observability/apm/tutorials/track-frontend-errors.md).

For deeper analysis, use the [Explore view](https://grafana.nav.cloud.nais.io/explore) with one of the Loki data sources. Here are some useful queries:

```logql
# All frontend logs for your app
{app_name="my-app"} | logfmt

# Exceptions only
{app_name="my-app", kind="exception"} | logfmt

# Slow Largest Contentful Paint (> 2.5s)
{app_name="my-app", kind="measurement"} | logfmt | web_vitals_lcp > 2500
```

Traces are available from data sources ending with `-tempo`. Use [TraceQL](/observability/tracing/reference/traceql.md) to query them.

## Local development

For local development, check out the [tracing demo repository](https://github.com/nais/tracing-demo) and run `docker-compose up`. This gives you a local Grafana, Loki, and Tempo stack to test against. See the README in that repository for details.

## Guides

The recommended path is the `@nais/apm` SDK. Pick the quickstart for your
framework:

| Framework quickstart | Description |
| --- | --- |
| [Next.js with `@nais/apm`](/observability/frontend/how-to/quickstart-nextjs.md) | App Router and Pages Router: client init, error boundary, route tracking, tracing |
| [React + Vite with `@nais/apm`](/observability/frontend/how-to/quickstart-react-vite.md) | React SPA: entry-point init, error boundary, React Router tracking |
| [Migrate from Sentry](/observability/frontend/how-to/migrate-from-sentry.md) | Move an existing `@sentry/*` app onto `@nais/apm` |

The raw-Faro guides below are the lower-level path — reach for them only when you
need to work with the Faro SDK directly. Everything the platform recommends,
including [trace propagation](/observability/frontend/how-to/trace-propagation.md), is available through
`@nais/apm` (`init({ tracing: true })`).

| Guide | Description |
| --- | --- |
| [Set up Faro](/observability/frontend/how-to/setup-faro.md) | Install, configure, and deploy Faro in any frontend app |
| [Next.js App Router](/observability/frontend/how-to/setup-nextjs.md) | Faro integration for Next.js with App Router |
| [Custom metrics](/observability/frontend/how-to/custom-metrics.md) | Send custom measurements and query them in Grafana |
| [Trace propagation](/observability/frontend/how-to/trace-propagation.md) | Connect frontend traces to backend spans |
| [Sourcemaps](/observability/frontend/how-to/sourcemaps.md) | How stack trace deobfuscation works |
| [Auto-configuration](/observability/frontend/reference/auto-configuration.md) | Generated config values and environment variables |
| [Troubleshooting](/observability/frontend/reference/troubleshooting.md) | CSP, CORS, and common issues |

## Further reading

- [Nais APM](/observability/apm.md) — view and triage the telemetry you instrument here
- [`@nais/apm` API reference](/observability/apm/reference/apm-client-api.md) — the recommended SDK's full API
- [Grafana Faro Web SDK docs](https://grafana.com/docs/grafana-cloud/monitor-applications/frontend-observability/)
- [Grafana Faro Web SDK on npm](https://www.npmjs.com/package/@grafana/faro-web-sdk)
- [Grafana Faro Web SDK changelog](https://github.com/grafana/faro-web-sdk/blob/main/CHANGELOG.md)
- [Grafana Faro Next.js example](https://github.com/grafana/faro-nextjs-example)
