spatie/laravel-analytics
Laravel package to retrieve Google Analytics data in your app. Provides simple methods to fetch visitors, page views, and most visited pages over a given period, returning results as Laravel Collections via an easy-to-use facade.
## Getting Started
### Minimal Setup
1. **Install the package**:
```bash
composer require spatie/laravel-analytics
php artisan vendor:publish --tag="analytics-config"
ANALYTICS_PROPERTY_ID in .env.service-account-credentials.json in storage/app/analytics/ (or update the config path).use Spatie\Analytics\Facades\Analytics;
use Spatie\Analytics\Period;
// Fetch today's most visited pages
$pages = Analytics::fetchMostVisitedPages(Period::today());
// Fetch weekly visitors and pageviews
$data = Analytics::fetchVisitorsAndPageViews(Period::days(7));
Dashboard Integration
fetchVisitorsAndPageViews(Period::days(7)) to populate a weekly traffic chart.$data = Analytics::fetchTotalVisitorsAndPageViews(Period::months(6));
Custom Reports
get() method for ad-hoc queries:
$metrics = ['activeUsers', 'screenPageViews'];
$dimensions = ['country', 'deviceCategory'];
$results = Analytics::get(
Period::days(30),
$metrics,
$dimensions,
maxResults: 10
);
Event Tracking
$dimensionFilter = new FilterExpression([
'filter' => new Filter([
'field_name' => 'eventName',
'string_filter' => new StringFilter([
'match_type' => MatchType::EXACT,
'value' => 'form_submit',
]),
]),
]);
$events = Analytics::get(
Period::days(7),
['eventCount'],
['eventName'],
dimensionFilter: $dimensionFilter
);
Pagination
offset and maxResults for large datasets:
$firstPage = Analytics::get(Period::today(), ['pageViews'], [], maxResults: 50);
$secondPage = Analytics::get(Period::today(), ['pageViews'], [], maxResults: 50, offset: 50);
cache()->remember() to store results beyond the package’s default cache lifetime:
$data = cache()->remember("analytics_{$period->startDate->format('Y-m-d')}", now()->addHours(1), function () use ($period) {
return Analytics::fetchVisitorsAndPageViews($period);
});
try-catch for Google\ApiCore\ApiException:
try {
$data = Analytics::fetchTopCountries(Period::days(7));
} catch (ApiException $e) {
Log::error("Analytics API error: " . $e->getMessage());
return back()->with('error', 'Failed to fetch analytics data.');
}
Credential Security
service-account-credentials.json to version control. Add it to .gitignore:
storage/app/analytics/service-account-credentials.json
GA4 Property ID
ANALYTICS_PROPERTY_ID matches the GA4 property ID (not Universal Analytics). Format: properties/12345678.Cache Invalidation
php artisan cache:clear
config/analytics.php for real-time data:
'cache_lifetime_in_minutes' => 0,
Dimension/Metric Limits
get() method for complex queries.Time Zone Handling
config/app.php). Convert to UTC if needed:
use Carbon\Carbon;
$period = Period::create(
Carbon::now()->timezone('UTC')->startOfDay(),
Carbon::now()->timezone('UTC')->endOfDay()
);
Enable API Logging
Add to config/analytics.php:
'debug' => env('ANALYTICS_DEBUG', false),
Logs will appear in storage/logs/laravel.log.
Validate Queries Use the Google Analytics Data API Query Explorer to test queries before implementing them in Laravel.
Common Errors
Invalid credentials: Verify the service account email has "Analyst" access in GA4.Property not found: Double-check the ANALYTICS_PROPERTY_ID format.Quota exceeded: Reduce query frequency or upgrade your Google Cloud plan.Custom Periods
Extend the Period class for reusable time ranges:
namespace App\Extensions;
use Spatie\Analytics\Period;
use Carbon\Carbon;
class CustomPeriod extends Period
{
public static function lastBusinessWeek(): self
{
$start = Carbon::now()->startOfWeek()->subDays(Carbon::now()->dayOfWeek - 1);
$end = Carbon::now()->endOfWeek();
return new self($start, $end);
}
}
Decorate the Facade
Add helper methods to the Analytics facade:
// app/Providers/AppServiceProvider.php
use Spatie\Analytics\Facades\Analytics;
public function boot()
{
Analytics::macro('topPagesByTraffic', function ($period, $limit = 5) {
return $this->fetchMostVisitedPages($period)->sortByDesc('screenPageViews')->take($limit);
});
}
Usage:
$topPages = Analytics::topPagesByTraffic(Period::days(30));
Event Listeners Trigger actions on analytics data changes (e.g., send Slack alerts for traffic spikes):
// app/Listeners/AnalyticsAlertListener.php
use Spatie\Analytics\Facades\Analytics;
use Spatie\Analytics\Period;
class AnalyticsAlertListener
{
public function handle()
{
$data = Analytics::fetchVisitorsAndPageViews(Period::today());
$today = $data->first();
$yesterday = Analytics::fetchVisitorsAndPageViews(Period::yesterday())->first();
if ($today['activeUsers'] > $yesterday['activeUsers'] * 1.5) {
// Send alert
}
}
}
Testing
fake() method to mock responses in tests:
Analytics::fake([
['pageTitle' => 'Home', 'screenPageViews' => 1000],
['pageTitle' => 'About', 'screenPageViews' => 500],
]);
Analytics::shouldReceive('fetchMostVisitedPages')
->once()
->andReturn(collect([...]));
---
How can I help you explore Laravel packages today?