PilotFoxDocs

Google Search Console

Connect a Google account, link a site to its Search Console property, and read clicks, impressions, queries and pages.

PilotFox can import a site's Google Search Console data, so its search performance sits next to its traffic. Access is read-only: PilotFox asks Google for the https://www.googleapis.com/auth/webmasters.readonly scope (read Search Console data) plus openid and email, to show which Google account is connected.

Connect a Google account (organization admins and owners). Organization settings → Integrations → Connect Google account, then sign in with a Google account that has access to your Search Console properties. This needs organization:update and a signed-in person: only a person can complete Google's consent screen, so an API key gets 403.

Link a site (editors and above, with site:update). Open the site's Search Console page, pick the property (PilotFox suggests the one that matches the site's domain) and how many days of history to import: 90 by default, up to 486 (Google keeps 16 months). Properties your Google account cannot read (unverified) are listed but cannot be linked.

A connection shares that Google account's properties with everyone who can link one: editors (and API keys with site:update) that have access to every site of the organization. Members restricted to some sites, and API keys limited to some sites, can still sync and unlink the sites they edit, but cannot list the connections, see their properties or link one, so they never pull another client's property into their site. Connect an account that sees only the properties your organization's sites need.

Only admins and owners (and API keys with organization:update for the whole organization) see the connected Google account's full email; others see a hint such as j…@gmail.com.

What you see

Everyone who can read the site (searchConsole:read: every organization role) sees its Search Console report:

  • clicks, impressions, click-through rate (CTR) and average position over time;
  • top queries, pages, countries and devices, each with a detail view (a query's pages, countries and devices; a page's queries);
  • keyword insights against the comparison period.

CTR is clicks ÷ impressions (a ratio from 0 to 1 in the API). Average position is weighted by impressions, like Google's own report.

Insight (type=)Queries listed
winnersShown in both periods, gained at least one click; by click gain.
losersShown in both periods, lost at least one click; by click loss.
newImpressions in this period, none in the previous one; by impressions. Empty when the previous period has no synced day.
lostImpressions in the previous period, none in this one; by clicks, then impressions, in the previous period. Empty when the previous period has no synced day.
striking"Striking distance": average position 8 to 20 with at least 10 impressions; by impressions.
ctrPage-one queries (average position up to 10, at least 50 impressions) whose CTR is under half of your own site's CTR at that position (bands 1–3, 3–6, 6–10); by missed clicks.

Share links and public dashboards do not include Search Console data.

How syncing works

  • The first sync imports the history, newest days first, one day at a time (Google's recommended way to stay within its quotas). The status shows its progress (backfill.done of backfill.total days).
  • Then, every 6 hours (at 20 minutes past 00:00, 06:00, 12:00 and 18:00 UTC), each linked site imports its last 5 days again: Google's newest data is preliminary and final figures arrive two to three days later. Reports show complete days by default and mark preliminary ones (provisional in the API).
  • If Google's quota is reached, the sync waits 15 minutes and continues where it stopped.
  • Sync now (POST /api/v1/sites/{siteId}/search-console/sync) asks for a sync right away, without waiting out a quota pause.

Search Console days are Google's: Pacific Time, whatever the site's time zone. In the API, last=28d means the last 28 complete days ending on the newest complete day of the site's data, start/end take YYYY-MM-DD days, and compare=previous or compare=year adds the comparison period.

Disconnecting and access problems

  • If the Google account removes PilotFox's access, or the grant expires (a refresh token unused for six months), the connection shows needs reconnect and its sites wait. Reconnecting the same account resumes them.
  • Disconnecting a Google account deletes the stored token and revokes it at Google, unless another organization in PilotFox still uses the same Google account. Tokens are stored encrypted.
  • A connection lasts while the member who made it belongs to the organization. When they leave or are removed, their connections turn needs reconnect and their token is erased; the sites keep their data until an admin connects a Google account again and relinks them.
  • Unlinking a site stops its syncing and keeps its data readable; relinking the same property continues from it. Unlinking with ?deleteData=true deletes the data too. Deleting a site deletes its Search Console data with the rest of the site.

Self-hosted instances

Search Console needs an OAuth client of yours in a Google Cloud project, with the Google Search Console API enabled. Set SEARCH_CONSOLE_CLIENT_ID and SEARCH_CONSOLE_CLIENT_SECRET, or leave them unset to use the Google sign-in client (GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET) if that one is set. Either way, add this authorized redirect URI to the client, exactly:

${PUBLIC_URL}/api/v1/search-console/oauth/callback

for example https://analytics.example.com/api/v1/search-console/oauth/callback. Until a client is configured, the pages show the setup steps and the redirect URI, and connecting answers 503. Rotating BETTER_AUTH_SECRET makes the stored tokens unreadable: the connections then show Reconnect. See the configuration reference for the variables.

API endpoints

EndpointPermissionReference
GET /api/v1/orgs/{orgId}/search-consoleorganization:updateorg status
POST /api/v1/orgs/{orgId}/search-console/connectorganization:update, signed inconnect
DELETE /api/v1/orgs/{orgId}/search-console/connections/{connectionId}organization:updatedisconnect
GET /api/v1/sites/{siteId}/search-consolesearchConsole:readsite status
GET …/search-console/connections, GET …/search-console/properties?connectionId=site:update, org-wideconnections, properties
PUT /api/v1/sites/{siteId}/search-console (connectionId, property, backfillDays)site:update, org-widelink
DELETE /api/v1/sites/{siteId}/search-consolesite:updateunlink
POST /api/v1/sites/{siteId}/search-console/syncsite:updatesync
GET …/search-console/overview, /queries, /pages, /countries, /devices, /insights, /queries/detail, /pages/detailsearchConsole:readoverview, queries, insights
curl "https://pilotfox.app/api/v1/sites/SITE_ID/search-console/queries?last=28d&compare=previous&sort=clicks&limit=20" \
  -H "Authorization: Bearer $PILOTFOX_API_KEY"

The report endpoints answer 404 while the site has no linked property. Tables take search, sort, order, limit (1 to 1,000, 50 by default) and offset; insights takes type and limit (up to 200).

On this page