Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Fathom Laravel Package

jeffersongoncalves/laravel-fathom

A Laravel package for integrating Fathom Analytics into your application. Configure your Fathom site ID, inject the privacy-friendly tracking script, and start collecting lightweight, cookie-free analytics with minimal setup. Ideal for developers who want simple, privacy-focused website stats withou...

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin integration layer: it publishes a config file and registers a Blade-level way to emit Fathom's script.js tag. Treat it as a script-tag helper, not a full analytics SDK.

  1. Install it:
    composer require jeffersongoncalves/laravel-fathom
    
  2. Publish the config (check the service provider for the exact tag; it is typically fathom-config):
    php artisan vendor:publish --tag="fathom-config"
    
  3. Add your Fathom site ID to .env:
    FATHOM_SITE_ID=ABCDEFGH
    
  4. Open config/fathom.php and confirm the key names, enabled flag, and any script URL/domain option. Because the package is small, reading the service provider and config file is faster than guessing at the README.
  5. Include the package's Blade directive or component in your main layout, usually inside <head>:
    <x-fathom::script />
    {{-- or, depending on the version: @fathom --}}
    
  6. Load any page, view source, and confirm a cdn.usefathom.com/script.js tag with your data-site value is present. That is the whole first use case: one layout change and you have pageview tracking.
  7. If your app sets a CSP nonce (Vite, laravel-security-headers, etc.), view source again and confirm nonce="..." is on the tag. As of 4.1.0 this happens automatically — if the attribute is missing, your nonce is being generated after the layout renders or under a different key, not a problem with the package.

Implementation Patterns

Put it in the one layout everyone uses. Add the directive to resources/views/layouts/app.blade.php (or your Inertia root template) rather than to individual pages. Fathom tracks pageviews automatically from the script tag, so a single inclusion covers normal navigation.

Drive it from environment config. Keep separate site IDs for production and staging, and disable tracking outside production:

FATHOM_SITE_ID=ABCDEFGH
FATHOM_ENABLED=true
@if (config('fathom.enabled'))
    <x-fathom::script />
@endif

This prevents local development, CI browser tests, and staging traffic from polluting production numbers.

Nonce-based CSP (4.1.0+). If you have moved off 'unsafe-inline', you no longer need to hand-roll the tag. Generate the nonce the Laravel way and the package will stamp it onto the script it renders:

// AppServiceProvider::boot()
Vite::useCspNonce();
// or, with a headers package
// middleware sets the CSP header + nonce, Laravel exposes it via csp_nonce()
<x-fathom::script />   {{-- renders <script src="..." nonce="{{ csp_nonce() }}"> --}}

Your header can then stay strict:

script-src 'self' 'nonce-{...}' https://cdn.usefathom.com;
connect-src 'self' https://api.usefathom.com;

The key ordering point: the nonce must exist before the layout renders. If you set it in a middleware, register that middleware globally or in the web group — a nonce generated in a controller or after the response is built will not reach the tag.

Guard against tracking internal pages. If you have admin panels or authenticated app routes, either skip the script there or gate it:

@guest
    <x-fathom::script />
@endguest

Alternatively, wrap the package component in your own Blade component so the policy lives in one place.

Track conversions with Fathom events. The package only injects the script; goal tracking is plain Fathom JavaScript. Call it from your own small helper or Alpine component:

window.fathom?.trackEvent('signup_completed');
window.fathom?.trackEvent('checkout', { value: 49, currency: 'USD' });

Trigger these on form success, subscription changes, or checkout completion. Keep event names stable and low-cardinality so reports remain useful.

SPA and Inertia. Include the script once in the root HTML. For client-side route changes, call window.fathom?.trackPageview() from your router's afterEach hook (or Inertia's router.on('navigate')). Do not add the script again on each navigation.

Consent banners. If you need consent before analytics, do not render the component until consent is granted. Since it is just Blade, a session/cookie check around the include is enough — and the nonce still applies once you do render it, so no extra CSP work is needed on the deferred path.

Testing. In your test environment, set FATHOM_ENABLED=false and assert the tag is absent. For the enabled case, assert the rendered HTML contains your site ID rather than making network assertions. If you set a nonce in tests (e.g. Vite::useCspNonce('test-nonce')), you can assert the attribute too — useful for catching a regression where the nonce stops being propagated.

Gotchas and Tips

  • CSP nonce only covers what the package renders. 4.1.0 attaches Laravel's Vite CSP nonce to the package's <script> tags. Your own inline snippets (the trackEvent calls, any bootstrap shim) are not covered — inline JS still needs a nonce/'unsafe-inline'/'unsafe-hashes of its own. Move such code into a nonce'd partial or an external file rather than assuming 4.1.0 solved inline CSP for you.
  • Nonce ordering. The nonce is read at render time. If you generate it in middleware that runs after the view is composed, or in a controller that returns a view already rendered, the tag will render without it (or with an empty attribute) and the browser will block it. Generate it early — Vite::useCspNonce() in a service provider or an early global middleware.
  • Config caching. After changing FATHOM_SITE_ID or the enabled flag, run php artisan config:clear. A stale cached config is the most common reason the script "disappears".
  • Empty site ID. If the env var is missing, the package may emit a script tag with an empty data-site, or omit it entirely depending on the version. Verify the rendered source after every deploy.
  • Other CSP directives. Even with the nonce correct, script-src must still allow https://cdn.usefathom.com (a nonce does not whitelist an external origin by itself), and connect-src must allow Fathom's endpoint. 'strict-dynamic' in script-src is fine and is the usual companion to nonces, but it means host allowlists are ignored in CSP3 browsers — rely on the nonce, not the host list.
  • Ad blockers. Fathom is frequently blocked. Expect undercounting in browser-heavy audiences; Fathom's custom-domain option improves this, and the package's config may expose the script URL for that case. If you switch to a custom domain, remember to update both script-src and connect-src.
  • Double counting. Do not combine automatic pageview tracking with a manual trackPageview() on every page load. Pick one model: automatic for server-rendered apps, manual for SPAs.
  • Livewire and Turbo. Partial page swaps do not re-execute the head script, which is usually correct, but full-page Turbo visits may need an explicit trackPageview() call. Nonce'd scripts are re-evaluated on full navigation, so make sure the nonce is fresh per response, not cached with the layout HTML.
  • Private data in URLs. Fathom records paths. Avoid putting emails, tokens, or customer identifiers in query strings on tracked pages.
  • Site ID is public. It appears in the HTML by design; do not treat it as a secret or try to hide it server-side. The nonce, by contrast, is per-response and must not be cached in a full-page/CDN cache without care.
  • Thin package, thin API. There is no facade or query API here—this package only renders the tag. For dashboards or server-side reporting, use Fathom's own API separately.
  • Extension point. If the included component does not fit (custom attributes, consent logic, domain), publish/override the Blade view or wrap the component in your own. When overriding the view, remember to keep whatever nonce call the shipped view uses — dropping it silently reintroduces CSP breakage on your next audit.
  • View cache. After editing layouts, run php artisan view:clear if changes do not appear in production, especially with precompiled Blade views. This also applies after upgrading to 4.1.0 if the nonce attribute does not show up.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib