Skip to content

[Feature]: Build a polished Google Search Performance workspace #261

Description

@PascaleBeier

Summary

Turn HitKeep's existing Google Search Console settings page and dashboard drilldown into one polished, site-scoped Search Performance workspace for SEO, content, and growth work.

The workspace should combine accurate imported Google Search metrics, previous-period comparisons, Search Appearance reporting, and page-level HitKeep outcomes, while making connection setup, property mapping, sync health, and recovery much clearer.

Problem

The current Search Console surface is useful but fragmented:

  • Connection and property mapping live in a settings-oriented integration page, while reporting is tucked into an oversized dashboard drilldown.
  • The report is shallow: fixed-size results, limited comparison and filtering, no Search Appearance view, and no page-level outcome context from HitKeep.
  • Headline totals and dimension rows are derived from combined query shapes, which makes aggregation semantics harder to understand and can reduce accuracy.
  • Loading and failure behavior is too coarse. A failed request can obscure otherwise usable data, and sync problems do not always lead users to a clear recovery action.
  • Healthy connection states still expose setup-oriented or disabled controls, adding noise.
  • The current surface does not scale well for a serious search-performance workflow.

Who Benefits

  • Site owners diagnosing organic-search performance
  • SEO and content teams prioritizing queries and landing pages
  • Growth teams connecting search visibility to on-site outcomes
  • Operators troubleshooting OAuth, property access, mapping, and imports
  • Self-hosted and HitKeep Cloud users equally

Proposed Solution

1. Create a dedicated Search Performance workspace

Add a site-scoped /search-console route under Analytics for every authenticated site viewer.

Use two query-parameter tabs:

  • ?tab=performance — default reporting workspace
  • ?tab=connection — OAuth, property mapping, sync health, retry, and destructive actions

Remove the duplicate Integration navigation item. Redirect the old /integration/google-search-console route to /search-console?tab=connection, and return OAuth callbacks there.

The Performance tab should include:

  • The shared date-range toolbar
  • An equal-length previous-period comparison
  • Four selectable KPI metrics: clicks, impressions, CTR, and average position
  • One restrained trend chart
  • Server-paginated tables for Queries, Pages, Countries, Devices, and Search Appearance
  • Default sorting by clicks descending
  • Page sizes of 25, 50, and 100
  • Reversible query/page contains filters and exact country/device filters
  • A compact KPI/trend summary on the main dashboard with an Open Search Console action, replacing the current large drilldown

Search Appearance should be a date-range/comparison table only. It should not be combined with the other dimension filters because the Search Analytics API's aggregation behavior can otherwise produce misleading totals.

2. Add page-level HitKeep outcome context

For each Search Console page row, show same-period HitKeep context derived from the normalized landing-page path:

  • Tracked landing sessions
  • Bounce rate
  • Goal conversions
  • Previous-period comparison for the same measures

Clearly label this as outcomes for all HitKeep-tracked traffic landing on that page. Do not present it as Google-attributed traffic or imply causality.

3. Deepen and harden the imported data model

Version search_console_facts with a dataset discriminator and search_appearance support.

Import finalized Web Search data into seven datasets:

  1. Property totals
  2. Queries
  3. Pages
  4. Countries
  5. Devices
  6. Search Appearance
  7. Existing combined dimensions used for cross-filtering

Use:

  • Property totals for accurate headline metrics
  • Dimension-specific datasets for unfiltered tables
  • Combined dimensions only when query, page, country, or device filters require them

During a 90-day v2 backfill:

  • Preserve legacy facts until the replacement dataset succeeds
  • Switch reporting atomically to the new model
  • Remove legacy rows for the mapped site/property only after successful cutover
  • Transactionally replace each rolling date window so rows that disappeared upstream do not remain stale
  • Retain the last good dataset when refresh fails
  • Store only a safe, actionable error category

After a property is mapped, request the initial sync automatically. While the page is visible, poll sync status every five seconds and stop when the state is stable or after two minutes.

Include Search Console facts in site/user takeout as search_console_fact. Never export OAuth tokens, credentials, provider headers, or raw provider error bodies.

4. Make connection and recovery states clear

The Connection tab should show a compact status summary and one contextual primary action. Avoid healthy-but-disabled setup controls. Separate destructive actions visually and explain their scope.

Load status, overview, chart, and active table independently so one failed section does not blank the rest of the workspace.

Support localized, actionable states for:

  • No site selected
  • Missing server credentials
  • Disconnected account
  • Unmapped property
  • No compatible property
  • Initial import
  • Empty result
  • Partial date range
  • Quota exhaustion
  • Google service outage
  • Revoked authorization
  • Token refresh failure
  • Property access loss
  • Permission denial
  • Generic safe failure

Use skeletons for first load and retain visible data during refresh. Keep last-good reporting available during failed or attention-required syncs, with the relevant recovery action.

Hide mutation controls from read-only users instead of showing disabled controls.

A valid OAuth callback should redirect with a safe success/error code. Invalid or mismatched state should remain an HTTP error and must not expose provider response bodies.

Disconnect copy must explain that every team site mapped through that connection will stop syncing while previously imported data remains. Removing a mapping affects only the current site.

5. Extend the public reporting surface additively

Keep existing routes and response fields backward compatible while adding:

  • Paired compare_from / compare_to
  • query_contains
  • page_contains
  • offset
  • sort
  • direction
  • dimension=search_appearance
  • Comparison metrics on overview, series, and dimension rows
  • total, limit, offset, and has_more on dimension responses
  • Optional current/comparison hitkeep_context on page rows
  • Stable warning codes for partial ranges, legacy backfill, sync failure/attention, and anonymized-query limitations
  • Import-model version in sync status

Extend the read-only aggregate MCP tool hitkeep_get_search_console with Search Appearance reporting. Update MCP audit expectations and public analytics procedures.

Update both the runtime OpenAPI source and the docs OpenAPI copy.

User Workflow

  1. A site viewer opens Analytics → Search Console.
  2. If setup is incomplete, the workspace explains the exact state and presents the next valid action.
  3. After property mapping, HitKeep starts the initial import automatically and updates visible status until it settles.
  4. The viewer compares clicks, impressions, CTR, and position across periods, then explores paginated query, page, country, device, or Search Appearance results.
  5. On the Pages tab, the viewer can relate search visibility to clearly labeled, non-attributed HitKeep landing outcomes.
  6. If Google sync later needs attention, the last good report remains available and the Connection tab provides a safe recovery path.

Success Criteria

  • A dedicated responsive Search Console workspace replaces the fragmented settings/drilldown experience.
  • Performance and Connection tabs are deep-linkable and the legacy integration route redirects safely.
  • Headline totals use property-level imports rather than sums from combined dimensions.
  • Queries, Pages, Countries, Devices, and Search Appearance support server pagination and comparison.
  • Query/page contains filters and exact country/device filters are reversible and URL-safe.
  • Search Appearance is reported without unsafe cross-dimension aggregation.
  • Page rows show clearly disclaimed HitKeep landing sessions, bounce rate, and goal conversions for current and comparison periods.
  • Initial sync starts automatically after mapping.
  • Legacy data remains readable until a successful atomic v2 cutover.
  • Rolling-window replacement removes stale upstream rows without exposing partial imports.
  • Section-level failures preserve unaffected and last-good data.
  • Every known setup, empty, partial, quota, authorization, access, and outage state has localized copy and a relevant action.
  • Read-only users can view reports without seeing mutation controls.
  • Disconnect and unmap actions clearly communicate their different scopes.
  • API additions are backward compatible and documented in both OpenAPI sources.
  • The read-only Search Console MCP tool supports Search Appearance and remains aggregate-only.
  • Takeout includes imported facts but never credentials or unsafe provider data.
  • Desktop/mobile, light/dark, long-locale, keyboard, focus, screen-reader, and reduced-motion behavior are verified.
  • All supported dashboard locales are updated.
  • Change-aware QA passes during implementation and the PR-parity profile passes before review.

Alternatives Considered

  • Polish the current cards only: lower effort, but it leaves reporting fragmented and does not solve data accuracy, pagination, comparison, or recovery limitations.
  • Build a complete Google Search hub now: URL Inspection, sitemaps, and every Google search type would make this issue too broad and introduce substantially different API, quota, storage, and UX concerns.
  • Import all search types immediately: image, video, news, Discover, hourly, and preliminary data are better handled as later extensions after the finalized Web Search model is reliable.

Constraints

  • Keep the integration read-only.
  • Preserve self-hosted and HitKeep Cloud parity.
  • Continue using the current read-only OAuth scope and finalized Web Search data.
  • Keep HitKeep as one deployable application with DuckDB and no new required services.
  • Preserve site-scoped permissions across REST, dashboard, export, and MCP surfaces.
  • Do not store or expose raw prompts, credentials, tokens, provider headers, or unrestricted provider error bodies.
  • Follow Google Search Analytics aggregation and anonymized-query caveats:

Explicitly out of scope for this issue:

  • URL Inspection
  • Sitemap management
  • Image, video, news, and Discover search types
  • Hourly or preliminary data
  • Public/shared Search Console reports

Release Notes

Search Console now includes a dedicated performance workspace with comparisons, deeper query and page reporting, Search Appearance insights, clearer sync recovery, and page-level HitKeep outcome context.

Docs Impact

Needed:

  • Search Console integration/setup guide
  • Analytics reporting guide
  • REST API reference
  • MCP and public analytics skill documentation
  • Updated screenshots
  • Release notes

The rendered documentation source is maintained separately; contributors without access should describe the required website updates in the implementation PR.

Additional Context

This should remain one scoped feature issue. Implementation may be delivered in reviewable vertical slices, but the data-model cutover, reporting semantics, recovery behavior, and public contract should be designed together so the workspace does not ship with internally inconsistent totals or states.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions