Looking to hire Laravel developers? Try LaraJobs

watchtower-laravel maintained by phattarachai

Description
Laravel client for the Watchtower self-hosted Sentry-compatible exception tracker. Wires up sentry/sentry-laravel and a same-origin browser tunnel that dodges ad blockers.
Last update
2026/05/18 18:11 (dev-main)
License
Links
Downloads
20

Comments
comments powered by Disqus

Watchtower Laravel

Laravel client for Watchtower, a self-hosted Sentry-compatible exception tracker. Installs and configures sentry/sentry-laravel, wires Integration::handles($exceptions) into bootstrap/app.php, and exposes a same-origin browser tunnel (/api/watchtower-relay) that proxies envelopes to your Watchtower instance — dodging ad-blockers that strip ?sentry_key= query strings.

Install

composer require phattarachai/watchtower-laravel
php artisan watchtower:install --dsn=http://your-public-key@your-watchtower-host/42

The install command:

  1. Validates and writes WATCHTOWER_DSN and SENTRY_LARAVEL_DSN to .env.
  2. Patches bootstrap/app.php to call Sentry\Laravel\Integration::handles($exceptions) inside withExceptions(...).
  3. Publishes config/watchtower.php.
  4. If vite.config.{js,ts} is present, writes VITE_SENTRY_DSN, VITE_SENTRY_TUNNEL, and VITE_SENTRY_ENVIRONMENT and prints a Vite entry snippet.

Re-running is idempotent. Pass --dry-run to preview changes.

Configuration

Env key Default Purpose
WATCHTOWER_DSN falls back to SENTRY_LARAVEL_DSN Watchtower DSN: http://{key}@{host}/{numeric-project-id}.
WATCHTOWER_RELAY_ENABLED true Register the relay route on boot.
WATCHTOWER_RELAY_PATH /api/watchtower-relay Relay endpoint path (must live under /api/).
WATCHTOWER_RELAY_TIMEOUT 5 Upstream request timeout (seconds).
WATCHTOWER_RELAY_ASYNC false Forward envelopes through a queued job instead of sync.
WATCHTOWER_RELAY_QUEUE (default queue) Queue name when async is enabled.
WATCHTOWER_VERIFY_SSL true Verify upstream TLS certificate.
WATCHTOWER_CONNECT_TIMEOUT 3 Guzzle connect timeout (seconds).

Browser side

The browser SDK posts envelopes to your own app at /api/watchtower-relay. The relay parses your configured DSN, forwards the request body verbatim to {scheme}://{host_with_port}/api/watchtower-relay on the Watchtower instance, and passes back the upstream status and rate-limit headers.

import * as Sentry from '@sentry/browser';

Sentry.init({
    dsn: import.meta.env.VITE_SENTRY_DSN,
    tunnel: import.meta.env.VITE_SENTRY_TUNNEL,
    environment: import.meta.env.VITE_SENTRY_ENVIRONMENT,
});

Because the request hits your own origin under /api/, ad-blockers don't recognize it as Sentry traffic.

Async forwarding

Set WATCHTOWER_RELAY_ASYNC=true to dispatch each forward through a ForwardEnvelope job. The relay returns 202 {"queued": true} immediately and the worker performs the upstream POST. Failures are logged but not retried beyond Guzzle's default behavior — the Sentry SDK retransmits anyway.

Verify

php artisan watchtower:test

Prints the resolved config, runs sentry:test, and POSTs a synthetic envelope through the relay path.

Troubleshooting

See the upstream Watchtower skill: https://watchtower.phattarachai.app/skill/watchtower-error-tracking.

License

MIT.