Grafana Faro: The ‘Watchful Eye’ for Real User Monitoring (RUM) in Web Applications

Monitoring tutorial - IT technology blog
Monitoring tutorial - IT technology blog

When Dashboards are ‘All Green’ but Customers Still Leave

It’s 2 AM, and your phone starts vibrating. The Prometheus dashboard shows CPU at 15%, plenty of RAM, and Nginx logs returning all 200 OK. Everything looks perfect. However, customers are complaining on social media that the ‘Checkout’ button isn’t working.

Traditional monitoring tools like Prometheus or Zabbix usually only see the server-side surface. They are completely “blind” to what happens in the user’s browser. It could be a broken JS file, an unstable client network, or a 5MB CSS file blocking the rendering process.

Grafana Faro is the final piece of the puzzle. It’s a Real User Monitoring (RUM) solution that helps you scrutinize every minor behavior on the client side. If you’re already using Loki for logs and Tempo for traces, Faro helps you achieve true Full-stack Observability.

Backend Setup: Configuring the Data Receiver

Browser data isn’t pushed directly into the database; it needs to pass through an intermediary collector. While we used to use Grafana Agent, **Grafana Alloy** is now the more optimal and flexible choice.

Step 1: Configuring Grafana Alloy

Create a config.alloy file on your server. You need to open an endpoint so the Faro SDK in the browser can send data back.

faro.receiver "default" {
  server {
    listen_address = "0.0.0.0"
    listen_port = 12347
    cors_allowed_origins = ["https://yourdomain.com"] 
  }

  output {
    logs   = [loki.write.local.receiver]
    traces = [otelcol.exporter.otlp.tempo.receiver]
  }
}

Important Note: Never set cors_allowed_origins = ["*"] in production. I’ve witnessed a system getting “flooded” with 10GB of junk logs daily just because random domains were pushing data, leading to wasted storage costs.

Step 2: Connecting to Loki

Next, define where the logs will be stored. If you’re self-hosting Loki, enter the correct server IP address in the configuration below:

loki.write "local" {
  endpoint {
    url = "http://loki-server:3100/loki/api/v1/push"
  }
}

Integrating Faro SDK into Frontend Applications

Once the “receiver station” is ready, we’ll attach sensors to the web app. Faro works excellently with React, Vue, Angular, and even vanilla Javascript.

Installing the Library

Use npm to add the SDK to your project:

npm install @grafana/faro-web-sdk

Initializing Faro in Source Code

Place the initialization code in your application’s entry file, such as index.js or main.ts. This ensures you don’t miss any errors from the moment the app starts loading.

import { initializeFaro } from '@grafana/faro-web-sdk';

initializeFaro({
  url: 'https://telemetry.yourcompany.com/collect',
  app: {
    name: 'ecommerce-frontend',
    version: '1.2.0',
    environment: 'production',
  },
  instrumentations: [
    ...getWebInstrumentations(),
    new TracingInstrumentation(),
  ],
});

Pro tip to avoid noise: Don’t log everything. I once made the mistake of capturing standard console.log entries. As a result, critical errors were buried under thousands of trivial logs from the dev team. Focus only on uncaught exceptions and error logs.

Leveraging Data: Turning Numbers into Action

When data starts flowing into Grafana, you’ll see information that was previously just… guesswork.

1. Real-world Web Vitals

Faro provides critical metrics to evaluate user experience:

  • LCP (Largest Contentful Paint): If this is > 2.5s, optimize your images. A 5MB banner image could be the culprit causing users to bounce early.
  • CLS (Cumulative Layout Shift): Measures UI stability. No one likes a website where buttons jump around while loading.

2. Javascript Error Tracing

In Grafana’s Explore section, you can view detailed stack traces for each error. Faro provides information on the browser, OS, and even screen resolution. This helps the QA team reproduce bugs instantly instead of asking customers: “What device were you using? What did you click?”.

3. Network Latency

There are cases where the server reports processing in just 50ms, but Faro reports the user waiting up to 2s. This discrepancy helps you realize the issue lies in the network connection or a heavy API payload slowing down the browser.

Final Thoughts from Real-world Implementation

Implementing Faro isn’t hard, but knowing how to filter data is key. Start by monitoring JS errors and Web Vitals before expanding to Distributed Tracing.

Since adopting Faro, my midnight emergency calls have significantly decreased. Instead of guessing, I just open the dashboard and point out: “Users in region X are experiencing errors on Chrome version Y.” That is how we master a system professionally.

Share: