Google Search Console - v1.0.0
Livewire Components
Three Livewire components are auto-registered when livewire/livewire ^3.6 is installed. All render server-side, so no bundler config is needed.
Requirements
livewire/livewire ^3.6installed and running.- The base
artisanpack-ui/googlepackage installed with the current user's Google account connected.
If Livewire isn't installed, GoogleSearchConsoleServiceProvider::registerLivewireComponents() returns without registering — the package still boots and the React / Vue surfaces still work.
performance-card
A four-tile summary (clicks, impressions, avg CTR, avg position) plus a daily-clicks trend chart, for a rolling range.
Basic usage
<livewire:google-search-console::performance-card />
With overrides
<livewire:google-search-console::performance-card
:days="90"
:site-url="'sc-domain:staging.example.com'"
/>
Public properties
| Property | Type | Default | Notes |
|---|---|---|---|
days |
int |
28 |
Clamped to 1 <= days <= DateRange::MAX_DAYS. |
siteUrl |
?string |
null |
Overrides config('google-search-console.reporting.site_url') for this instance. |
totals |
?array{clicks: float, impressions: float, ctr: float, position: float} |
null |
Populated after refresh(). null while never fetched. |
trend |
list<array{date: string, clicks: float, impressions: float, ctr: float, position: float}> |
[] |
One entry per day in the range. |
hasData |
bool |
false |
false when the API returned no rows (fresh property / last 2–3 finalising days). |
errorMessage |
?string |
null |
Human-readable error or null. |
baseInstalled |
bool |
true |
Flips to false if BaseInstalled::check() returns false. |
Actions
refresh()— re-fetches from Google. Called automatically on mount and every 60 seconds viawire:poll.60s.updatedDays()— Livewire lifecycle hook that re-fetches whendayschanges (used by the range dropdown in the default view).
View
google-search-console::livewire.performance-card. Publish with --tag=google-search-console-views to customize; Laravel's view resolver prefers the published copy over the package copy.
top-queries-table
Ranked table of the highest-performing search queries. Server fetches the rows once; client-side sort + pagination.
Basic usage
<livewire:google-search-console::top-queries-table />
With overrides
<livewire:google-search-console::top-queries-table
:days="90"
:limit="100"
:site-url="'https://staging.example.com/'"
/>
Public properties
| Property | Type | Default | Notes |
|---|---|---|---|
days |
int |
28 |
Clamped to 1..DateRange::MAX_DAYS. |
limit |
int |
TopQueriesFetcher::DEFAULT_LIMIT (50) |
Clamped to 1..1000. |
siteUrl |
?string |
null |
Overrides the configured site URL. |
sortBy |
string |
'clicks' |
One of query, clicks, impressions, ctr, position. |
sortDir |
string |
'desc' |
'asc' or 'desc'. |
perPage |
int |
10 |
Client-side paginate size. |
page |
int |
1 |
Clamped in nextPage() / previousPage(). |
rows |
list<array{query: string, clicks: float, impressions: float, ctr: float, position: float}> |
[] |
All rows the server returned. |
Actions
refresh()— re-fetch from Google. Auto-called on mount.sortByColumn(string $column)— flip sort direction if same column, else set new column with a sensible default direction (positionandquery→asc, everything else →desc).nextPage()/previousPage()— clamp to[1, ceil(count / perPage)].updatedDays()— re-fetch and reset to page 1 whendayschanges.
top-pages-table
Same shape as top-queries-table but keyed by page URL instead of query text.
Basic usage
<livewire:google-search-console::top-pages-table />
Public properties
Same as top-queries-table, but rows items have a page key instead of query, and sortBy accepts page, clicks, impressions, ctr, position.
Refresh from other code
Every component listens for its own refresh message and re-fetches when it's dispatched. From another Livewire component or Alpine:
<button wire:click="$dispatchTo('google-search-console::performance-card', 'refresh')">
Refresh performance card
</button>
Or from JS:
<script>
Livewire.dispatch('refresh'); // fires on every listening component
</script>
Customising the views
php artisan vendor:publish --tag=google-search-console-views
Copies resources/views/livewire/performance-card.blade.php, top-queries-table.blade.php, and top-pages-table.blade.php under resources/views/vendor/google-search-console/.
The default views use plain HTML with ap-gsc-* BEM classes — no Tailwind classes, no daisyUI dependency. Style them however you want.
Using ArtisanPack UI components inside
If you're already on livewire-ui-components, publish and rewrite the views with <x-artisanpack-*> components:
{{-- resources/views/vendor/google-search-console/livewire/performance-card.blade.php --}}
<x-artisanpack-card wire:poll.60s="refresh">
<x-slot:header>
{{ __( 'Search performance' ) }}
</x-slot:header>
@if ( ! $baseInstalled )
<x-artisanpack-alert type="warning">
{{ __( 'Install artisanpack-ui/google to enable Search Console reporting.' ) }}
</x-artisanpack-alert>
@elseif ( $errorMessage )
<x-artisanpack-alert type="error">{{ $errorMessage }}</x-artisanpack-alert>
@elseif ( ! $hasData )
<p>{{ __( 'No data for this range yet.' ) }}</p>
@else
{{-- render totals + trend --}}
@endif
</x-artisanpack-card>
Testing
use ArtisanPackUI\GoogleSearchConsole\Livewire\PerformanceCard;
use Livewire\Livewire;
use Illuminate\Support\Facades\Http;
Http::fakeSequence()
->push( [ 'rows' => [ [ 'keys' => [], 'clicks' => 42, 'impressions' => 500, 'ctr' => 0.084, 'position' => 3.2 ] ] ], 200 )
->push( [ 'rows' => [ [ 'keys' => [ '2026-01-01' ], 'clicks' => 42, 'impressions' => 500, 'ctr' => 0.084, 'position' => 3.2 ] ] ], 200 );
Livewire::test( PerformanceCard::class )
->assertSet( 'baseInstalled', true )
->assertSet( 'hasData', true )
->assertSet( 'totals.clicks', 42.0 )
->assertSee( 'Search performance' );
Full test patterns in Testing.
The classes
ArtisanPackUI\GoogleSearchConsole\Livewire\PerformanceCardArtisanPackUI\GoogleSearchConsole\Livewire\TopQueriesTableArtisanPackUI\GoogleSearchConsole\Livewire\TopPagesTable
Every rule about what to show lives on the DTO layer (PerformanceOverviewData, TopQueriesData, TopPagesData) so the Livewire, React, and Vue surfaces cannot drift. See API Reference/Livewire Components for method signatures.