How OpenSEO Integrates Google Search Console Data: A Complete Technical Guide

OpenSEO connects to Google Search Console through a layered architecture that separates OAuth authentication, business logic in GscService, and server-function endpoints, ensuring secure, client-side-free data retrieval.

The every-app/open-seo repository implements a robust Google Search Console (GSC) integration that lets users link their properties, query search analytics, and inspect URLs without exposing credentials to the browser. This guide walks through the exact implementation, from OAuth configuration to performance reporting.

OAuth Configuration and Constants

All GSC-related constants live in src/shared/gsc.ts. This file defines the OAuth provider ID (google-search-console) and required scopes for accessing site data and search analytics.

The shared location ensures both frontend and backend use identical values when initiating OAuth flows or validating grants.

The GSC Client Wrapper

A low-level createGscClient function in src/server/lib/gscClient.ts encapsulates HTTP calls to Google's REST API. This wrapper exposes methods including:

  • listSites — enumerate accessible properties
  • querySearchAnalytics — fetch click, impression, position, and CTR data
  • inspectUrl — run URL inspection for indexing status

The client handles token injection and response parsing, isolating HTTP concerns from business logic.

GscService: Core Business Logic

The heart of the integration is GscService in src/server/features/gsc/services/GscService.ts. This class coordinates grant detection, connection management, and data operations.

Grant Detection

userHasGrant queries the account table for records where providerId = "google-search-console". This determines whether the authenticated user has completed OAuth authorization.

Connection Management

Three methods handle the project-to-property mapping:

  • getConnection — retrieve the current GscConnection for a project
  • setSite — bind a specific GSC property URL to a project
  • disconnect — remove the link via GscConnectionRepository

The one-to-one relationship is persisted in GscConnectionRepository, storing only the property URL and account reference—never raw Google data.

Data Retrieval

getPerformance forwards structured requests to querySearchAnalytics, returning:

  • Rows — dimension/metric breakdowns (query, page, device, etc.)
  • Request metadata — total counts, sampling info
  • Property URL — the connected site's canonical address

URL Inspection

inspectUrls executes batch URL inspections against the connected property. It processes per-URL errors individually while surfacing token failures (expired or revoked grants) for reconnection flows.

Error Handling Strategy

Two custom error types govern UI behavior:

  • GscNotConnectedError — thrown when a project lacks a linked GSC property
  • isExpectedGrantFailure — detects 401/403 responses and token errors, triggering reconnection prompts instead of generic error states

Server-Function API Endpoints

The public API surface resides in src/serverFunctions/gsc.ts. These functions bridge the frontend to GscService with clear, typed contracts.

Grant and Connection Status

// Check OAuth grant status
const { connected } = await getGscGrantStatus();
// → { connected: true }

// Get full connection state for a project
const status = await getGscConnection({ projectId: "proj_123" });
// → { connected: true, siteUrl: "https://example.com/", grantValid: true }

Site Selection

listGscSites returns all GSC properties the user can access, marking which is currently bound to the project:

const { accounts } = await listGscSites({ projectId: "proj_123" });
// accounts: [{ email: "user@gmail.com", sites: [...], current: true }]

Connection Lifecycle

// Bind a property to the project
await setGscSite({
  projectId: "proj_123",
  accountId: "gsc_acc_456",
  siteUrl: "https://example.com/",
});

// Remove the link
await disconnectGsc({ projectId: "proj_123" });

Self-Hosted OAuth

startSelfHostedGscLink generates an authorization URL for deployments without managed OAuth credentials, enabling custom client ID/secret configurations.

Performance Reporting Integration

Higher-level analytics consume GSC data through src/serverFunctions/searchPerformance.ts. These endpoints call GscService.getPerformance to assemble:

  • Dashboard visualizations
  • Filtered data tables
  • CSV exports

Example report request:

const report = await getSearchPerformanceReport({
  projectId: "proj_123",
  dateRange: { start: "2024-01-01", end: "2024-01-31" },
  device: "mobile",
  dimensions: ["query", "page"],
});
console.log(report.totals); // { clicks: 15234, impressions: 89012, ctr: 0.171, position: 12.4 }

MCP Debugging Tools

The integration also powers debugging utilities in src/server/mcp/tools/search-console-tools.ts. These Model Context Protocol tools let developers programmatically query GSC data during troubleshooting sessions.

Complete Data Flow


Frontend          Server Function          GscService          GSC Client          Google API
   │                    │                      │                    │                  │
   │ getGscGrantStatus  │                      │                    │                  │
   │───────────────────>│                      │                    │                  │
   │                    │ userHasGrant         │                    │                  │
   │                    │─────────────────────>│ check account table│                  │
   │                    │<─────────────────────│                    │                  │
   │ { connected: true }│                      │                    │                  │
   │<───────────────────│                      │                    │                  │
   │                    │                      │                    │                  │
   │ setGscSite         │                      │                    │                  │
   │───────────────────>│ setSite              │                    │                  │
   │                    │─────────────────────>│ persist via        │                  │
   │                    │                      │ GscConnectionRepo  │                  │
   │                    │<─────────────────────│                    │                  │
   │ success            │                      │                    │                  │
   │<───────────────────│                      │                    │                  │
   │                    │                      │                    │                  │
   │ getSearchPerformanceReport                  │                    │                  │
   │───────────────────>│                      │                    │                  │
   │                    │ getPerformance       │                    │                  │
   │                    │─────────────────────>│ querySearchAnalytics                  │
   │                    │                      │───────────────────>│                  │
   │                    │                      │                    │─── REST call ───>│
   │                    │                      │                    │<─── response─────│
   │                    │                      │<───────────────────│                  │
   │                    │<─────────────────────│ rows + metadata    │                  │
   │ report object      │                      │                    │                  │
   │<───────────────────│                      │                    │                  │

All GSC operations execute server-side only, using the user's stored OAuth token. No Google credentials or analytical data reach the browser.

Summary

Frequently Asked Questions

What OAuth scopes does OpenSEO request for Google Search Console?

According to src/shared/gsc.ts, OpenSEO requests scopes for site verification and search analytics read access. The exact scope strings are centralized in this shared module so both authorization URL generation and validation remain consistent across the application.

How does OpenSEO handle expired or revoked GSC grants?

GscService.isExpectedGrantFailure identifies 401/403 responses and token-related errors from Google. Instead of throwing internal server errors, these trigger the reconnection UI flow, prompting users to reauthorize while preserving their project settings.

Can OpenSEO connect multiple GSC properties to one project?

No—the architecture enforces a one-to-one mapping. GscService.setSite replaces any existing connection for a project, and GscConnectionRepository stores a single property URL per project. Users must disconnect before switching properties.

Where is raw Google Search Console data stored?

Only connection metadata (property URL, account reference) persists in OpenSEO's database. Actual search analytics data is fetched on-demand through GscService.getPerformance and never cached or stored permanently, ensuring compliance with Google's data policies.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →