genealabs/nova-telescope
Brings Laravel Telescope into Laravel Nova, letting you browse requests, exceptions, queries, logs, and other Telescope entries directly from your Nova dashboard. Adds a convenient monitoring tool so you can inspect and debug application activity without leaving the admin panel.
Prerequisites — confirm all three before writing any code:
telescope_entries is empty, you will be debugging an empty panel.Install:
composer require genealabs/nova-telescope
Because the repository is archived, pin it immediately:
composer require genealabs/nova-telescope:^11.0
and commit composer.lock. There is no upstream to publish a patch if the resolved version breaks.
Register the tool. In app/Providers/NovaServiceProvider.php:
use GeneaLabs\NovaTelescope\NovaTelescope; // confirm exact FQCN in the package's src/
public function tools()
{
return [
new NovaTelescope(),
];
}
Assets. Nova tools ship as a nova-components-style package with a compiled dist/. Check whether dist/js/tool.js is committed in vendor/genealabs/nova-telescope/:
ls vendor/genealabs/nova-telescope/dist
If dist/ is empty or missing, you are in npm install && npm run prod territory inside a vendor directory — which is exactly the kind of failure archived packages exhibit on fresh installs. Test this in a clean CI checkout before trusting it.
Where to look first, in order:
vendor/genealabs/nova-telescope/composer.json — the real Nova/Telescope/PHP constraints, not the changelog prose.src/ — find the Tool class and read its canSee() / authorize() method. This is the security boundary and you must know what it does.telescope_entries directly (schema-coupled). This single fact determines how it fails.First use case — a support triage loop, in staging:
That round-trip — replacing "can you check the logs?" with a self-serve read — is the entire value proposition. Validate it before investing further.
Do not register the tool unconditionally. Treat registration as a config decision:
// config/nova.php (or a dedicated config/nova-telescope.php you own)
'telescope_tool' => env('NOVA_TELESCOPE_ENABLED', false),
public function tools()
{
return array_filter([
config('nova.telescope_tool') ? new NovaTelescope() : null,
]);
}
Default false, enable in staging only. This keeps the archived dependency off every production panel by default and forces an explicit decision to expose it.
This is the pattern that matters more than any other. There are two independent gates:
| Gate | Controls |
|---|---|
Telescope::auth(fn ($request) => ...) in TelescopeServiceProvider |
Who can reach /telescope and its API routes |
Nova's canSee() / authorize() on the tool |
Who sees the Nova menu entry and the tool's page |
If the Vue frontend proxies Telescope's routes, both gates apply — Telescope's middleware runs on each request, so a Nova user without Telescope access gets 403s inside the tool. Ugly, but safe.
If the Vue frontend reads the database directly, only Nova's gate applies. Telescope's auth callback is bypassed entirely, and anyone with Nova tool visibility sees raw request payloads, headers, cookies, and SQL bindings.
Verify which one you have, in a non-production environment:
// tinker against a Nova user who should NOT see Telescope
$user = User::where('email', '[email protected]')->first();
// Log in as them, open the tool, watch network tab.
// 403 from /telescope/... → proxying, safe.
// 200 with populated data → direct read, your only gate is Nova.
If it is a direct read, tighten canSee() in your own subclass:
class GatedTelescope extends NovaTelescope
{
public function canSee(NovaRequest $request): bool
{
return parent::canSee($request)
&& $request->user()->hasRole(['engineer', 'ops']);
}
}
Register your subclass in NovaServiceProvider::tools(), never the vendor class directly.
The wrapper does not change Telescope's storage or sampling behaviour — and it does not fix them either. Set these first, because putting a convenient panel in front of Telescope will accelerate adoption in environments you previously kept dark:
// AppServiceProvider
Telescope::filter(function (IncomingEntry $entry) {
return match (true) {
$this->app->environment('local') => true,
$entry->type === EntryType::EXCEPTION => true,
$entry->type === EntryType::JOB => true,
$entry->type === EntryType::REQUEST => false, // do not store payloads
$entry->type === EntryType::QUERY => false,
default => false,
};
});
Telescope::night(); // sampling
php artisan telescope:prune --hours=72
# schedule it
Rule of thumb: if you would not show telescope_entries to the whole Nova user base, do not register the tool for the whole Nova user base. The two decisions are the same decision.
The low-cost, zero-dependency equivalent of this package is a Nova menu link. If the archived status becomes a problem — and it will at the next Nova major — you can migrate in an afternoon:
// NovaServiceProvider::tools() or a custom Dashboard card
Nova::script('telescope-link', resource_path('js/nova/telescope-link.js'));
Or, iframe Telescope behind your own Nova tool, keeping Telescope's auth callback as the single source of truth. One to three engineer-days and you own it outright. Measure this before you invest in forking the package.
Where the package earns its keep, concretely:
batch_id — the tool shows both screens side by side within Nova, which is the workflow win./telescope, in your runbooks. Consistency is the whole point of consolidating into one panel.Archived is the dominant constraint, not a footnote. 16 stars, 0 dependents, no vendor, last release November 2024. There is no one to file an issue with. Treat every bug you find as your own work. Pin the version, and put an explicit line in your dependency register: archived, reviewed, replacement plan at next Nova major.
Expect breakage at the next Nova major. Nova changes tool scaffolding and asset conventions between majors. The archive date means this tool predates Nova 5 and Laravel 12. Do not build anything load-bearing on it. Budget for a fork or removal at the next framework upgrade, not "someday."
Asset rot on fresh installs. Archived packages frequently fail to compile from a clean checkout — stale package.json, missing dist/, lockfile drift from an npm registry three years newer. This failure mode is invisible on developer machines that already have node_modules and only surfaces in CI or a new hire's first clone. Test composer install from a bare clone in CI before rollout. This is the single most common way archived Nova tools bite.
Two gates, one assumption. The highest-severity failure here is authorization divergence: Telescope's auth callback says "engineers only," Nova's tool visibility says "all Nova users," and the tool reads the database directly. Request payloads, headers, cookies, session IDs, and SQL bindings then become visible to support staff, contractors, and anyone else in the Nova user table. Prove the gates agree; do not assume they do.
Telescope storage growth is not this package's fault but will be blamed on it. telescope_entries grows fast and is not the wrapper's problem — but the wrapper makes the data convenient, which drives adoption, which drives storage. Watch table size in the first month after rollout. Prune on a shorter schedule than you think you need. If a table with LONGTEXT payloads grows unbounded and you never prune, you will discover it at the worst possible moment.
Debugging a blank or broken panel:
# 1. Is Telescope actually collecting?
php artisan tinker --execute="dump(DB::table('telescope_entries')->count());"
# 2. Is the tool's compiled asset present and served?
ls -la public/vendor/genealabs/nova-telescope/ 2>/dev/null || echo "check dist/"
# 3. Does a fresh install build?
composer install --no-dev && npm ci && npm run prod
# 4. Are the vendor constraints what you think they are?
composer why-not genealabs/nova-telescope
Empty panel usually means one of: Telescope migrated but not recording (check Telescope::filter), the tool's asset 404s (check public/vendor symlink / nova:publish), or a JS exception in the browser console — open devtools before assuming the backend is at fault.
Extension points are limited to what you fork. The clean places to intervene without touching vendor code:
canSee() / authorize() — register your subclass in NovaServiceProvider.filter() and auth() in TelescopeServiceProvider — this is upstream, supported, and the correct place to solve exposure problems.Anything deeper — adding filters, changing columns, fixing a Vue bug — means editing vendor/ (never) or forking into your namespace (only with a named owner and a CI entry). Do not patch vendor files; the next composer install erases it and the person who does it will not know why the panel changed.
Do not use this for observability. Telescope is a debugging tool, not an APM. No alerting, no SLOs, no retention policy, no cross-service traces. If someone asks "can we get paged when this fires," the answer is Sentry, Pulse, or Nightwatch — not a Nova tool.
If you do fork it, do it properly: vendor under your namespace, add it to the dependency register with a named owner, wire a CI job that runs composer install + npm run prod on every Nova and Telescope major, and commit to retesting. That is a recurring cost line, not a one-time fix. The honest comparison is never "free package vs. paid build" — it is "unowned abandoned package vs. a small owned tool." The small owned tool usually wins, and it is a nav link plus an iframe away.
How can I help you explore Laravel packages today?