openclaudia/openclaudia-skills1 file

Search Console

>

Specification
Skill ID
openclaudia/openclaudia-skills/search-console
Publisher
openclaudia
Repository
openclaudia-skills
Installs
0
Files
1
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

openclaudia/openclaudia-skills/search-consoleInstalls these files
  • SKILL.md

What this skill tells the agent

Google Search Console

Pull search performance data, index coverage, and Core Web Vitals from Google Search Console API.

Prerequisites

Requires Google OAuth credentials:

  • GOOGLE_CLIENT_ID
  • GOOGLE_CLIENT_SECRET
  • A valid OAuth access token with https://www.googleapis.com/auth/webmasters.readonly scope

Set credentials in .env, .env.local, or ~/.claude/.env.global.

Getting an Access Token

# Step 1: Authorization URL (user visits in browser)
echo "https://accounts.google.com/o/oauth2/v2/auth?client_id=${GOOGLE_CLIENT_ID}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/webmasters.readonly&response_type=code&access_type=offline"

# Step 2: Exchange code for tokens
curl -s -X POST "https://oauth2.googleapis.com/token" \
  -d "code={AUTH_CODE}" \
  -d "client_id=${GOOGLE_CLIENT_ID}" \
  -d "client_secret=${GOOGLE_CLIENT_SECRET}" \
  -d "redirect_uri=urn:ietf:wg:oauth:2.0:oob" \
  -d "grant_type=authorization_code"

# Step 3: Refresh expired token
curl -s -X POST "https://oauth2.googleapis.com/token" \
  -d "refresh_token={REFRESH_TOKEN}" \
  -d "client_id=${GOOGLE_CLIENT_ID}" \
  -d "client_secret=${GOOGLE_CLIENT_SECRET}" \
  -d "grant_type=refresh_token"

Listing Available Sites

curl -s -H "Authorization: Bearer ${GSC_ACCESS_TOKEN}" \
  "https://www.googleapis.com/webmasters/v3/sites" \
  | python3 -c "
import json, sys
data = json.load(sys.stdin)
for site in data.get('siteEntry', []):
    print(f\"{site['siteUrl']}  |  Permission: {site['permissionLevel']}\")
"

The site URL format is either https://example.com/ (URL prefix) or sc-domain:example.com (domain property).


1. Search Performance Report

The core report: queries, pages, clicks, impressions, CTR, and average position.

API Endpoint

POST https://www.googleapis.com/webmasters/v3/sites/{siteUrl}/searchAnalytics/query

Note: The {siteUrl} must be URL-encoded (e.g., https%3A%2F%2Fexample.com%2F or sc-domain%3Aexample.com).

Top Queries

curl -s -X POST \
  "https://www.googleapis.com/webmasters/v3/sites/sc-domain%3Aexample.com/searchAnalytics/query" \
  -H "Authorization: Bearer ${GSC_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "startDate": "2024-01-01",
    "endDate": "2024-03-31",
    "dimensions": ["query"],
    "rowLimit": 50,
    "startRow": 0
  }'

Top Pages

curl -s -X POST \
  "https://www.googleapis.com/webmasters/v3/sites/sc-domain%3Aexample.com/searchAnalytics/query" \
  -H "Authorization: Bearer ${GSC_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "startDate": "2024-01-01",
    "endDate": "2024-03-31",
    "dimensions": ["page"],
    "rowLimit": 50
  }'

Query + Page Combination

curl -s -X POST \
  "https://www.googleapis.com/webmasters/v3/sites/sc-domain%3Aexample.com/searchAnalytics/query" \
  -H "Authorization: Bearer ${GSC_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "startDate": "2024-01-01",
    "endDate": "2024-03-31",
    "dimensions": ["query", "page"],
    "rowLimit": 100,
    "dimensionFilterGroups": [{
      "filters": [{
        "dimension": "page",
        "operator": "contains",
        "expression": "/blog/"
      }]
    }]
  }'

Available Dimensions

DimensionDescription
querySearch query
pageURL
countryCountry code (ISO 3166-1 alpha-3)
deviceDESKTOP, MOBILE, TABLET
dateIndividual date
searchAppearanceRich result type

Response Parsing

