google/analytics-data
Idiomatic PHP client for the Google Analytics Data API (GA4). Query reports, audience exports, and more via REST or gRPC. Install with Composer (google/analytics-data) and authenticate using Google Cloud credentials. Part of Google Cloud PHP (beta).
Installation:
composer require google/analytics-data
Ensure your project uses PHP 8.1+ (recommended) and has ext-grpc if using gRPC.
Authentication:
Use the Google Cloud PHP Auth Guide.
For Laravel, store credentials in .env (e.g., GOOGLE_APPLICATION_CREDENTIALS=path/to/service-account.json) or use the Laravel Google Auth package.
First Query:
use Google\Analytics\Data\V1beta\BetaAnalyticsDataClient;
use Google\Analytics\Data\V1beta\RunReportRequest;
$client = new BetaAnalyticsDataClient();
$request = (new RunReportRequest())
->setProperty('properties/YOUR_PROPERTY_ID')
->setDateRanges(['startDate:7daysAgo', 'endDate:today'])
->setDimensions(['country'])
->setMetrics(['activeUsers']);
$response = $client->runReport($request);
Key Files:
vendor/google/analytics-data/src/ for core classes.Basic Report:
$report = $client->runReport($request);
$rows = $report->getRows();
Pivot Reports:
$pivotRequest = (new RunPivotReportRequest())
->setProperty('properties/YOUR_PROPERTY_ID')
->setDimensions(['country', 'deviceCategory'])
->setMetrics(['sessions']);
$pivotReport = $client->runPivotReport($pivotRequest);
Async Reports (for large datasets):
$task = $client->createReportTask($request);
$report = $client->queryReportTask($task->getName());
$audienceLists = $client->listAudienceLists('properties/YOUR_PROPERTY_ID');
$export = $client->createAudienceExport([
'name' => 'properties/YOUR_PROPERTY_ID/audienceExports/EXPORT_ID',
'audienceId' => 'AUDIENCE_ID',
'destination' => ['bigqueryDestination' => ['datasetId' => 'DATASET']],
]);
$quota = $client->getPropertyQuotasSnapshot('properties/YOUR_PROPERTY_ID');
$remaining = $quota->getQuotaStatuses()[0]->getRemaining();
// app/Providers/AnalyticsServiceProvider.php
public function register()
{
$this->app->singleton(BetaAnalyticsDataClient::class, function ($app) {
return new BetaAnalyticsDataClient();
});
}
// app/Facades/Analytics.php
public static function runReport($request)
{
return app(BetaAnalyticsDataClient::class)->runReport($request);
}
Use Laravel’s cache to store frequent reports:
$cacheKey = 'analytics_report_' . md5($request->serializeToJsonString());
return Cache::remember($cacheKey, now()->addHours(1), function () use ($client, $request) {
return $client->runReport($request);
});
Wrap API calls in a try-catch:
try {
$response = $client->runReport($request);
} catch (Google\ApiCore\ApiException $e) {
Log::error('Analytics API Error: ' . $e->getMessage());
return response()->json(['error' => 'Failed to fetch analytics'], 500);
}
Authentication:
env() helper.https://www.googleapis.com/auth/analytics.readonly scope for read operations.Quota Limits:
sampling_metadatas in responses to avoid hitting limits.if ($response->getMetadata()->getSamplingMetadatas()[0]->getSampledQuota()) {
Log::warning('Report was sampled due to quota limits.');
}
Date Ranges:
startDate:2023-01-01, endDate:2023-01-31).7daysAgo) are supported but may behave unexpectedly in cached reports.Deprecations:
v1alpha surface is deprecated. Use v1beta for new projects.credentials in client options are deprecated. Use Application Default Credentials instead.gRPC vs REST:
ext-grpc. Fall back to REST if gRPC is unavailable:
$client = new BetaAnalyticsDataClient(['grpc' => false]);
Empty Filters:
EmptyFilter to match all rows when no filter is needed:
$request->setFilter('filter:emptyFilter');
Enable Debugging:
Set the GAX_DEBUG environment variable to log gRPC/REST traffic:
export GAX_DEBUG=debug
Or in Laravel’s .env:
GAX_DEBUG=debug
Validate Requests:
Use serializeToJsonString() to inspect request payloads:
Log::debug('Analytics Request:', ['payload' => $request->serializeToJsonString()]);
Common Errors:
INVALID_ARGUMENT: Validate property IDs, date ranges, and dimension/metric names against Google’s documentation.PERMISSION_DENIED: Ensure your service account has access to the Google Analytics property.Sampling:
If sampling_metadatas indicates sampling, consider:
samplingLevel: NO_SAMPLING (if quota allows):
$request->setSamplingLevel('NO_SAMPLING');
Batch Requests:
Combine multiple reports into a single API call where possible (e.g., using RunPivotReport for multi-dimensional data).
Async Reports:
For large datasets, use CreateReportTask and poll the result:
$task = $client->createReportTask($request);
while (true) {
$report = $client->queryReportTask($task->getName());
if ($report->getStatus() === 'COMPLETE') {
break;
}
sleep(5); // Poll every 5 seconds
}
Caching: Cache responses aggressively for static reports (e.g., daily metrics):
Cache::forever('analytics_daily_metrics', $response);
Custom Metrics/Dimensions:
Extend the Dimension and Metric classes to add project-specific fields:
class CustomDimension extends \Google\Analytics\Data\V1beta\Dimension {
public function __construct(string $name, string $value) {
parent::__construct();
$this->setName($name);
$this->setValue($value);
}
}
Middleware: Add request/response middleware for logging or transformation:
$client->addMiddleware(function ($request, $next) {
Log::info('Analytics Request:', ['method' => $request->getMethod()]);
return $next($request);
});
Laravel Events:
Dispatch events for analytics data (e.g., AnalyticsReportFetched):
event(new AnalyticsReportFetched($response));
How can I help you explore Laravel packages today?