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

Fathom Api Laravel Package

beyondcode/fathom-api

A Laravel-friendly PHP client for the Fathom Analytics API. Query sites, page views, events, and other analytics data directly from your app, with a clean wrapper around Fathom's endpoints for dashboards and reporting.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. beyondcode/fathom-api is a thin fluent adapter over Fathom's v3 HTTP API, not a data layer. It contributes four capabilities — /sites, /aggregations, /events, /current_visitors — and returns untyped PHP arrays. That means it fits cleanly into one architectural role and only one: a read-only reporting edge for a Laravel app that has already committed to Fathom as its analytics backend. It fits poorly anywhere the application needs a domain model for analytics (sessions, funnels, retention, user journeys). The architecture decision this package actually implicates is not "do we adopt this library" but "do we standardize on Fathom," because the library is trivially replaceable and the backend is not.

Integration feasibility. Low effort, high ambiguity. Installation is composer require beyondcode/fathom-api:^1.1, a published config, and one env token; Laravel auto-discovery registers the provider and Fathom facade. A first successful Fathom::sites() call is achievable in well under a day, and a dashboard widget is a day or two more. The ambiguity is in what you're integrating against: 1.1.0 is the only release that speaks v3, and there is no documentation stating whether v3 coexists with the v2 path behind config or replaces it. Budget an explicit spike — not a feature sprint — to answer that empirically against a live token before committing scope.

Technical risk. Five risks, ranked by what they would cost us:

  1. Adoption vacuum. Zero stars, zero dependents, 0.3 package score. One release is a maintenance signal, not a cadence or a track record. Mitigation is cheap and non-negotiable: pin "1.1.0" exactly, and keep the facade behind our own AnalyticsReport interface so replacement is a single container binding.
  2. Schema drift with no error surface. Every response is an untyped array. If Fathom changes a response shape, widgets render null and nothing raises. This is the risk most likely to reach a stakeholder before it reaches engineering — a client report showing zero traffic. Mitigation: DTO mapping at the boundary plus a validation assertion that logs a warning on missing keys.
  3. Endpoint coverage is partial by design. No event ingestion, no site management, no funnels or cohorts. Every stakeholder expectation about "product analytics" must be closed out in the spec, not discovered in a demo.
  4. Rate limits and latency. The Fathom API is comparatively slow and throttled; a live-on-render dashboard will degrade under real admin usage.
  5. Unverified rate-limit and error semantics for v3. Limits and response envelopes "may have moved from v2," per the assessment notes. Unknown, so treat as unknown.

Key questions to resolve before approval.

  • Is 1.1.0 additive or breaking versus v2, and did the config schema change? (Answer determines whether this is a dependency bump or a migration project.)
  • Do we already run Fathom, and at which version? If no existing Fathom account, this package is the second decision; the first is the vendor contract.
  • Which specific numbers do we commit to displaying, to whom, and at what freshness? Nightly snapshot vs 5-minute cache vs live is a product decision with a latency and throttle consequence, and it must be made at spec time.
  • Are we comfortable that a 0-dependent package with one release is on the critical path for any externally visible report? (Recommended answer: no — internal-only until we fork or vendor it.)
  • Who owns the escape hatch? If the answer is "nobody," we haven't scoped the risk, we've deferred it.

Integration Approach

Stack fit. Native fit for Laravel 8+ with package discovery; Lumen requires manual provider and alias registration in bootstrap/app.php, and a missed registration fails as an opaque null-reference rather than a useful exception — call that out for any Lumen service in the estate. The package sits on Laravel's HTTP client, which means timeout, retry, and Http::fake() all work through the framework's existing mechanisms and our existing observability. No new infrastructure, no queue worker, no migration — unless we adopt the snapshot table, which we should.

Migration path. Assume the package is the easy part and Fathom is the hard part. Three entry scenarios:

  • No Fathom today. The real path is: Fathom account and site provisioning → token issuance → site ID capture → this package → our adapter → widgets. The package is roughly 10% of that sequence.
  • Fathom at v2. The v3 upgrade is its own scoped change with regression tests, deployed separately from any feature work. Do not bundle an API-version upgrade with a new dashboard in one PR; when numbers look wrong you will not know which change caused it.
  • Replacement of an existing tracking stack. Out of scope for this evaluation, but note that Fathom's value proposition (privacy-first, cookieless) is a roadmap input to the compliance workstream, not just an engineering swap.

Compatibility. Two hard constraints. First, v2→v3 surface change is unconfirmed — verify returned array keys against a live v3 response before trusting any of them, and treat the published base_url/version config key as the highest-risk value in the file. Second, config:cache is the dominant failure mode: a stale cached token or base URL keeps hitting the old endpoint, and the exception message contains nothing that identifies the cause. Any runbook for this integration must lead with config:clear / config:cache.

Sequencing. Recommended four-stage rollout, each stage independently valuable and independently abandonable:

  1. Spike (1–3 days, time-boxed). Token, config, Fathom::sites() against a real site. Produce a one-page answer to the v2/v3 ambiguity and a sample of every response shape we intend to use. Decision gate: proceed or stop.
  2. Adapter layer (small). AnalyticsReport interface with a Fathom-backed implementation, site ID resolved once into config or DB — never a firstWhere('name', ...) lookup on a request path, which fails silently on rename and throws on absence. Bind per-environment so local, staging, and production point at distinct sites with no code change.
  3. Snapshot job. Nightly SnapshotFathomDaily per site into an analytics_daily table, withoutOverlapping(). This is the load-bearing stage: it converts an unreliable live API into a dependable internal data source, gives us history beyond Fathom's retention, enables backfill and repair without touching the vendor, and is the precondition for any external-facing report.
  4. Presentation. Widgets and client reports read the local table only. Keep them dumb — widgets that own their own fetch cannot be tested without faking HTTP, and they re-implement caching unevenly.

Only after stage 3 should we expose numbers to anyone outside the internal team. Anything shown to a client before the snapshot exists is being served by a live rate-limited call on a render path.

Operational Impact

Maintenance. Low code volume, disproportionate process overhead. Plan for: exact version pin; a watching brief on the repo and on Fathom's v3 changelog; and a quarterly dependency review line item with an explicit trigger — 12 months with no release plus a Fathom v4 announcement means fork or replace, not "hope." Keeping the vendor behind our AnalyticsReport interface reduces the replacement cost to a one-line binding, which is the single highest-return piece of discipline in this entire integration.

Support. Support load concentrates in two places. First, "the number is wrong" — which with untyped arrays and no vendor-side error signalling is genuinely hard to triage, and is why DTO validation with structured warnings is a support tool, not just a code-hygiene preference. Second, auth and config — the debugging order is fixed and should be written into the runbook verbatim: sites() first (auth + base URL), then a wide 90-day range (isolates date-argument bugs from endpoint bugs), then HTTP logging for endpoint paths, then config:cache if it works locally but not in production. Publishing that order saves more engineer-hours than any refactor.

Scaling. Scale is not the constraint; freshness is. Every additional widget, portal, or client site multiplies HTTP calls against a throttled vendor. The architectural answer is fixed: cache per-site, per-metric, per-range — not per-dashboard — so five widgets over the same pageview query cost one call, and dashboards read the local snapshot rather than the API. Explicit timeout, retry with backoff and jitter, and a circuit breaker in front of non-critical reporting paths. Multi-site and client-portal use is a config loop plus per-site fetch; it scales linearly in storage and near-zero in vendor calls if stage 3 is done properly.

Failure modes to design for, and the product response to each.

  • API outage or throttling → serve last cached value; never fail an admin page render because reporting is down.
  • Expired token → nightly Fathom::sites() health check raises it before a stakeholder does.
  • Response-schema drift → silent nulls; caught only by boundary validation, logged as structured warnings, alerted on error rate.
  • Site renamed or deleted → resolved once and stored, so this degrades to a stale-but-stable ID rather than a runtime exception.
  • Laravel upgrade incompatibility → the adapter contains the blast radius; the interface is the contract we test against.
  • Stale config cache → runbook, not code.

Ramp-up. Effectively zero for a Laravel developer — the public surface is two files, and a working integration is measurable in hours. The real ramp-up is organizational: stakeholders must internalize that this is traffic reporting, not product analytics, and that "today" on a dashboard means yesterday's full aggregate rather than the current partial day. Both are expectations problems rather than engineering problems, and both are cheaper to fix in the spec than in a steering meeting after launch. Timezone mismatch between the Fathom site and the application is the same class of issue — decide it explicitly, once, and document it next to the site ID.

Recommendation. Approve as a time-boxed spike with an explicit go/no-go, targeting internal dashboards only, with an exact version pin and the adapter seam in place before any widget code is written. Do not treat it as a strategic dependency, and do not put it on a client-facing surface until the nightly snapshot exists and has run clean for a full reporting cycle. The 0.3 package score and the 6.59 opportunity score are not in conflict — they describe a small, low-maturity wrapper around a genuinely useful need. Buy the wrapper, own the interface, and keep the exit cheap.

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource