Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Js Logger Bundle Laravel Package

nelmio/js-logger-bundle

NelmioJsLoggerBundle integrates JavaScript error logging into Symfony applications, capturing browser-side errors and warnings and sending them to your server logs via Monolog. It helps centralize frontend issues alongside backend logs for easier debugging.

View on GitHub
Deep Wiki
Context7

Getting Started

Before anything else: this is a Symfony bundle, not a Laravel package. There is no JsLoggerServiceProvider, no auto-discovery, no config/js-logger.php. If your stack is pure Laravel, you cannot composer require and php artisan your way to a working install — you will use it either (a) inside a Symfony app that shares your architecture, or (b) as a reference implementation to copy the pattern into Laravel. Both are legitimate; decide which one you are doing before writing code.

If you actually have a Symfony component in your stack:

  1. composer require nelmio/js-logger-bundle
  2. Register Nelmio\JsLoggerBundle\NelmioJsLoggerBundle in config/bundles.php
  3. Create config/packages/nelmio_js_logger.yaml with at minimum log_level and the route/controller you want exposed
  4. Import the bundle's routing (config/routes/nelmio_js_logger.yaml)
  5. Pull the client script into your layout via the bundle's Twig template (@NelmioJsLogger/logger.js), and confirm the browser is actually POSTing by watching var/log/dev.log

First use case (the only one worth doing first): capture uncaught window errors and unhandled promise rejections from production browsers into a dedicated Monolog channel. Nothing else. Do not wire up console.error interception, breadcrumbs, or source maps on day one.

If you are porting to Laravel (the more likely scenario for this audience): read Controller/LogController.php and the Resources/public/js/ shim first — they are ~100 lines combined. Then build:

  • POST /_js-errors route → a thin controller that validates and writes to Log::channel('javascript')
  • A JS snippet (or @sentry/browser-style shim) that hooks window.addEventListener('error') and 'unhandledrejection', builds a JSON payload, and fires it with navigator.sendBeacon
  • A javascript log channel in config/logging.php pointing at a separate daily file so error noise never pollutes application logs

Implementation Patterns

Endpoint contract. Mirror the bundle's shape rather than inventing one: { message, url, line, column, error (stack), userAgent }. Keep it a flat JSON object — the bundle's JS does no nesting, and flat payloads are trivially indexable if you ever ship them to Elastic/Datadog.

Dedicated channel, always. The single most important pattern. Route JS errors to js_errors / javascript channel, separate from stack and single. You will want to tail it independently, set its own retention, and alert on it without alerting on app errors.

Sampling at the edge. Real browsers generate floods (extension errors, third-party script failures, ad blockers). Wrap the client shim in a sample rate:

if (Math.random() > 0.1) return; // 10% of errors

Better still, dedupe client-side by hashing message + url + line and only sending the first occurrence per page load.

Use sendBeacon, not fetch. The bundle targets old browsers, but for new code navigator.sendBeacon(url, JSON.stringify(payload)) survives page unload and doesn't require awaiting a promise, which is exactly what you need when the error fires mid-navigation. Fall back to fetch(..., { keepalive: true }) if the payload needs custom headers.

Context enrichment. The bundle's logged_content config is the analogue of "what do I attach to each entry." In Laravel, put this in middleware or the controller:

  • user_id from Auth::id() (never the session cookie, never the full user agent hash)
  • request_id from a correlation middleware so a JS error can be joined to a server-side log line
  • route / url from $_SERVER['REQUEST_URI'] sent by the client
  • app_version — commit SHA or git tag; without this you cannot tell whether a fix shipped

Integration tip — throttle at the route level, not in the controller. Route::post('/_js-errors', ...)->middleware('throttle:60,1'). The bundle exposes no built-in rate limiting; if you port it, add this deliberately. A misbehaving script in one user's tab can otherwise generate thousands of log lines per minute.

Exclusion patterns. The bundle's exclude_patterns (regex on the source URL) is a pattern worth copying: never log errors originating from /admin, /horizon, or third-party domains you don't own. Filtering server-side is cheap; filtering downstream in Kibana is not.

Stack traces, not messages. A JS message alone ("Cannot read property 'x' of undefined") is worthless. Ensure the payload's error field contains the full Error.stack. If minified, note the version so you can map it later.

Gotchas and Tips

You cannot use this with Laravel out of the box. There is no Laravel bridge, no facade, no config publish. composer require nelmio/js-logger-bundle in a Laravel app installs files that Laravel never loads. Treat it as documentation, not a dependency. This is the single largest source of wasted time for a Laravel developer picking this up.

The endpoint is unauthenticated by design. That means anyone can POST arbitrary log entries to your server — log injection, storage exhaustion, PII fabrication in your incident data. Mitigations: throttle hard, cap message and error length (e.g. 4KB), reject payloads where url origin doesn't match app.url, and never eval or render a logged value. If you need auth, add it in your port — the bundle won't do it for you.

CSP will silently block the beacon. If you ship Content-Security-Policy, add your logging origin to connect-src. Symptom: no errors in your log channel, browser devtools console shows a Refused to connect violation. This is the most common "why is nothing logging" complaint.

sendBeacon sends text/plain by default. If your controller requires application/json, either accept text/plain and json_decode manually, or use a Blob with an explicit type: new Blob([body], { type: 'application/json' }). This will bite you during local testing even though it works in production.

Beware the error loop. If your logging endpoint itself throws an uncaught error, the client shim catches it and POSTs again — infinite loop, log flood. Always return 204 No Content unconditionally from the endpoint and swallow all exceptions in the handler. Wrap in try { ... } catch { return response()->noContent(); }.

Do not log from a logging channel that writes to the same channel being read. Sounds obvious, but if you point the JS channel at stack and also have middleware logging request failures there, a bad deploy will produce a self-referential flood. Keep javascript on its own file.

Extension points (if you're on Symfony). The bundle is small enough to extend cleanly: override the controller via a service alias, swap the JS template with your own Twig template, and set log_level per environment. In a Laravel port, the equivalents are: replace the controller outright, publish the Blade partial, and set LOG_LEVEL in .env.

Version pinning and maintenance signal. Last release 2026-04-08 with 176 stars and 0 dependents is a warning sign — this is a small, low-traffic package. For a Laravel team, that's one more reason to port the pattern (~100 lines) rather than depend on a bundle that ships on a Symfony release cadence disconnected from yours.

Debugging checklist when nothing appears in logs: (1) browser connect-src CSP, (2) ad blocker intercepting the route name (/log, /error are commonly blocked — use an innocuous path like /_js-errors), (3) the route actually registered (php artisan route:list | grep js-errors), (4) sendBeacon payload content-type, (5) log channel permissions (storage/logs writability), (6) sampling filter dropping everything.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums