Grafana Cloud

Send custom errors

After you set it up, Faro Web SDK automatically handles and reports all unhandled exceptions and rejected promises. Unhandled errors are errors that are not identified in a try/catch block and are picked up by the global error handler. Consider the following example:

In the following example, the someOperation function will generate an error that can potentially break your app because it is not handled properly. Similarly, rejected promises are asynchronous functions (Promises) that fail and are not handled by a .catch(error => {}) or a try/catch block in an async/await context.

function someOperation() {
  throw new Error('I am supposed to fail');

function main() {


In this case, if fetch fails for any reason, the error propagates to the global promise rejection handler.

async function getUsers() {
  const users = await fetch('/api/users');
  return users;

async function main() {
  const userList = await getUsers();
  // render the user list


Faro Web SDK automatically hooks into both of these handlers and reports the error back to the collector endpoint. These events will ultimately be ingested by a Loki instance as logs with a specific label kind=error. For more information about Loki labels, refer to Labels.

When to report errors manually

Faro reports only unhandled errors, which means if you have already implemented an error handling mechanism (for example, ErrorBoundary for React Apps), you should manually add Faro Web SDK to the error handling pipeline.

Before you begin


After it is initialized, Faro is an instance that can be accessed either by importing it from the @grafana/faro-web-sdk or referencing it from the window global object.

// Import the global faro instance
import { faro } from '@grafana/faro-web-sdk';

The faro.api object is a wrapper of the Faro API and provides a pushError method with which you can send any error. You can also provide the stack frames, or manually set the type of event for better filtering.

// Send custom errors with faro
// 1. Simple error generated at some point in your application
// 2. Namespaced error

// Supposed this error is generated somewhere in your app
const error = new Error('I am supposed to fail');
// ...
// And at some point you want to pipe it to Faro

// Different type
const error = new Error('I am an error generated by network requests');
// ...
faro.api.pushError(error, {
  type: 'network',