Already using Nightwatch and not ready to fully switch? You can run both agents side by side. Nightwatch sends telemetry to both, so you can compare them in parallel before committing.
1. Set NightOwl to a different port
In your .env, set the NightOwl agent to a different port and provide both tokens:
NIGHTOWL_AGENT_PORT=2410
NIGHTOWL_TOKEN=your-nightowl-token-from-dashboard
NIGHTWATCH_TOKEN=your-nightwatch-token
NIGHTWATCH_TOKEN is used by the Nightwatch package to send telemetry. NIGHTOWL_TOKEN is the token from the NightOwl dashboard — the NightOwl agent uses it for payload authentication and health reporting.
2. Create a MultiIngest wrapper
Create app/Support/MultiIngest.php:
<?php
namespace App\Support;
use Laravel\Nightwatch\Contracts\Ingest;
final class MultiIngest implements Ingest
{
/** @var Ingest[] */
private array $ingests;
public function __construct(Ingest ...$ingests)
{
$this->ingests = $ingests;
}
public function write(array $record): void
{
foreach ($this->ingests as $ingest) {
try { $ingest->write($record); } catch (\Throwable) {}
}
}
public function writeNow(array $record): void
{
foreach ($this->ingests as $ingest) {
try { $ingest->writeNow($record); } catch (\Throwable) {}
}
}
public function ping(): void
{
foreach ($this->ingests as $ingest) {
try { $ingest->ping(); } catch (\Throwable) {}
}
}
public function shouldDigest(bool $bool = true): void
{
foreach ($this->ingests as $ingest) { $ingest->shouldDigest($bool); }
}
public function shouldDigestWhenBufferIsFull(bool $bool = true): void
{
foreach ($this->ingests as $ingest) { $ingest->shouldDigestWhenBufferIsFull($bool); }
}
public function digest(): void
{
foreach ($this->ingests as $ingest) {
try { $ingest->digest(); } catch (\Throwable) {}
}
}
public function flush(): void
{
foreach ($this->ingests as $ingest) { $ingest->flush(); }
}
}
3. Wire it up in AppServiceProvider
In your app/Providers/AppServiceProvider.php, add to the register method:
public function register(): void
{
$this->app->booted(function () {
if (! $this->app->bound(\Laravel\Nightwatch\Core::class)) {
return;
}
$core = $this->app->make(\Laravel\Nightwatch\Core::class);
$nightowlPort = config('nightowl.agent.port', 2410);
$nightowlToken = config('nightowl.agent.token', config('nightwatch.token', ''));
$tokenHash = substr(hash('xxh128', $nightowlToken), 0, 7);
$nightowlIngest = new \Laravel\Nightwatch\Ingest(
transmitTo: "127.0.0.1:{$nightowlPort}",
connectionTimeout: 0.5,
timeout: 0.5,
streamFactory: new \Laravel\Nightwatch\SocketStreamFactory,
buffer: new \Laravel\Nightwatch\RecordsBuffer(length: 500),
tokenHash: $tokenHash,
);
$core->ingest = new \App\Support\MultiIngest($core->ingest, $nightowlIngest);
});
}
4. Run both agents
# Terminal 1 — Nightwatch agent (default port 2407)
php artisan nightwatch:agent
# Terminal 2 — NightOwl agent (port 2410)
php artisan nightowl:agent
Both agents receive identical telemetry. If one goes down, the other keeps running.
Switching fully to NightOwl
When you’re ready, remove the MultiIngest wrapper and set NIGHTOWL_AGENT_PORT=2407 (or whatever port Nightwatch was using). That’s it.