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

Google Analytics Bundle Laravel Package

ottsch/google-analytics-bundle

A Symfony bundle for integrating Google Analytics into your application. It provides configuration and Twig integration for adding the tracking code, helping you connect your Symfony project to Google Analytics with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a fork of widop/google-analytics-bundle — a Symfony 2 era bundle that wires the Google Analytics Data Export API into a Symfony service using certificate-based (service account) authentication. Before you write a line of integration code, confirm two things: that the package installs at all on your PHP/Symfony version, and that Google Analytics still has data for the endpoint it targets (it uses the Universal Analytics ga: prefix; UA properties stopped processing hits in July 2023, so verify your property is still readable).

1. Install and register (Symfony 2.x style)

composer require ottsch/google-analytics-bundle
// app/AppKernel.php
public function registerBundles()
{
    $bundles = [
        // ...
        new Widop\Bundle\GoogleAnalyticsBundle\WidopGoogleAnalyticsBundle(),
    ];
}

There is no Flex recipe and no autoconfiguration — this is manual AppKernel registration only.

2. Create the credentials

  • In Google Cloud Console, create a service account, enable the Analytics API.
  • Download the P12 certificate (the bundle's certificate auth path) — not the JSON key.
  • In Google Analytics Admin → Property/View → User Management, add the service account email (e.g. [email protected]) with Read & Analyze.
  • Note the view ID (the ga:XXXXXXXX number) from Admin → View Settings.

3. Configure

# app/config/config.yml
widop_google_analytics:
    client_id:       "[email protected]"
    private_key_path: "%kernel.root_dir%/../app/keys/analytics.p12"
    account_name:    "[email protected]"

The exact keys live in the bundle's DependencyInjection/Configuration.php — read that file first; forks rename things. The certificate passphrase is virtually always notasecret.

4. First use case

The quickest smoke test is a console command that pulls sessions for the last 7 days:

$analytics = $this->get('widop_google_analytics');
$rows = $analytics->query(
    'ga:12345678',            // view ID
    'ga:sessions,ga:users',   // metrics
    'ga:date',                // dimensions
    ['max-results' => 7]
);

If this returns rows, everything else is just shaping. If it 401s, the problem is almost always the GA user permission, not the config.

Implementation Patterns

Wrap the bundle service — don't call it from controllers. The service name widop_google_analytics is a Symfony 2 convention and will not survive a framework upgrade. Put it behind your own interface:

interface AnalyticsReportInterface
{
    public function sessionsByDate(\DateTime $from, \DateTime $to): array;
}

final class WidopAnalyticsReport implements AnalyticsReportInterface
{
    public function __construct(private object $analytics) {}

    public function sessionsByDate(\DateTime $from, \DateTime $to): array
    {
        return $this->analytics->query(
            $this->viewId,
            'ga:sessions',
            'ga:date',
            [
                'start-date' => $from->format('Y-m-d'),
                'end-date'   => $to->format('Y-m-d'),
            ]
        );
    }
}

This single indirection makes the eventual migration to the modern google/analytics-data client a one-file change.

Prefer scheduled jobs over request-time calls. GA API calls are slow and rate-limited. A daily app:analytics:import console command writing into your own table, with the web app reading local data, is the pattern that actually holds up:

// AppBundle/Command/ImportAnalyticsCommand.php
protected function configure() { $this->setName('app:analytics:import'); }
protected function execute(InputInterface $in, OutputInterface $out)
{
    $rows = $this->getContainer()->get('app.analytics_report')
        ->sessionsByDate(new \DateTime('-1 day'), new \DateTime('-1 day'));
    // persist to DB
}

Use max-results and start-index to page. The bundle exposes them as query options; the API caps single responses (historically 10,000 rows). Loop until a short page comes back.

Discover view IDs programmatically rather than hardcoding — the bundle's client exposes the management/profile listing, so a small app:analytics:profiles command saves a lot of copy-pasting during setup.

Batch with dimensions. Every query() call is a quota hit. If you need device + country + channel breakdowns, ask for them in one query with multiple dimensions and aggregate in PHP rather than issuing three queries.

Multi-property setups compose naturally with the wrapper above: construct one report object per view ID and fan out in the import job.

Gotchas and Tips

Symfony 2 only. This predates Symfony 3's deprecations and Symfony 4's service container rewrite. On Symfony 4+ it will not boot — AppKernel::registerBundles, $this->get() from controllers, and the %kernel.root_dir% parameter are all gone. Treat it as a Symfony 2.x dependency only; if you're on anything newer, this is a learning reference, not a dependency.

Certificate auth is the legacy path. Modern Google client libraries default to JSON service-account keys + OAuth2 JWT flow. The P12 flow still technically works, but it's deprecated, undocumented in current Google guides, and the underlying google/apiclient version bundled here is from the same era. Expect Composer conflicts if your project already depends on a modern google/apiclient — you'll likely need to isolate it in its own process or vendor it.

The notasecret passphrase. Google's generated P12 files use the literal password notasecret. If the bundle's config exposes a passphrase key, set it; if not, the default in the client handles it. A wrong passphrase surfaces as an OpenSSL error, not an auth error — easy to misdiagnose.

401 vs. 403. A 401 means the credentials are wrong (bad key path, bad client ID). A 403 means the credentials are fine but the service account lacks permission on the view — add the service account email in GA's User Management, and check you're on the right view, not the property. This split will save you an afternoon.

UA sunset. The Universal Analytics Reporting API is read-only for historical data at best. This bundle does not speak GA4. If your property is GA4-only, no certificate will make it work — the data path is different (analyticsdata.googleapis.com, dimension/metric names without the ga: prefix).

Quota. Per-project daily quota and concurrent-request caps apply. A tight cron that re-queries the same window every minute will burn through it. Cache aggressively.

Dates are property-timezone, not UTC. start-date/end-date are interpreted in the view's timezone. Off-by-one-day bugs around midnight are common — format with the view's timezone, not the server's.

Debugging. Log the raw exception message from the Google client; it usually names the exact failure (invalid_grant, invalid_client). The bundle itself adds little logging, so wrap query() in a try/catch that logs request parameters alongside the exception.

Extension point. The cleanest escape hatch is the underlying client object the bundle exposes via the container — grab it and call the Google client directly for any query the bundle's convenience methods don't cover, rather than fighting the wrapper.

Reality check on maintenance. Zero stars, zero dependents, last release January 2019. There is no community to ask, no security response, and issues will go unanswered. Pin it in composer.json with an explicit version, and treat replacement as a planned task rather than a possibility.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource