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

Laravel Google Searchconsole Laravel Package

revolution/laravel-google-searchconsole

Laravel wrapper for the Google Search Console API. Query search analytics data, inspect sites and sitemaps, and manage properties from your app with a clean, expressive PHP interface built on Google's official client library.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package:

    composer require revolution/laravel-google-searchconsole
    

    Laravel's auto-discovery registers the service provider and the LaravelGoogleSearchConsole facade.

  2. Publish the config file (check the README for the exact tag name, typically google-searchconsole-config) and inspect config/google-searchconsole.php. The key setting is the path to your service-account JSON credentials.

  3. In Google Cloud Console:

    • Create a project, enable the Google Search Console API.
    • Create a service account and download its JSON key.
    • Put the JSON somewhere outside public/ (e.g. storage/app/google/service-account.json) and point the config/env at its absolute path.
  4. In Search Console, open the property → Settings → Users and permissions → Add user, and add the service account's client_email with at least Full or Restricted permission. This step is separate from GCP IAM and is the usual reason the first call fails.

  5. First use case — pull search analytics for a property:

    use Revolution\GoogleSearchConsole\Facades\LaravelGoogleSearchConsole as SearchConsole;
    
    $response = SearchConsole::setSite('https://example.com/')
        ->query([
            'startDate'  => now()->subDays(28)->toDateString(),
            'endDate'    => now()->subDays(2)->toDateString(),
            'dimensions' => ['query'],
            'rowLimit'   => 25,
        ]);
    
    foreach ($response->getRows() ?? [] as $row) {
        dump($row->getKeys(), $row->getClicks(), $row->getImpressions());
    }
    

Where to look first: the published config file, then the facade class (src/Facades/) and its resolved service class to confirm the exact method names (setSite, query, sites, sitemaps, etc.). The underlying return objects are Google\Service\SearchConsole\* classes from google/apiclient, so the Google PHP client docs and the Search Console API reference are the real API surface.

Implementation Patterns

Wrap the facade in your own service. Don't sprinkle the facade through controllers. Create App\Services\SearchConsoleService that injects the config, holds a default site, and returns typed DTOs/arrays. This isolates the third-party API and makes it swappable in tests.

Scheduled sync into your database. The most common production pattern: a daily job that pulls the last N days and upserts into a search_console_rows table keyed by (site, date, query, page, country, device). Later, dashboards read from your DB instead of hitting the API. Keep the sync window overlapping (e.g. re-pull 7 days) because Google backfills data.

// app/Console/Commands/SyncSearchConsole.php
foreach (config('searchconsole.sites') as $site) {
    SearchConsole::setSite($site)->query([
        'startDate'  => now()->subDays(10)->toDateString(),
        'endDate'    => now()->subDays(2)->toDateString(),
        'dimensions' => ['date','query','page','country','device'],
        'rowLimit'   => 25000,
        'startRow'   => 0,
    ]);
}

Paginate manually. rowLimit caps at 25,000 per request. Loop with startRow until fewer than rowLimit rows come back. A page-level loop is usually cheaper than splitting by date.

Discover properties dynamically. Use the sites/sitemaps endpoints to enumerate verified properties once, then iterate. This avoids hardcoding sc-domain: vs https:// mismatches.

Cache aggressively for interactive pages. Analytics data is delayed anyway; a 15–60 minute cache (Cache::remember) on any dashboard request saves quota and latency. Prefer syncing to your DB for anything heavier.

Multiple credentials / multi-tenant. If you serve agencies, build one service instance per credential set. The config holds a single path by default, so construct the underlying Google client yourself for tenant-specific credentials rather than mutating global config at runtime.

Testing. Because the package resolves a google/apiclient service object, bind a mock or use an HTTP-level fake against www.googleapis.com. For unit tests, swapping the facade with SearchConsole::shouldReceive(...) is the fastest path.

Gotchas and Tips

  • Service account must be added in Search Console, not just GCP. A valid JSON key with the API enabled still returns 403 until the service account email is a user on the property. This is the #1 support question.
  • Site identifier must match exactly. https://example.com/ (trailing slash), https://www.example.com/, and sc-domain:example.com are three distinct properties. Store the canonical form in config; don't derive it from APP_URL.
  • Dates are in the property's timezone, and data is delayed ~2–3 days. Requesting endDate = today returns empty or partial data. Always end at now()->subDays(2).
  • startDate/endDate are strings (Y-m-d), not Carbon objects — cast with ->toDateString().
  • Dimensions are limited (typically max 3 per query) and some combinations are invalid. query + page together inflates rows fast; filter with dimensionFilterGroups instead of aggregating in PHP.
  • Absolute path for credentials. base_path('storage/...') works; a relative path silently fails inside queued workers with a different CWD. Set GOOGLE_SEARCHCONSOLE_CREDENTIALS env and reference it in config.
  • Quotas are per-project, not per-property. Inspect the API's daily/per-minute limits before scheduling a large multi-site crawl. Batch sites sequentially with a small sleep() between them.
  • Return shapes are Google client objects. Use getRows(), getKeys(), getClicks(), etc. — not arrays. The response can be null-ish for rows when no data exists; guard with ?? [].
  • Queue the syncs. API latency is high; never call the API synchronously in a web request path for large properties. Use a job and a last_synced_at column.
  • URL inspection endpoint has a tiny quota (roughly 2,000/day per property). Cache inspection results for days and never trigger them per pageview.
  • Extension point: the package is a thin wrapper around Google\Client. If a needed endpoint (e.g. newer Search Console features) isn't exposed, resolve the underlying Google client from the container and call the service directly — you don't need to fork the package.
  • Log the raw request on failure. Wrap calls in try/catch on Google\Service\Exception, log getErrors() and the site string; generic 500 errors from Google are almost always a mismatched site or missing permission.
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.
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
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager