jeffersongoncalves/laravel-clarity
Laravel Clarity is a lightweight package that brings Microsoft Clarity analytics to your Laravel app. Publish the config, add the tracking snippet, and start capturing session recordings, heatmaps, and click data with almost no setup.
The package renders inline/<script> tags into your Laravel responses. Start by reading the service provider — that's where the script registration API lives — and the config file, which is where you control placement (head vs. body), ordering, and whether output is queued per-request or globally.
Minimal setup:
composer require the package, then php artisan vendor:publish --tag=<package>-config.First use case: add a single third-party snippet (analytics, error tracking, consent loader) and verify it appears in the rendered HTML exactly once, in the right position, and after @vite if anything depends on your app bundle.
As of 1.1.0, do that first test with a CSP nonce enabled. This is the natural entry point because it's the release's headline feature: if your app already sets a nonce (e.g. via laravel-security-headers, or Vite::useCspNonce()), every script the package emits now carries that nonce automatically. No config flag, no per-script opt-in.
Treat the package as the single source of truth for injected scripts. The most common anti-pattern is scattering raw <script> tags through Blade and using the package — you then lose the nonce handling for the hand-written ones. Funnel everything through the package's registration API and delete the inline tags.
Nonce-aware CSP (new in 1.1.0). Set the nonce once at the top of the request — Vite::useCspNonce($nonce) (or the csp_nonce() helper) — and emit the matching Content-Security-Policy header containing script-src 'nonce-…'. Every script the package renders picks it up. Drop 'unsafe-inline' from script-src and confirm the console is clean.
Registering scripts per context. Register global scripts in a service provider and request/section-specific ones from controllers or middleware. For conditional loading (e.g. only for authenticated users, only on certain routes), keep the registration behind a check rather than rendering and hiding client-side — it keeps the payload honest and avoids CSP surprises.
Composing with Blade stacks. If the package targets a stack (e.g. @push('scripts')), make sure that stack is actually rendered in your layout after the Vite tags. Otherwise scripts silently vanish — the single most common integration bug.
Testing. Assert the rendered tag carries the nonce:
$response->assertSee('nonce="'.$nonce.'"', false);
Run this against a route that actually emits a package script, not just @vite. For CSP regressions, a lightweight feature test that asserts the header and the tag nonce match is cheap and catches breakage when you upgrade either the package or laravel-security-headers.
Ordering. If a snippet depends on window helpers your bundle defines, ensure the package renders after @vite. Dependency ordering is usually explicit in the config/registration API — use it rather than relying on document order coincidence.
nonce attribute. The 1.1.0 behaviour is conditional. If you expected a nonce and see none, the nonce was never registered on the request, or your middleware that generates it runs after the response is rendered. Move the nonce generation earlier (typically a middleware that runs before Vite::useCspNonce).nonce-… in the response header against the nonce="…" attribute character by character; a middleware that rewrites the header after the fact will diverge from the rendered tags.'unsafe-inline' "temporarily". It masks the failure instead of fixing it, and you'll ship it. If something breaks, find the offending tag — it's almost certainly a hand-written <script> outside the package.type attributes. JSON-LD blocks (type="application/ld+json") are not executed, but strict CSP still applies in some browsers; the nonce is harmless there. Watch that any type or data-* attributes you pass through are escaped — the new nonce rendering path must not change how user-controlled attribute content is handled.<script> tags, module preloads), don't monkey-patch the renderer — wrap it or file the request upstream.script-src in the same PR so you actually capture the benefit.How can I help you explore Laravel packages today?