curl -s -X POST "..." | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f\"{'Query':<50} {'Clicks':>8} {'Impr':>8} {'CTR':>8} {'Pos':>6}\")
print('-' * 82)
for row in data.get('rows', []):
    keys = ' + '.join(row.get('keys', []))
    print(f\"{keys:<50} {row['clicks']:>8} {row['impressions']:>8} {row['ctr']*100:>7.1f}% {row['position']:>6.1f}\")
"

2. Search Performance by Date

Track daily trends for queries and pages.

curl -s -X POST \
  "https://www.googleapis.com/webmasters/v3/sites/sc-domain%3Aexample.com/searchAnalytics/query" \
  -H "Authorization: Bearer ${GSC_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "startDate": "2024-01-01",
    "endDate": "2024-03-31",
    "dimensions": ["date"],
    "rowLimit": 1000
  }'

To track a specific query over time:

curl -s -X POST \
  "https://www.googleapis.com/webmasters/v3/sites/sc-domain%3Aexample.com/searchAnalytics/query" \
  -H "Authorization: Bearer ${GSC_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "startDate": "2024-01-01",
    "endDate": "2024-03-31",
    "dimensions": ["date"],
    "dimensionFilterGroups": [{
      "filters": [{
        "dimension": "query",
        "operator": "equals",
        "expression": "your target keyword"
      }]
    }]
  }'

3. Index Coverage (URL Inspection API)

Check if a specific URL is indexed.

Endpoint

POST https://searchconsole.googleapis.com/v1/urlInspection/index:inspect

Example curl

curl -s -X POST \
  "https://searchconsole.googleapis.com/v1/urlInspection/index:inspect" \
  -H "Authorization: Bearer ${GSC_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "inspectionUrl": "https://example.com/page-to-check",
    "siteUrl": "sc-domain:example.com"
  }'

Response Fields

FieldDescription
inspectionResult.indexStatusResult.coverageStateSubmitted and indexed, Crawled - currently not indexed, etc.
inspectionResult.indexStatusResult.robotsTxtStateALLOWED or DISALLOWED
inspectionResult.indexStatusResult.indexingStateINDEXING_ALLOWED or INDEXING_NOT_ALLOWED
inspectionResult.indexStatusResult.lastCrawlTimeWhen Googlebot last crawled
inspectionResult.indexStatusResult.crawledAsDESKTOP or MOBILE
inspectionResult.mobileUsabilityResult.verdictPASS, FAIL, or VERDICT_UNSPECIFIED

4. Sitemaps

List and check sitemap status.

List Sitemaps

curl -s -H "Authorization: Bearer ${GSC_ACCESS_TOKEN}" \
  "https://www.googleapis.com/webmasters/v3/sites/sc-domain%3Aexample.com/sitemaps" \
  | python3 -c "
import json, sys
data = json.load(sys.stdin)
for sm in data.get('sitemap', []):
    print(f\"URL: {sm['path']}\")
    print(f\"  Type: {sm.get('type','')}  |  Submitted: {sm.get('lastSubmitted','')}\")
    print(f\"  URLs discovered: {sm.get('contents',[{}])[0].get('submitted','?')}  |  Indexed: {sm.get('contents',[{}])[0].get('indexed','?')}\")
    print()
"

Submit a Sitemap

curl -s -X PUT -H "Authorization: Bearer ${GSC_ACCESS_TOKEN}" \
  "https://www.googleapis.com/webmasters/v3/sites/sc-domain%3Aexample.com/sitemaps/https%3A%2F%2Fexample.com%2Fsitemap.xml"

5. Opportunity Identification

Use Search Console data to find SEO opportunities.

Low-Hanging Fruit: High Impressions, Low CTR

Queries with many impressions but low CTR suggest the title/description needs optimization.

# Pull queries, then filter for: impressions > 100 AND ctr < 0.03 AND position < 20
curl -s -X POST \
  "https://www.googleapis.com/webmasters/v3/sites/sc-domain%3Aexample.com/searchAnalytics/query" \
  -H "Authorization: Bearer ${GSC_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "startDate": "2024-01-01",
    "endDate": "2024-03-31",
    "dimensions": ["query", "page"],
    "rowLimit": 1000
  }' | python3 -c "
import json, sys
data = json.load(sys.stdin)
print('== Low CTR Opportunities (High impressions, low CTR, good position) ==')
print(f\"{'Query':<40} {'Page':<40} {'Impr':>6} {'CTR':>7} {'Pos':>5}\")
for row in data.get('rows', []):
    if row['impressions'] > 100 and row['ctr'] < 0.03 and row['position'] < 20:

Use this skill in a project

Open any RiverX project, search the Skills panel for openclaudia/openclaudia-skills/search-console, and install it in one click.

Use this skill