PHPackages                             rudolfbruder/laravel-snip - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Debugging &amp; Profiling](/categories/debugging)
4. /
5. rudolfbruder/laravel-snip

ActiveLibrary[Debugging &amp; Profiling](/categories/debugging)

rudolfbruder/laravel-snip
=========================

A dd()-style snipping tool for Laravel — capture values during a request and view them on-page in an admin-only panel.

v0.1.6(2mo ago)030MITPHPPHP ^8.1CI failing

Since May 9Pushed 2mo agoCompare

[ Source](https://github.com/rudolfbruder/laravel-snip)[ Packagist](https://packagist.org/packages/rudolfbruder/laravel-snip)[ Docs](https://github.com/rudolfbruder/laravel-snip)[ RSS](/packages/rudolfbruder-laravel-snip/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (7)Versions (9)Used By (0)

 [![laravel-snip](art/banner.svg)](art/banner.svg)

laravel-snip
============

[](#laravel-snip)

A `dd()` that does not die.

Drop a `snip($order)` anywhere in your Laravel app and the value shows up in an admin-only on-page panel — no log files to grep, no debugger to attach, no broken page. Works the same on full HTML responses, Livewire components, and Inertia SPA navigations.

```
snip($order, 'before-payment');
```

Open the page as an authorised user, hit **Cmd+K** (or **Ctrl+K**), and you have a Horizon-style panel pinned to the corner of the page with everything you captured during the request — values, timings, milestones, dataLayer events, cache keys, and queue state.

Safe to leave in production. Gated, redacted, never cached.

---

Why not just `dd()` or Debugbar?
--------------------------------

[](#why-not-just-dd-or-debugbar)

**vs. `dd()` / `dump()`**

`dd()``dump()``snip()`Breaks the pageYes — terminates the responseSometimes — prints into the HTMLNo — value rendered in a side panelSurvives a redirectNo — the response is killed before the redirect runsNo — output lost on the next requestYes — captures are flashed across the redirect and shown on the landing pageWorks in API / JSON / Inertia XHR responsesNo — corrupts the response bodyNo — sameYes — shipped via Inertia shared prop, or carried across redirects until a panel-renderable responseMultiple values per requestOne, then deadYes, inlineYes — and grouped by label, with timings and milestones in their own tabsInspect laterNo — gone after the pageNo — gone after the pageYes — pin the panel open, navigate freely, keep capturingSafe to leave in prodNeverNeverYes — gated, redacted, no-store cached**vs. Laravel Debugbar / Telescope / Clockwork**

Debugbar / Telescope / Clockwork`snip()`Production-safeDiscouraged or off-limits — they capture for *every* request and store a lotYes — recording short-circuits for non-gated users before any backtrace, dump, or serialise runsPer-user gatingCoarse (env / IP / config flag)Fine-grained Laravel `Gate::define('viewSnip', …)` — pick any user predicatePerformance hit on the hot pathAlways-on instrumentationZero cost for non-gated users; ~one gate check per request for gated usersWhat gets recordedThe whole request (queries, jobs, mail, views, etc.) — opinionatedWhatever *you* write `snip(…)` against — surgical, intent-drivenStorageDatabase / files / external services to clean upSession flash + in-memory; nothing to migrate, nothing to expireSetupMigrations, providers, dashboards, retention`composer require` + one gate closureThe trade is deliberate. Debugbar / Telescope answer "what happened in this request?". `snip()` answers "what is this value right now?" — the same question `dd()` answers, with none of the costs of `dd()`.

What it carries over from a production-safe tool like Horizon: scoped per-request state, an admin-only gate, private cache headers on every injected response, and zero impact on users who do not match the gate.

---

Installation
------------

[](#installation)

```
composer require rudolfbruder/laravel-snip
php artisan snip:install
```

The installer publishes `config/snip.php`, copies the frontend bundle to `public/vendor/snip/`, and creates `app/Providers/SnipServiceProvider.php` where you define who can see the panel.

Register the provider:

```
// Laravel 10 — config/app.php
App\Providers\SnipServiceProvider::class,

// Laravel 11+ — bootstrap/providers.php
App\Providers\SnipServiceProvider::class,
```

After every `composer update rudolfbruder/laravel-snip`, refresh the bundle:

```
php artisan snip:publish
```

Who can see the panel
---------------------

[](#who-can-see-the-panel)

Edit `app/Providers/SnipServiceProvider.php`:

```
protected function gate(): void
{
    Gate::define('viewSnip', function ($user = null) {
        return $user?->is_admin === true;
    });
}
```

Without an override, only `app()->environment('local')` sees the panel. Unauthorised users never receive captured data — the middleware never injects, the Inertia share callback returns `null`, and the recording API short-circuits before any backtrace or serialisation runs.

---

Laravel support
---------------

[](#laravel-support)

Three top-level helpers cover most use:

```
snip($value, 'label');     // capture a value
snip_time('elastic');      // record an elapsed-time entry
snip_here('reached-step-2'); // drop a milestone breadcrumb
```

Or use the facade:

```
use RudolfBruder\LaravelSnip\Facades\Snip;

Snip::add($order, 'order');
Snip::start('payment');
$result = $gateway->charge($order);
Snip::timing('payment');
Snip::milestone('payment-confirmed');
```

Reload the page. The panel pill appears bottom-right; click it or press **Cmd+K / Ctrl+K**.

That is the entire surface area. No bootstrapping, no middleware to register, no `` tags to add — the package wires everything into the framework on install.

Inertia support
---------------

[](#inertia-support)

Works out of the box. The package detects Inertia and registers a shared `_snip` prop so every visit — initial HTML and subsequent SPA XHR navigations — carries the current request's captures.

```
// Inertia controller
public function show(Order $order)
{
    snip($order, 'order');
    snip_time('elastic-query');

    return Inertia::render('Orders/Show', [...]);
}
```

Captures appear in the panel without a full page reload. When the panel is already open and you navigate to another page via ``, the panel re-renders with the new request's data.

For Inertia POST → 303 → GET XHR flows (form submissions, destroy actions), captures recorded in the POST handler are flashed to the session and replayed on the next request, so nothing gets lost across the redirect.

---

Tabs
----

[](#tabs)

The panel has six tabs. Each tab is independent — you only see the ones with data, or all of them when `display_mode = always`.

### Snips

[](#snips)

Inspect any PHP value as a typed, collapsible tree.

```
snip($order, 'order');
snip(['user' => $user, 'cart' => $cart], 'checkout-state');
snip(Order::with('items')->find($id));
```

Returns the value unchanged so it can be inlined inside expressions:

```
return snip(User::find($id), 'lookup')->email;
```

Eloquent models, collections, arrays, objects, and primitives all render with type badges, child counts, and a memory size estimate. Keys matching `password`, `token`, `secret`, etc. are auto-redacted.

### Timings

[](#timings)

Profile blocks of code with start/stop marks.

```
Snip::start('elasticsearch');
$products = $repo->search($query);
Snip::timing('elasticsearch');

snip_time('build-payload');         // measured from request start
```

Each timing shows the elapsed duration in milliseconds plus where in the request lifecycle it ran, so you can see at a glance which block ate the budget.

### Milestones

[](#milestones)

Confirm a code path executed without breaking the page.

```
snip_here('discount-applied');
snip_here('admin-fallback-path');
```

A non-fatal alternative to `dd()`. Useful for confirming a feature flag fired, a guard clause passed, or a fallback branch took over — anywhere you would have reached for `dump()` and a page reload.

### DataLayer

[](#datalayer)

Tees every `window.dataLayer.push(...)` call into a panel tab so GTM events are visible without opening the GTM debugger.

```
window.dataLayer.push({
    event: 'add_to_cart',
    ecommerce: { items: [...] },
});
```

The tab shows the event name, the full payload, and the order in which events were pushed during the page lifetime. Site-defined events are highlighted; framework noise (`gtm.js`, `gtm.dom`, `gtm.load`) is collapsed.

Disable with `SNIP_DATALAYER=false`.

### Cache

[](#cache)

Browse the active cache store without a separate tool.

Supported drivers:

DriverLists keysInspect valueredisYes (SCAN with prefix)Yes (handles strings, lists, sets, hashes, zsets)arrayYesYesdatabaseYesYesfileYes (hashed keys only)NomemcachedNo (driver not enumerable)—Click any key to fetch its value on demand — the panel never embeds cache contents in the HTML response. Useful for confirming a `Cache::remember(...)` actually wrote, or seeing what is currently under `user:123:cart`.

Disable with `SNIP_CACHE=false`.

### Queue

[](#queue)

Inspect jobs across the configured queue driver — failed, pending, scheduled, and (Horizon only) completed.

StateSourcefailed`queue.failer` — works on any driverpending`redis` / `database` queues — jobs ready to runscheduled`redis` / `database` queues — jobs delayed to a future timecompletedHorizon `completed_jobs` tableUseful for verifying a job dispatch actually landed, checking why a notification has not gone out yet, or watching a queue drain during a deploy. Each list is paginated and capped (`max_scan` / `per_page`) so a 100k-job queue does not stall the request.

Disable with `SNIP_QUEUE=false`. Name your redis queues with `SNIP_QUEUE_NAMES=high,default,low`.

---

Configuration
-------------

[](#configuration)

Publish only when overriding defaults:

```
php artisan vendor:publish --tag=snip-config
```

Most-used knobs:

KeyDefaultPurpose`enabled``env('SNIP_ENABLED', true)`Master kill-switch.`display_mode``'on_capture'``'always'` to show the pill on every gated response.`guard``env('SNIP_GUARD')`Auth guard for the gate. Null = framework default.`pending_redirects``true`Flash captures across redirect chains.`redact_keys``[password, token, secret, …]`Keys replaced with `***REDACTED***`.`cache.enabled` / `queue.enabled` / `datalayer``true`Toggle individual tabs.`limits.*`variousDepth / array / string / per-kind hard caps.See `config/snip.php` for the full reference with inline notes.

Security
--------

[](#security)

- Captures only reach users who pass the `viewSnip` gate.
- Common credential keys auto-redacted; extend `redact_keys` for project-specific PII.
- Injected responses are forced `Cache-Control: private, no-store` plus `Vary: Cookie` so shared caches (Varnish, CDN, response cache) cannot leak captures to other users.
- Bundle file contains the renderer only — no captured data lives in JS.
- The recording manager is scoped per request, so Octane and queue workers reset between requests.
- The cache and queue lookup endpoints are gated by the same `viewSnip` ability — a guest hits `403`, not the data.

License
-------

[](#license)

MIT.

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance87

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 83.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

7

Last Release

71d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/56951790?v=4)[Rudolf Bruder](/maintainers/rudolfbruder)[@rudolfbruder](https://github.com/rudolfbruder)

---

Top Contributors

[![rudolfbruder](https://avatars.githubusercontent.com/u/56951790?v=4)](https://github.com/rudolfbruder "rudolfbruder (15 commits)")[![jaroslavstefanec](https://avatars.githubusercontent.com/u/55752260?v=4)](https://github.com/jaroslavstefanec "jaroslavstefanec (3 commits)")

---

Tags

laraveldebugdumpddrudolfbruderlaravel-sniphorizon-style-gate

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/rudolfbruder-laravel-snip/health.svg)

```
[![Health](https://phpackages.com/badges/rudolfbruder-laravel-snip/health.svg)](https://phpackages.com/packages/rudolfbruder-laravel-snip)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[laravel/ai

The official AI SDK for Laravel.

1.0k3.2M246](/packages/laravel-ai)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M133](/packages/roots-acorn)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

77922.3M186](/packages/laravel-mcp)[api-platform/laravel

API Platform support for Laravel

58174.6k17](/packages/api-platform-laravel)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

813336.8k3](/packages/defstudio-telegraph)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
