
# JavaScript errors

JavaScript error tracking captures client-side errors and reports them through your own application. When enabled, the package registers a POST route at `/ranetrace/javascript-errors/store` (named `ranetrace.javascript-errors.store`, throttled to 60 requests per minute) and exposes a Blade directive that renders the client-side script.

## Add the Blade directive

Place `@ranetraceErrorTracking` in your layout (commonly before `</body>`). This is code, so it deploys with your app:

```blade
<!DOCTYPE html>
<html>
<body>
    @yield('content')

    @ranetraceErrorTracking
</body>
</html>
```

The directive renders the `ranetrace::error-tracker` view. When `javascript_errors.enabled` is `false`, the directive renders nothing, so it is safe to leave in place even before the feature is on.

## Turn it on in production

JavaScript error tracking runs where your users are, so enable it in your **production** environment, not just a local `.env`:

```dotenv
RANETRACE_ENABLED=true
RANETRACE_JAVASCRIPT_ERRORS_ENABLED=true
```

To try it during development, set the same flags in your local `.env`.

## What the script captures

From `resources/views/error-tracker.blade.php`:

- **`window.onerror`**: uncaught exceptions.
- **`unhandledrejection`**: unhandled promise rejections.
- **Console errors**: only when `RANETRACE_JAVASCRIPT_ERRORS_CAPTURE_CONSOLE_ERRORS=true` (default: `false`).

It also collects breadcrumbs leading up to the error:

| Category | Tracked events |
|---|---|
| `navigation` | Page loaded |
| `user` | Clicks (tag, id, class, first 50 chars of text), form submissions (action, method) |
| `http` | XHR completed/failed, fetch completed/failed |

The number of breadcrumbs kept is capped at `max_breadcrumbs` (default: 20).

## Sampling and deduplication

- **Sample rate**: `RANETRACE_JAVASCRIPT_ERRORS_SAMPLE_RATE` (default `1.0` = 100%).
- **Deduplication**: the script keys errors by `message|filename|line|column` and skips duplicates within a 50-entry rolling cache.

## Ignored errors

`config/ranetrace.php` ships with a default `ignored_errors` list, including:

- `ResizeObserver loop limit exceeded` / `…undelivered notifications`
- `Script error.` / `Script error` (cross-origin)
- `Failed to fetch`, `NetworkError when attempting to fetch resource`, `Network request failed`, `Load failed`
- `Loading chunk`, `ChunkLoadError`
- `cancelled`, `canceled`, `The operation was aborted`, `AbortError`
- `Illegal invocation`

Matches are case-insensitive substring checks. Add patterns by publishing the config and extending the array.

## Reporting errors manually

The script exposes two helpers on `window.Ranetrace`:

```javascript
try {
    riskyOperation();
} catch (error) {
    window.Ranetrace.captureError(error, { payment_amount: amount });
}

window.Ranetrace.addBreadcrumb('user', 'Clicked retry', { attempt: 2 });
```

`captureError(error, context)` sends an error immediately. `addBreadcrumb(category, message, data)` records a breadcrumb for inclusion with the next error.

## When you get notified

JavaScript errors notify you on the same cadence as PHP errors. Reports with the same message, normalized stack trace and error type are grouped into one error, and each report is an occurrence. An error notifies you:

- on its first occurrence, so a new error never goes unseen
- on its 5th and 10th occurrence, which tell a one-off from a pattern
- when it starts happening 10 times within an hour after a calmer hour, however old the error is
- when it comes back after you resolved it, even if it happens only once

An error that keeps failing at a steady rate notifies once when the burst starts, not every hour. A snoozed error stays silent until the snooze ends, and an ignored error is not recorded at all.

JavaScript errors have their own rule, separate from PHP errors, so you can switch one off and keep the other. Turn it off or on under **Notify**, **Rules**.

## Testing your setup

```bash
php artisan ranetrace:test-javascript-errors
```

## Disabling

```dotenv
RANETRACE_JAVASCRIPT_ERRORS_ENABLED=false
```

The Blade directive is safe to leave in your layout: it becomes a no-op when the feature is disabled.
