jeffersongoncalves/laravel-metrics-posthog
A Laravel package that integrates PostHog metrics, letting you capture and send product analytics events from your app with minimal setup. Useful for tracking user behavior and wiring PostHog into Laravel's metrics tooling.
Install the package with Composer, then configure the PostHog personal API key, project ID, and host. Because settings are backed by spatie/laravel-settings, expect to publish/run the package’s settings migration and seed/update the settings record from env.
POSTHOG_PERSONAL_API_KEY=phx_...
POSTHOG_PROJECT_ID=12345
POSTHOG_HOST=https://us.posthog.com
# EU: https://eu.posthog.com
# Self-hosted: https://posthog.example.com
First checks:
POSTHOG_PROJECT_ID is the numeric project ID, not the project API key.realtimeVisitors.PostHog facade methods; use the PostHog HogQL/query docs when building raw queries.First practical use case: a small internal analytics page showing pageviews over time, top pages, referrers, and current visitors. Use the canned facade methods first; drop to PostHog::query($hogql) only when the canned helpers do not cover the metric.
Wrap the facade in an application service. Keep PostHog calls out of controllers and Blade templates so you can cache, retry, mock, and normalize responses.
final class Analytics
{
public function pageviewsLast7Days(): array
{
return cache()->remember(
'analytics.pageviews.7d',
now()->addMinutes(10),
fn () => PostHog::aggregate('$pageview', now()->subDays(7), now()),
);
}
public function realtime(): int
{
return cache()->remember(
'analytics.realtime',
now()->addSeconds(15),
fn () => PostHog::realtimeVisitors(),
);
}
}
Use canned helpers for dashboards and tables. A typical dashboard maps cleanly to the facade:
timeseries for charts over time.breakdown for property-level comparisons.pages, sources, countries, browsers, devices for table widgets.aggregate for single-number cards.realtimeVisitors for a live badge or status indicator.query for custom HogQL metrics, cohorts, or dimensions not covered by helpers.Cache aggressively and warm on schedule. Analytics queries are remote API calls and are rate-limited. Cache dashboard reads for 5–15 minutes and realtime for 10–30 seconds. A scheduled command can refresh common widgets so user requests never wait on PostHog.
Schedule::command('analytics:warm')->everyFiveMinutes();
Expose analytics through your own JSON endpoints. For Livewire, Inertia, or Vue/React dashboards, return normalized arrays/DTOs from your service. Never call the facade from frontend code, and never expose the personal API key.
Handle exceptions at the boundary. Let AuthenticationException surface as a configuration problem, back off on RateLimitException, and catch PostHogException to return stale cached data or a degraded widget rather than breaking the page.
try {
return $this->analytics->pageviewsLast7Days();
} catch (RateLimitException $e) {
return cache()->get('analytics.pageviews.7d', []);
} catch (PostHogException $e) {
report($e);
return [];
}
Use raw HogQL for custom product metrics. For example, group by a custom event property, filter by host/path, or build a metric the canned helpers do not expose. Keep raw queries in one class, version them, and test them against a staging PostHog project.
Separate environments. Use distinct PostHog projects or at least distinct settings records per environment. Do not let local/staging dashboards query production analytics unless that is deliberate.
posthog-js or a backend capture integration to send pageviews/events.spatie/laravel-settings, but it must never reach the browser. Scope the key as narrowly as PostHog allows.realtimeVisitors is approximate and laggy. Use it for presence/status, not billing, SLA, or exact reporting.query.Http::fake() can also isolate tests from the live API.How can I help you explore Laravel packages today?