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 propertiesquerySearchAnalytics— fetch click, impression, position, and CTR datainspectUrl— 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 currentGscConnectionfor a projectsetSite— bind a specific GSC property URL to a projectdisconnect— remove the link viaGscConnectionRepository
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 propertyisExpectedGrantFailure— 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
- OAuth constants in
src/shared/gsc.tsdefine provider IDs and scopes - GSC client (
src/server/lib/gscClient.ts) wraps Google's REST API - GscService (
src/server/features/gsc/services/GscService.ts) implements grant detection, connection management, data retrieval, and error handling - Server functions (
src/serverFunctions/gsc.ts) expose typed endpoints for grant status, site listing, connection lifecycle, and self-hosted OAuth - Performance reports (
src/serverFunctions/searchPerformance.ts) consume GSC data for dashboards and exports - Security model keeps tokens server-side, persists only connection metadata, and surfaces grant failures for clean reconnection UX
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →