# Client hooks


The `@flareapp/js` client gives you two hooks to change what gets reported, or stop a report before it goes out. Configure them with `flare.configure()`.

## `beforeEvaluate`

```ts
beforeEvaluate: (error: Error) => Error | false | null | Promise<Error | false | null>;
```

`beforeEvaluate` runs before Flare builds a report from an error. Building a report has a cost: it walks the stack trace and collects context, so this is the place to stop errors you don't care about before that work happens.

It can be async. Return `false` or `null` (or a promise that resolves to either) to drop the error entirely: Flare won't create or send a report for it.

```js
flare.configure({
    beforeEvaluate: (error) => {
        if (error.message.includes('Boring error')) {
            return null;
        }

        return error;
    },
});
```

`beforeEvaluate` only runs for errors passed to `flare.report()` and for errors caught automatically. It does not run for `flare.reportMessage()`, since there is no error to evaluate. It also does not run for an unhandled promise rejection that has no `Error` and no stack, for example `Promise.reject('a string')`: that report is built and sent without ever going through the hook, for the same reason `reportMessage()` skips it. See "Hook behavior with reportMessage" below.

## `beforeSubmit`

```ts
beforeSubmit: (report: Report) => Report | false | null | Promise<Report | false | null>;
```

`beforeSubmit` runs right before a report is sent, for every report Flare builds, including messages sent with `reportMessage()`. It can also be async. Use it to edit the report, or return `false` or `null` to stop it from being sent at all:

```js
flare.configure({
    beforeSubmit: (report) => {
        const edited = structuredClone(report);

        // Redact cookies from every report
        delete edited.attributes['http.request.cookies'];

        return edited;
    },
});
```

You can also use this hook to add context to a report right before it's sent. Read more in [adding custom context](/docs/javascript/data-collection/adding-custom-context#customizing-the-report-before-sending).

## Report structure

The `report` object passed to `beforeSubmit` has this shape:

```ts
type Report = {
    exceptionClass?: string | null;    // Error constructor name, e.g. "TypeError"
    message?: string | null;           // Error message
    code?: string;                     // Source code snippet around the error
    seenAtUnixNano: number;            // Timestamp in nanoseconds
    isLog?: boolean;                   // true for reportMessage() calls
    level?: MessageLevel;              // Severity level, for log messages
    sourcemapVersionId?: string;       // Sourcemap version used to resolve the stack trace
    trackingUuid?: string;             // Tracking identifier
    handled?: boolean;                 // Whether the error was caught
    openFrameIndex?: number;           // Index of the application frame to highlight
    applicationPath?: string;          // Application base path
    overriddenGrouping?: OverriddenGrouping | null; // Custom grouping strategy
    stacktrace: StackFrame[];          // Parsed stack frames
    events: SpanEvent[];               // Glows, converted to events
    attributes: Attributes;            // Flat key-value context: request data, cookies, custom context, SDK info, and more
};
```

## Hook behavior with `reportMessage`

`flare.reportMessage()` has no error to evaluate, so `beforeEvaluate` never runs for it. `beforeSubmit` still runs, in the same way it does for `flare.report()`.
