seo-google skill (claude-seo)

From Public Agent Wiki
Contents
  1. Install
  2. SKILL.md (verbatim)
  3. Prerequisites
  4. Credential Tiers
  5. Quick Reference
  6. PageSpeed + CrUX
  7. /seo google pagespeed <url>
  8. /seo google crux <url>
  9. /seo google crux-history <url>
  10. Search Console
  11. /seo google gsc <property>
  12. /seo google inspect <url>
  13. /seo google inspect-batch <file>
  14. /seo google sitemaps <property>
  15. Indexing API
  16. /seo google index <url>
  17. /seo google index-batch <file>
  18. GA4 Traffic
  19. /seo google ga4 [property-id]
  20. /seo google ga4-pages [property-id]
  21. YouTube (Video SEO)
  22. /seo google youtube <query>
  23. /seo google youtube-video <videoid>
  24. NLP Content Analysis
  25. /seo google nlp <url-or-text>
  26. /seo google entities <url-or-text>
  27. Keyword Research (Google Ads)
  28. /seo google keywords <seed>
  29. /seo google volume <keywords>
  30. Supplementary
  31. /seo google entity <query>
  32. /seo google safety <url>
  33. /seo google quotas
  34. Reports
  35. /seo google report <type>
  36. Rate Limits
  37. Cross-Skill Integration
  38. Output Format
  39. Technical Notes
  40. Error Handling
  41. Other files in this skill
  42. assets/templates/cwv-audit-report.md (verbatim)
  43. CrUX Field Data (28-day rolling average)
  44. Lighthouse Lab Scores
  45. CrUX History Trends (25-week)
  46. Top Opportunities
  47. Recommendations
  48. assets/templates/gsc-performance-report.md (verbatim)
  49. Summary
  50. Top Queries
  51. Top Pages
  52. Quick Wins (Position 4-10, High Impressions)
  53. Device Breakdown
  54. assets/templates/indexation-status-report.md (verbatim)
  55. Summary
  56. Detailed Results
  57. Canonical Mismatches
  58. Common Issues
  59. Rich Results Detected
  60. references/auth-setup.md (verbatim)
  61. Overview
  62. Step 1: Create a Google Cloud Project
  63. Step 2: Enable APIs
  64. Step 3: Create an API Key
  65. Step 4: Create a Service Account
  66. Step 5: Grant Search Console Access
  67. Step 6: Grant GA4 Access
  68. Step 7: Create Config File
  69. Property URL Formats
  70. Step 8: Verify Setup
  71. Environment Variable Alternatives
  72. OAuth Scopes Used
  73. Troubleshooting
  74. references/dma-consent-mode-v2.md (verbatim)
  75. What the seo-google skill should do
  76. Required GA4 / Consent Mode setup the audit should check for
  77. Softening cookieless-attribution warnings
  78. Primary sources
  79. references/ga4-data-api.md (verbatim)
  80. Overview
  81. Key Methods
  82. runReport Request
  83. SEO-Relevant Dimensions
  84. SEO-Relevant Metrics
  85. Filter Expressions
  86. String Filter
  87. Combining Filters
  88. Date Range Shortcuts
  89. Token-Based Quotas
  90. Python Example
  91. Authentication
  92. references/indexing-api.md (verbatim)
  93. Overview
  94. Endpoints
  95. Publish Notification
  96. Get Notification Metadata
  97. Batch Requests
  98. Authentication
  99. Quotas
  100. Error Codes
  101. Best Practices
  102. references/keyword-planner-api.md (verbatim)
  103. Prerequisites (More Complex Than Other Google APIs)
  104. Key Methods
  105. GenerateKeywordIdeas
  106. GenerateKeywordHistoricalMetrics
  107. GenerateKeywordForecastMetrics
  108. Configuration
  109. Rate Limits
  110. Python Library
  111. Important Notes
  112. references/nlp-api.md (verbatim)
  113. Endpoint
  114. Features
  115. Entity Types
  116. Sentiment Scoring
  117. Pricing
  118. Enable the API
  119. references/pagespeed-crux-api.md (verbatim)
  120. Table of Contents
  121. PageSpeed Insights v5
  122. Parameters
  123. Response Structure
  124. Field Data Metrics (in loadingExperience)
  125. Key Lighthouse Audit IDs
  126. Rate Limits
  127. Note on Field Data Migration
  128. CrUX API (Daily)
  129. Request
  130. Available Metrics
  131. Response
  132. Important
  133. Rate Limits
  134. CrUX History API (Weekly)
  135. Response Differences from CrUX API
  136. NaN Handling
  137. Update Schedule
  138. Core Web Vitals Thresholds
  139. references/rate-limits-quotas.md (verbatim)
  140. Consolidated Quota Table
  141. Exponential Backoff Strategy
  142. Common Error Codes
  143. Retry-After Header
  144. GA4 Token Budgeting
  145. CrUX Shared Quota
  146. Cost Summary
  147. references/supplementary-apis.md (verbatim)
  148. Knowledge Graph Search API
  149. Custom Search JSON API
  150. Web Risk API

What it does. Google SEO APIs: Search Console (Search Analytics, URL Inspection, Sitemaps), PageSpeed Insights v5, CrUX field data with 25-week history, Indexing API v3, and GA4 organic traffic. Provides real Google field data for Core Web Vitals, indexation status, search performance, and organic traffic trends. Use when user says "search console", "GSC", "PageSpeed", "CrUX", "field data", "indexing API", "GA4 organic", "URL inspection", or "real CWV data". Part of seo skill (claude-seo: 25 sub-skills, 18 sub-agents) (AgriciDaniel/claude-seo).

Upstream AgriciDaniel/claude-seo
Skill file skills/seo-google/SKILL.md
License MIT (skill folder LICENSE.txt)
Author Daniel Agrici
Fetched 2026-09-10

Install

  • Claude Code: /plugin marketplace add AgriciDaniel/claude-seo; other agents: npx skills add AgriciDaniel/claude-seo --skill seo-google.
  • Raw file: curl -sL https://raw.githubusercontent.com/AgriciDaniel/claude-seo/HEAD/skills/seo-google/SKILL.md

SKILL.md (verbatim)

name: seo-google
description: >
  Google SEO APIs: Search Console (Search Analytics, URL Inspection, Sitemaps),
  PageSpeed Insights v5, CrUX field data with 25-week history, Indexing API v3,
  and GA4 organic traffic. Provides real Google field data for Core Web Vitals,
  indexation status, search performance, and organic traffic trends. Use when
  user says "search console", "GSC", "PageSpeed", "CrUX", "field data",
  "indexing API", "GA4 organic", "URL inspection", or "real CWV data".
user-invocable: true
argument-hint: "[command] [url|property]"
license: MIT
metadata:
  author: AgriciDaniel
  version: "2.2.6"
  category: seo

Google SEO APIs

Direct access to Google's own SEO data. Bridges the gap between crawl-based analysis (existing claude-seo skills) and Google's real-time field data: actual Chrome user metrics, real indexation status, search performance, and organic traffic.

All APIs are free. Setup requires a Google Cloud project with API key and/or service account -- run /seo google setup for step-by-step instructions.

Prerequisites

Before executing any command, check credentials:

"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run google_auth.py --check --json

Config file: ~/.config/claude-seo/google-api.json

{
  "service_account_path": "/path/to/service_account.json",
  "api_key": "<GOOGLE_API_KEY>",
  "default_property": "sc-domain:example.com",
  "ga4_property_id": "properties/123456789"
}

If missing, read references/auth-setup.md and walk the user through setup.

Credential Tiers

Tier Detection Available Commands
0 (API Key) api_key present pagespeed, crux, crux-history, youtube, nlp
1 (OAuth/SA) + OAuth token or service account Tier 0 + gsc, inspect, sitemaps, index
2 (Full) + ga4_property_id configured Tier 1 + ga4, ga4-pages
3 (Ads) + ads_developer_token + ads_customer_id Tier 2 + keywords, volume

Always communicate the detected tier before running commands.

Quick Reference

Command What it does Tier
/seo google setup Check/configure API credentials --
/seo google pagespeed <url> PSI Lighthouse + CrUX field data 0
/seo google crux <url> CrUX field data only (p75 metrics) 0
/seo google crux-history <url> 25-week CWV trend analysis 0
/seo google gsc <property> Search Console: clicks, impressions, CTR, position 1
/seo google inspect <url> URL Inspection: index status, canonical, crawl info 1
/seo google inspect-batch <file> Batch URL Inspection from file 1
/seo google sitemaps <property> GSC sitemap status 1
/seo google index <url> Submit URL to Indexing API 1
/seo google index-batch <file> Batch submit up to 200 URLs 1
/seo google ga4 [property-id] GA4 organic traffic report 2
/seo google ga4-pages [property-id] Top organic landing pages 2
/seo google youtube <query> YouTube video search (views, likes, duration) 0
/seo google youtube-video <id> YouTube video details + top comments 0
/seo google nlp <url-or-text> NLP entity extraction + sentiment + classification 0
/seo google entities <url-or-text> Entity analysis only (for E-E-A-T) 0
/seo google keywords <seed> Keyword ideas from Google Ads Keyword Planner 3
/seo google volume <keywords> Search volume lookup from Keyword Planner 3
/seo google entity <query> Knowledge Graph entity check 0
/seo google safety <url> Web Risk URL safety check 0
/seo google quotas Show rate limits for all APIs --

PageSpeed + CrUX

/seo google pagespeed <url>

Combined Lighthouse lab data + CrUX field data.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run pagespeed_check.py <url> --json Reference: references/pagespeed-crux-api.md Default: Both mobile + desktop strategies, all Lighthouse categories.

Output merges lab scores (point-in-time Lighthouse) with field data (28-day Chrome user metrics). CrUX tries URL-level first, falls back to origin-level.

/seo google crux <url>

CrUX field data only (no Lighthouse run). Faster.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run pagespeed_check.py <url> --crux-only --json

/seo google crux-history <url>

25-week CrUX History trends. Shows whether CWV metrics are improving, stable, or degrading.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run crux_history.py <url> --json Reference: references/pagespeed-crux-api.md

Output includes per-metric trend direction, percentage change, and weekly p75 values.


Search Console

/seo google gsc <property>

Search Analytics: clicks, impressions, CTR, position for last 28 days.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run gsc_query.py --property <property> --json Reference: references/search-console-api.md Default: 28 days, dimensions=query,page, type=web, limit=1000.

Includes quick-win detection: queries at position 4-10 with high impressions. The totals block comes from a separate dimensionless aggregate query because query-level rows can omit anonymized low-volume traffic. Treat totals as site-wide only when totals_complete is true. --limit caps total returned dimension rows, not the size of every pagination request.

AI surfaces in GSC (2026):

  • Generative AI performance report (launched 2026-06-03), a dedicated view of AI Overviews + AI Mode visibility. Impressions only (no clicks/CTR/position/query); dimensions Pages/Countries/Devices/Dates (Pacific Time); 1,000-row limit; newest data preliminary; a separate Discover gen-AI report also exists. Rolling out to a subset of properties.
  • AI Mode already rolls into standard Performance totals (Web search type), clicks (external-link clicks in AI Mode) and impressions are counted in the normal report, so you cannot cleanly split "classic" vs "AI" traffic from totals. Use the Generative AI report for impressions-only AI visibility.
  • Data-reliability caveat: a GSC logging error made impressions, CTR, and average position unreliable from 2025-05-13 to 2026-04-27 (clicks unaffected; fixed forward-only, no backfill). Treat impression/CTR/position trends spanning that window with caution; expect an apparent impressions drop after the fix.

Platform properties (2026): Search Console can expose verified TikTok, Instagram, X, and YouTube accounts as individual properties. Verify each account separately, unless it was already added through a claimed Search profile. Use these properties for Google Search performance only, not as a substitute for the platform's own analytics. Source: developers.google.com/search/docs/monitor-debug/analyze-social-video-content

/seo google inspect <url>

URL Inspection: real indexation status from Google.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run gsc_inspect.py <url> --json

Returns: verdict (PASS/FAIL), coverage state, robots.txt status, indexing state, page fetch state, canonical selection, mobile usability, rich results.

/seo google inspect-batch <file>

Batch inspection from a file (one URL per line). Rate limited to 2,000/day per site.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run gsc_inspect.py --batch <file> --json

/seo google sitemaps <property>

List submitted sitemaps with status, errors, warnings. Sitemap contents report submitted counts only; URL Inspection API is the indexation truth for whether specific URLs are indexed.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run gsc_query.py sitemaps --property <property> --json


Indexing API

/seo google index <url>

Notify Google of a URL update.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run indexing_notify.py <url> --json Reference: references/indexing-api.md

The Indexing API is officially for JobPosting and BroadcastEvent/VideoObject pages. Always inform the user of this restriction. Daily quota: 200 publish requests.

/seo google index-batch <file>

Batch submit URLs from a file. Tracks quota usage.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run indexing_notify.py --batch <file> --json


GA4 Traffic

/seo google ga4 [property-id]

Organic traffic report: daily sessions, users, pageviews, bounce rate, engagement.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run ga4_report.py --property <id> --json Reference: references/ga4-data-api.md Default: 28 days, filtered to Organic Search channel group.

GA4 "AI Assistants" channel (live ~2026-05-13): GA4 added a native AI Assistants Default Channel Group. Sessions referred by a recognized AI assistant get medium=ai-assistant. Google's recognized sources are ChatGPT, Gemini, Claude, Deepseek, Copilot, Grok and the channel excludes Google AI Overviews / AI Mode. Verify Perplexity separately if needed; unsupported sources may stay in Referral, and most AI sessions arrive referrer-less and fall into Direct, so this channel undercounts AI traffic. Forward-only, no backfill.

/seo google ga4-pages [property-id]

Top organic landing pages ranked by sessions.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run ga4_report.py --property <id> --report top-pages --json


YouTube (Video SEO)

Some third-party studies report a 0.737 correlation between YouTube mentions and AI visibility. Treat it as a methodology-dependent signal. Free, API key only.

/seo google youtube <query>

Search YouTube for videos. Returns title, channel, views, likes, duration.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run youtube_search.py search "<query>" --json Reference: references/youtube-api.md Quota: 100 units per search (10,000 units/day free).

/seo google youtube-video <video_id>

Detailed video info + tags + top 10 comments.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run youtube_search.py video <video_id> --json Quota: 2 units (video details + comments).


NLP Content Analysis

Google NLP entity/sentiment output for internal content-quality checks. Do not treat it as Google E-E-A-T scoring.

/seo google nlp <url-or-text>

Full NLP analysis: entities, sentiment, content classification.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run nlp_analyze.py --url <url> --json or --text "..." Reference: references/nlp-api.md Free tier: 5,000 units/month. Requires billing enabled on GCP project.

/seo google entities <url-or-text>

Entity extraction only (faster, less quota).

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run nlp_analyze.py --url <url> --features entities --json


Keyword Research (Google Ads)

Gold-standard keyword volume data. Requires Google Ads account.

/seo google keywords <seed>

Generate keyword ideas from seed terms.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run keyword_planner.py ideas "<seed>" --json Reference: references/keyword-planner-api.md Requires: Ads developer token + customer ID in config (Tier 3).

/seo google volume <keywords>

Search volume for specific keywords (comma-separated).

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run keyword_planner.py volume "<kw1>,<kw2>" --json


Supplementary

/seo google entity <query>

Knowledge Graph entity check. Verifies brand presence.

Reference: references/supplementary-apis.md Uses Knowledge Graph Search API with API key.

/seo google safety <url>

Web Risk API check for malware/social engineering flags.

Reference: references/supplementary-apis.md

/seo google quotas

Display rate limits table. Read references/rate-limits-quotas.md.


Reports

After any analysis command, offer to generate a PDF/HTML report.

/seo google report <type>

Generate a professional PDF report with charts and analytics.

Script: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run google_report.py --type <type> --data <json> --domain <domain> --format pdf

Type Input Output
cwv-audit PSI + CrUX + CrUX History data Core Web Vitals audit with gauges, timelines, distributions
gsc-performance GSC query data Search Console report with query tables, quick wins
indexation Batch inspection data Indexation status with coverage donut chart
full All data combined Comprehensive Google SEO report (all sections)

Workflow:

  1. Run data collection commands (pagespeed, gsc, inspect-batch, etc.)
  2. Save JSON output to file: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run pagespeed_check.py <url> --json > data.json
  3. Generate report: "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run google_report.py --type cwv-audit --data data.json --domain <domain>

Convention: After completing analysis, suggest: "Generate a report? Use /seo google report <type>"


Rate Limits

API Per-Minute Per-Day Auth
PSI v5 240 QPM 25,000 QPD API Key
CrUX + History 150 QPM (shared) Unlimited API Key
GSC Search Analytics 1,200 QPM/site 30M QPD Service Account
GSC URL Inspection 600 QPM 2,000 QPD/site Service Account
Indexing API 380 RPM 200 publish/day Service Account
GA4 Data API 10 concurrent ~25K tokens/day Service Account

Cross-Skill Integration

  • seo-audit: Spawns seo-google agent for live CWV + indexation data (conditional)
  • seo-technical: Uses pagespeed_check.py for real CWV field data
  • seo-performance: CrUX field data supplements Lighthouse lab data
  • seo-sitemap: GSC sitemap status shows submitted counts, errors, and warnings; use URL Inspection for indexation truth
  • seo-content: GSC query data informs keyword targeting
  • seo-geo: Use GSC Generative AI performance reports and AI Overviews/AI Mode/Discover gen-AI include/exclude controls where available

Output Format

  • CWV metrics: traffic-light rating (Good / Needs Improvement / Poor)
  • Performance reports: tables with sortable columns
  • Always include data freshness note
  • Save reports as GOOGLE-API-REPORT-{domain}.md
  • Markdown/LLM templates in assets/templates/: cwv-audit-report.md, gsc-performance-report.md, indexation-status-report.md; distinct from google_report.py's PDF pipeline

Technical Notes

  • INP replaced FID on March 12, 2024. Never reference FID.
  • CLS values from CrUX are string-encoded (e.g., "0.05"). Scripts handle parsing.
  • CrUX 404 = insufficient traffic, not an auth error.
  • Search Analytics data has 2-3 day lag.
  • round_trip_time replaced effectiveConnectionType in CrUX (Feb 2025).
  • Custom Search JSON API is closed to new customers (2025).

Error Handling

Scenario Action
No credentials configured Run /seo google setup. List Tier 0 commands that work with just an API key.
Service account lacks GSC access Report error. Instruct: add client_email to GSC > Settings > Users > Add.
CrUX data unavailable (404) Report insufficient Chrome traffic. Suggest PSI lab data as fallback.
GA4 property not found Report error. Show how to find property ID in GA4 Admin > Property Details.
Indexing API quota exceeded Report 200/day limit. Suggest prioritizing most important URLs.
Rate limit (429) Wait and retry with exponential backoff. Report which API hit the limit.

Other files in this skill

assets/templates/cwv-audit-report.md (verbatim)

Core Web Vitals Audit

URL/Origin: {target} Strategy: {strategy}

CrUX Field Data (28-day rolling average)

Real Chrome user experience data from the Chrome UX Report.

Metric p75 Value Rating Good Threshold Distribution
LCP {lcp_value} {lcp_rating} ≤ 2,500ms Good: {lcp_good}% / NI: {lcp_ni}% / Poor: {lcp_poor}%
INP {inp_value} {inp_rating} ≤ 200ms Good: {inp_good}% / NI: {inp_ni}% / Poor: {inp_poor}%
CLS {cls_value} {cls_rating} ≤ 0.1 Good: {cls_good}% / NI: {cls_ni}% / Poor: {cls_poor}%
FCP {fcp_value} {fcp_rating} ≤ 1,800ms Good: {fcp_good}% / NI: {fcp_ni}% / Poor: {fcp_poor}%
TTFB {ttfb_value} {ttfb_rating} ≤ 800ms Good: {ttfb_good}% / NI: {ttfb_ni}% / Poor: {ttfb_poor}%

Collection Period: {collection_start} to {collection_end}

Lighthouse Lab Scores

Category Score
Performance {perf_score}/100
Accessibility {a11y_score}/100
Best Practices {bp_score}/100
SEO {seo_score}/100
Metric Direction Change Earliest → Latest
{trends_table}

Top Opportunities

Opportunity Estimated Savings
{opportunities_table}

Recommendations

{recommendations}


CrUX data updated daily ~04:00 UTC. 28-day rolling average. INP replaced FID as the responsiveness Core Web Vital on March 12, 2024. Generated {timestamp}.

assets/templates/gsc-performance-report.md (verbatim)

Google Search Console Performance Report

Property: {property} Date Range: {start_date} — {end_date} Search Type: {search_type}

Summary

Metric Value
Total Clicks {total_clicks}
Total Impressions {total_impressions}
Average CTR {avg_ctr}%
Average Position {avg_position}

Top Queries

# Query Clicks Impressions CTR Position
{queries_table}

Top Pages

# Page Clicks Impressions CTR Position
{pages_table}

Quick Wins (Position 4-10, High Impressions)

These queries rank on page 1 but below position 3. A small ranking improvement could yield significant traffic gains.

Query Position Impressions Clicks CTR Opportunity
{quick_wins_table}

Device Breakdown

Device Clicks Impressions CTR Position
{device_table}

Data freshness: Search Analytics has a 2-3 day lag. Data available for ~16 months. If this report overlaps 2025-05-13 to 2026-04-27, impressions, CTR, and average position require caution due to the confirmed GSC impressions logging error. Clicks were not affected and affected metrics were not backfilled. Generated {timestamp} via Google Search Console API.

assets/templates/indexation-status-report.md (verbatim)

URL Indexation Status Report

Property: {property} URLs Inspected: {total_urls}

Summary

Status Count Percentage
Indexed (PASS) {pass_count} {pass_pct}%
Not Indexed (FAIL) {fail_count} {fail_pct}%
Neutral {neutral_count} {neutral_pct}%
Errors {error_count} {error_pct}%

Detailed Results

URL Verdict Coverage State Fetch State Google Canonical Last Crawl
{results_table}

Canonical Mismatches

URLs where Google selected a different canonical than declared:

URL User Canonical Google Canonical
{canonical_mismatches_table}

Common Issues

Issue Count Priority Action
{issues_table}

Rich Results Detected

URL Rich Result Type Status
{rich_results_table}

URL Inspection API: 2,000 inspections/day per site, 600/min. Generated {timestamp} via Google Search Console URL Inspection API.

references/auth-setup.md (verbatim)

Google API Authentication Setup

Overview

Three credential types serve different APIs:

Type Used By Cost
API Key PageSpeed Insights, CrUX, CrUX History, Knowledge Graph Free
Service Account Search Console, Indexing API, GA4 Free
Both Full seo-google skill Free

Step 1: Create a Google Cloud Project

  1. Go to console.cloud.google.com
  2. Click Select a project > New Project
  3. Name it (e.g., "Claude SEO") and note the project ID
  4. Select the project after creation

Step 2: Enable APIs

Navigate to APIs & Services > Library and enable:

API Required For
Google Search Console API GSC Search Analytics, URL Inspection, Sitemaps
PageSpeed Insights API PSI Lighthouse lab data
Chrome UX Report API CrUX field data + History
Web Search Indexing API Indexing API v3
Google Analytics Data API GA4 organic traffic
Knowledge Graph Search API Entity verification (optional)

Step 3: Create an API Key

  1. APIs & Services > Credentials > Create Credentials > API key
  2. Click Restrict key:
    • Under API restrictions, select: PageSpeed Insights API, Chrome UX Report API, Knowledge Graph Search API
  3. Copy the generated API key and store it securely

Step 4: Create a Service Account

  1. IAM & Admin > Service Accounts > Create Service Account
  2. Name: claude-seo (or similar)
  3. Skip optional permissions steps
  4. Click on the created service account > Keys > Add Key > Create new key > JSON
  5. Download the JSON file and store it securely (e.g., ~/.config/claude-seo/service_account.json)

The JSON file looks like:

{
  "type": "service_account",
  "project_id": "your-project-id",
  "private_key_id": "...",
  "private_key": "<service-account-private-key>",
  "client_email": "<service-account-identifier>",
  "client_id": "...",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token"
}

The client_email field is what you add to GSC and GA4.

Step 5: Grant Search Console Access

  1. Go to Google Search Console
  2. Select your property
  3. Settings > Users and permissions > Add user
  4. Paste the service account client_email
  5. Set permission level:
    • Full for read-only (Search Analytics, URL Inspection, Sitemaps)
    • Owner if you also need the Indexing API

Step 6: Grant GA4 Access

  1. Go to Google Analytics
  2. Admin > Property Access Management > Add users (the + icon)
  3. Paste the service account client_email
  4. Set role: Viewer (minimum for read-only reporting)
  5. Note the numeric property ID from Admin > Property Details (e.g., 123456789)

Step 7: Create Config File

mkdir -p ~/.config/claude-seo

Save to ~/.config/claude-seo/google-api.json:

{
  "service_account_path": "~/.config/claude-seo/service_account.json",
  "api_key": "<GOOGLE_API_KEY>",
  "default_property": "sc-domain:example.com",
  "ga4_property_id": "properties/123456789"
}

Property URL Formats

Format Example When to Use
Domain property sc-domain:example.com Covers all URLs on the domain (recommended)
URL-prefix property https://example.com/ Covers only that specific prefix

Step 8: Verify Setup

"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run google_auth.py --check

Expected output at Tier 2 (full):

Credential Tier: 2 -- Full (API key + Service Account + GA4)

  [OK] PageSpeed Insights v5
  [OK] Chrome UX Report (CrUX) API
  [OK] CrUX History API
  [OK] Google Search Console API
       Service account: configured
  [OK] Google Indexing API v3
  [OK] GA4 Data API v1beta

Environment Variable Alternatives

Instead of (or in addition to) the config file:

Variable Purpose
GOOGLE_API_KEY API key for PSI/CrUX
GOOGLE_APPLICATION_CREDENTIALS Path to service account JSON
GA4_PROPERTY_ID GA4 property (e.g., properties/123456789)
GSC_PROPERTY Default GSC property (e.g., sc-domain:example.com)

OAuth Scopes Used

Scope APIs
https://www.googleapis.com/auth/webmasters.readonly GSC (read)
https://www.googleapis.com/auth/webmasters GSC (read/write, needed for sitemap submission)
https://www.googleapis.com/auth/indexing Indexing API
https://www.googleapis.com/auth/analytics.readonly GA4 (read)

Troubleshooting

Error Fix
403 Forbidden on GSC Service account email not added to GSC property, or wrong permission level
403 Forbidden on GA4 Service account email not added to GA4 property as Viewer
404 Not Found on GSC Wrong property URL format. Use sc-domain: or include trailing slash for URL-prefix
404 Not Found on CrUX Site has insufficient Chrome traffic. Not a credentials issue.
429 Rate Limit Wait and retry. See rate-limits-quotas.md for per-API limits
API not enabled Enable the specific API in GCP Console > APIs & Services > Library

DMA + Consent Mode v2 — click-through impact diagnostic

EU traffic flowing through Google Search has been subject to the Digital Markets Act since 2024-03-07. The DMA limits how Google can use behavioural data and forces consent-mode v2 compliance for GA4 + Ads in EU. The operational effect for SEO audits:

  • EU click-through-rate (CTR) data from Search Console is materially noisier after the DMA enforcement date. Year-over-year CTR comparisons across that boundary are not apples-to-apples.
  • GA4 organic-traffic reports for EU users show systematic under-reporting when consent-mode v2 is configured as "denied for ad_storage, granted for analytics_storage" (the typical EU default). Conversion modelling fills the gap, but the raw counts are lower than pre-2024.

What the seo-google skill should do

  1. When pulling GSC search analytics for an EU-targeted property, note: "EU CTR comparisons before/after 2024-03-07 are not apples-to-apples (DMA + consent-mode v2 took effect)."
  2. When pulling GA4 organic traffic, surface the consent-mode configuration if the GA4 admin API exposes it. If the property has eu_data_collection_disabled or denies ad_storage by default, note "EU traffic counts are conservative; conversion-modelled uplift may apply."
  3. Do not lecture the user on cookie consent UX — that's a legal team / engineering concern outside SEO scope. Just attach the diagnostic note.
  • GA4 4.x consent-mode v2 wired up (gtag('consent', 'default', ...) before any pageview).
  • ads_data_redaction flag set on EU traffic.
  • Server-side tagging at consent transitions (recommended pattern; not legally required).

Softening cookieless-attribution warnings

Google abandoned third-party cookie deprecation in July 2024 and confirmed in April 2025 that Chrome will not ship a standalone cookie prompt. The "cookieless future" framing is no longer urgent.

For audits as of May 2026:

  • Do NOT recommend "switch to cookieless attribution" as a priority.
  • DO recommend "implement consent-mode v2 + server-side tagging" for EU compliance + signal-loss recovery.
  • Privacy Sandbox APIs are still available, but optional. Mention only if the audit subject is consumer-facing and has heavy retargeting dependence.

Primary sources

Last verified: 2026-05-17.

references/ga4-data-api.md (verbatim)

GA4 Data API v1beta Reference

Overview

The Google Analytics Data API v1beta provides programmatic access to GA4 report data. For SEO, the primary use case is organic traffic analysis.

Base URL: https://analyticsdata.googleapis.com/v1beta

Key Methods

Method Description
properties.runReport Run a standard report
properties.batchRunReports Up to 5 reports in one call
properties.runRealtimeReport Last 30 minutes of data
properties.getMetadata Available dimensions and metrics
properties.checkCompatibility Verify dimension/metric combinations

runReport Request

{
  "property": "properties/123456789",
  "dimensions": [
    { "name": "date" },
    { "name": "landingPage" }
  ],
  "metrics": [
    { "name": "sessions" },
    { "name": "totalUsers" }
  ],
  "dateRanges": [
    { "startDate": "28daysAgo", "endDate": "yesterday" }
  ],
  "dimensionFilter": {
    "filter": {
      "fieldName": "sessionDefaultChannelGroup",
      "stringFilter": {
        "matchType": "EXACT",
        "value": "Organic Search"
      }
    }
  },
  "orderBys": [
    { "metric": { "metricName": "sessions" }, "desc": true }
  ],
  "limit": 100,
  "returnPropertyQuota": true
}

SEO-Relevant Dimensions

Dimension Description
date Date in YYYYMMDD format
pagePath Page path (e.g., /blog/post)
landingPage Entry page path
landingPagePlusQueryString Entry page with query params
fullPageUrl Full page URL
pageTitle Page title
sessionSource Traffic source (e.g., google)
sessionMedium Traffic medium (e.g., organic)
sessionDefaultChannelGroup Channel grouping (e.g., Organic Search)
country User country
deviceCategory desktop, mobile, tablet
hostName Domain name
pageReferrer Referrer URL

SEO-Relevant Metrics

Metric Description
sessions Number of sessions
totalUsers Total unique users
newUsers First-time users
activeUsers Users with engagement
screenPageViews Page views
bounceRate Bounce rate (0-1, multiply by 100 for %)
averageSessionDuration Avg duration in seconds
engagementRate Engaged session rate (0-1)
keyEvents Key events (replaced deprecated conversions)
eventCount Total event count

Filter Expressions

String Filter

{
  "filter": {
    "fieldName": "sessionDefaultChannelGroup",
    "stringFilter": {
      "matchType": "EXACT",
      "value": "Organic Search"
    }
  }
}

Match types: EXACT, BEGINS_WITH, ENDS_WITH, CONTAINS, FULL_REGEXP, PARTIAL_REGEXP

Combining Filters

{
  "andGroup": {
    "expressions": [
      { "filter": { "fieldName": "country", "stringFilter": { "matchType": "EXACT", "value": "US" }}},
      { "filter": { "fieldName": "deviceCategory", "stringFilter": { "matchType": "EXACT", "value": "mobile" }}}
    ]
  }
}

Also supports orGroup and notExpression.

Date Range Shortcuts

Value Meaning
today Current day
yesterday Previous day
NdaysAgo N days ago (e.g., 28daysAgo)
YYYY-MM-DD Specific date

Up to 4 date ranges per request (for period-over-period comparison).

Token-Based Quotas

Quota Limit Scope
Daily tokens 25,000 Per property per project
Hourly tokens 5,000 Per property per project
Concurrent requests 10 Per property per project
Hourly tokens (project-wide) 1,250 Per project per property per hour

Set returnPropertyQuota: true to monitor consumption. Simple reports cost ~1-10 tokens; complex ones up to ~100.

Python Example

from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import (
    DateRange, Dimension, Filter, FilterExpression,
    Metric, OrderBy, RunReportRequest,
)
from google.oauth2 import service_account

credentials = service_account.Credentials.from_service_account_file(
    "service_account.json",
    scopes=["https://www.googleapis.com/auth/analytics.readonly"],
)

client = BetaAnalyticsDataClient(credentials=credentials)

request = RunReportRequest(
    property="properties/123456789",
    dimensions=[Dimension(name="landingPage")],
    metrics=[Metric(name="sessions"), Metric(name="totalUsers")],
    date_ranges=[DateRange(start_date="28daysAgo", end_date="yesterday")],
    dimension_filter=FilterExpression(
        filter=Filter(
            field_name="sessionDefaultChannelGroup",
            string_filter=Filter.StringFilter(
                match_type=Filter.StringFilter.MatchType.EXACT,
                value="Organic Search",
            ),
        )
    ),
    order_bys=[OrderBy(metric=OrderBy.MetricOrderBy(metric_name="sessions"), desc=True)],
    limit=50,
    return_property_quota=True,
)

response = client.run_report(request)
for row in response.rows:
    print(f"{row.dimension_values[0].value}: {row.metric_values[0].value} sessions")

Authentication

  • Scope: https://www.googleapis.com/auth/analytics.readonly
  • Service account must have Viewer role in GA4 property
  • Add via GA4 Admin > Property Access Management

references/indexing-api.md (verbatim)

Google Indexing API v3 Reference

Overview

The Indexing API allows you to notify Google when pages are added or removed.

IMPORTANT: Use the Indexing API only for eligible URLs with JobPosting or BroadcastEvent embedded in VideoObject structured data. For a few ordinary URLs, use URL Inspection; for many ordinary URLs, use sitemaps. A URL_UPDATED notification only means Google may recrawl soon and gives no indexing benefit for other page types.

Endpoints

Publish Notification

POST https://indexing.googleapis.com/v3/urlNotifications:publish

{
  "url": "https://example.com/jobs/software-engineer",
  "type": "URL_UPDATED"
}
Field Values
url The fully qualified URL
type URL_UPDATED (page added/changed), URL_DELETED (page removed)

Response:

{
  "urlNotificationMetadata": {
    "url": "https://example.com/jobs/software-engineer",
    "latestUpdate": {
      "url": "https://example.com/jobs/software-engineer",
      "type": "URL_UPDATED",
      "notifyTime": "2026-03-27T10:00:00Z"
    }
  }
}

Get Notification Metadata

GET https://indexing.googleapis.com/v3/urlNotifications/metadata?url={ENCODED_URL}

Returns latestUpdate and latestRemove timestamps for the URL.

Batch Requests

POST https://indexing.googleapis.com/batch

Up to 100 URLs per batch request using multipart/mixed format:

POST /batch HTTP/1.1
Content-Type: multipart/mixed; boundary=batch_boundary

--batch_boundary
Content-Type: application/http
Content-ID: <item1>

POST /v3/urlNotifications:publish HTTP/1.1
Content-Type: application/json

{"url": "https://example.com/jobs/1", "type": "URL_UPDATED"}
--batch_boundary
Content-Type: application/http
Content-ID: <item2>

POST /v3/urlNotifications:publish HTTP/1.1
Content-Type: application/json

{"url": "https://example.com/jobs/2", "type": "URL_UPDATED"}
--batch_boundary--

Authentication

  • Scope: https://www.googleapis.com/auth/indexing
  • Auth type: Service account (OAuth 2.0)
  • The service account must be Owner in Google Search Console for the target domain

Quotas

Limit Value Scope
Publish requests 200/day (default) Per project
Read-only requests 180/min Per project
Total requests 380/min Per project

Request a quota increase: Indexing API Quota Increase Form

Error Codes

Code Meaning Action
400 Malformed URL or request body Check URL format
403 Permission denied or quota exceeded Add service account as Owner in GSC, or check quota
429 Rate limit exceeded Back off and retry with exponential delay
500/503 Server error Retry with exponential backoff

Best Practices

  1. Submit only URLs with actual content changes (don't spam updates)
  2. Use URL_DELETED only when a page is permanently removed (returns 404/410)
  3. Track daily quota usage -- the 200/day limit resets at midnight Pacific Time
  4. For large-scale indexing, use XML sitemaps + Search Console instead
  5. Batch requests count individually against the daily quota (100 batch = 100 quota)

references/keyword-planner-api.md (verbatim)

Google Ads API - Keyword Planner Reference

Gold-standard source for keyword search volume. DataForSEO gets its volume data from Google Ads -- this cuts out the middleman.

Prerequisites (More Complex Than Other Google APIs)

  1. Google Ads Manager Account -- create at ads.google.com (free to create)
  2. Developer Token -- apply at Google Ads API Center (requires Basic access approval)
  3. OAuth 2.0 credentials -- reuse existing OAuth client from seo-google config
  4. For exact volumes: Run a minimal campaign (~$5-10/day). Without spend, volumes are bucketed ranges ("1K-10K")

Key Methods

GenerateKeywordIdeas

Generate keyword suggestions from seed terms.

Returns per keyword:

  • text: Keyword string
  • avg_monthly_searches: Average monthly volume (exact if spending, bucketed if not)
  • competition: LOW / MEDIUM / HIGH (for ads, not organic)
  • competition_index: 0-100 competition score
  • low_top_of_page_bid_micros: ~20th percentile CPC in micros
  • high_top_of_page_bid_micros: ~80th percentile CPC in micros
  • monthly_search_volumes[]: Per-month volume for last 12 months

GenerateKeywordHistoricalMetrics

Get volume data for specific keywords.

Same return fields as above but for exact keyword list instead of suggestions.

GenerateKeywordForecastMetrics

Predict clicks, impressions, and cost for keywords.

Configuration

Add to ~/.config/claude-seo/google-api.json:

{
  "ads_developer_token": "YOUR_DEV_TOKEN",
  "ads_customer_id": "123-456-7890",
  "ads_login_customer_id": "123-456-7890"
}

Rate Limits

  • Keyword Planning requests are more strictly rate-limited than other Ads API services
  • Exact QPM/QPS not publicly documented
  • Google recommends caching results

Python Library

pip install google-ads

Uses google-ads library (separate from google-api-python-client).

Important Notes

  • Volume accuracy: Without active ad spend, Google returns bucketed ranges ("1K-10K", "10K-100K") instead of exact numbers like "14,800"
  • Competition score: Measures advertiser competition for ads, NOT organic ranking difficulty
  • CPC bids: Reflect what advertisers pay, useful for estimating keyword commercial value
  • Location targeting: Use location IDs (2840 = United States, 2826 = United Kingdom)
  • Language targeting: Use language IDs (1000 = English, 1003 = Spanish)

references/nlp-api.md (verbatim)

Google Cloud Natural Language API Reference

Use NLP analysis as an internal diagnostic for entity coverage, content sentiment, and topic classification. Do not present it as Google's E-E-A-T score, a ranking factor, or a proxy for numeric E-E-A-T weights.

Endpoint

Entities use POST https://language.googleapis.com/v1/documents:analyzeEntities. Sentiment, classification, and moderation use POST https://language.googleapis.com/v2/documents:annotateText.

Send the API key in the X-Goog-Api-Key header, not in the URL.

Features

Feature What It Does SEO Use
extractEntities Extract people, orgs, places, events with salience scores Topic coverage depth, entity optimization
extractDocumentSentiment Document + sentence-level sentiment score/magnitude Content tone assessment
classifyText Map content to 700+ Google categories Topic relevance verification
moderateText Content safety/moderation categories Content quality flags

Entity Types

PERSON, LOCATION, ORGANIZATION, EVENT, WORK_OF_ART, CONSUMER_GOOD, OTHER, PHONE_NUMBER, ADDRESS, DATE, NUMBER, PRICE

Each entity includes:

  • name: Entity text
  • type: Entity type
  • salience: Importance score (0-1, higher = more relevant)
  • sentiment: Per-entity sentiment (score + magnitude)
  • metadata: Wikipedia URL, MID (Knowledge Graph ID)
  • mentions: Occurrences in the text

Sentiment Scoring

  • Score: -1.0 (negative) to +1.0 (positive)
  • Magnitude: 0 to infinity (emotional intensity, higher = more emotional)
  • Neutral content: score ~0, low magnitude
  • Mixed content: score ~0, HIGH magnitude (both positive and negative)

Pricing

Feature Free/month Paid (per 1K chars)
Entity Analysis 5,000 units $0.001
Sentiment Analysis 5,000 units $0.001
Content Classification 30,000 units $0.002
Text Moderation 50,000 units $0.0005

One "unit" = 1,000 characters. Free tier resets monthly.

Enable the API

  1. Go to console.cloud.google.com/apis/library
  2. Search for "Cloud Natural Language API"
  3. Click Enable
  4. Billing must be enabled on the project (free tier still applies)

Uses the same API key as PSI/CrUX.

references/pagespeed-crux-api.md (verbatim)

PageSpeed Insights v5 + CrUX API Reference

Table of Contents

  1. PageSpeed Insights v5
  2. CrUX API (Daily)
  3. CrUX History API (Weekly)
  4. Core Web Vitals Thresholds

PageSpeed Insights v5

Endpoint: GET https://www.googleapis.com/pagespeedonline/v5/runPagespeed

Parameters

Param Type Description
url string Required. URL to analyze.
category string ACCESSIBILITY, BEST_PRACTICES, PERFORMANCE, SEO. Can specify multiple.
strategy string DESKTOP or MOBILE (default).
locale string Locale for text (e.g., en).
key string API key. Optional but recommended for quota.

Response Structure

{
  "id": "https://example.com/",
  "loadingExperience": { ... },        // URL-level CrUX data
  "originLoadingExperience": { ... },  // Origin-level CrUX data
  "lighthouseResult": {
    "categories": {
      "performance": { "score": 0.85 },
      "accessibility": { "score": 0.92 },
      "best-practices": { "score": 0.88 },
      "seo": { "score": 0.95 }
    },
    "audits": { ... }                  // Individual audit results
  },
  "analysisUTCTimestamp": "2026-03-27T..."
}

Field Data Metrics (in loadingExperience)

PSI Key CrUX Metric Unit
LARGEST_CONTENTFUL_PAINT_MS LCP ms
INTERACTION_TO_NEXT_PAINT INP ms
CUMULATIVE_LAYOUT_SHIFT_SCORE CLS unitless
FIRST_CONTENTFUL_PAINT_MS FCP ms
EXPERIMENTAL_TIME_TO_FIRST_BYTE TTFB ms

Each metric contains: percentile (p75), distributions[] ({min, max, proportion}), category (FAST/AVERAGE/SLOW/NONE).

Key Lighthouse Audit IDs

first-contentful-paint, largest-contentful-paint, total-blocking-time, cumulative-layout-shift, speed-index, interactive

Rate Limits

  • 25,000 QPD with API key
  • 240 QPM
  • Free, no billing required

Note on Field Data Migration

Google is migrating CrUX field data out of PSI. For field data, prefer the CrUX API directly. Use PSI primarily for Lighthouse lab data.


CrUX API (Daily)

Endpoint: POST https://chromeuxreport.googleapis.com/v1/records:queryRecord

Send the API key in the X-Goog-Api-Key header, not in the URL.

Request

{
  "origin": "https://example.com",
  "formFactor": "PHONE",
  "metrics": ["largest_contentful_paint", "interaction_to_next_paint", "cumulative_layout_shift"]
}
Field Description
origin Origin URL (mutually exclusive with url)
url Specific page URL (mutually exclusive with origin)
formFactor DESKTOP, PHONE, TABLET (optional, omit for all)
metrics Array of metric names (optional, omit for all)

Available Metrics

Metric Type Notes
largest_contentful_paint int (ms) Core Web Vital
largest_contentful_paint_resource_type fractions LCP resource type, added January 2025
largest_contentful_paint_image_time_to_first_byte int (ms) LCP image subpart, added January 2025
largest_contentful_paint_image_resource_load_delay int (ms) LCP image subpart, added January 2025
largest_contentful_paint_image_resource_load_duration int (ms) LCP image subpart, added January 2025
largest_contentful_paint_image_element_render_delay int (ms) LCP image subpart, added January 2025
interaction_to_next_paint int (ms) Core Web Vital (replaced FID)
cumulative_layout_shift string Core Web Vital. String-encoded! Parse carefully.
first_contentful_paint int (ms)
experimental_time_to_first_byte int (ms)
round_trip_time int (ms) Replaced effectiveConnectionType (Feb 2025)
navigation_types fractions navigate, navigate_cache, reload, etc.
form_factors fractions desktop/phone/tablet distribution

Response

{
  "record": {
    "key": { "origin": "https://example.com" },
    "metrics": {
      "largest_contentful_paint": {
        "histogram": [
          { "start": 0, "end": 2500, "density": 0.72 },
          { "start": 2500, "end": 4000, "density": 0.18 },
          { "start": 4000, "density": 0.10 }
        ],
        "percentiles": { "p75": 2100 }
      },
      "cumulative_layout_shift": {
        "percentiles": { "p75": "0.05" }
      }
    },
    "collectionPeriod": {
      "firstDate": { "year": 2026, "month": 2, "day": 27 },
      "lastDate": { "year": 2026, "month": 3, "day": 26 }
    }
  }
}

Important

  • CLS p75 is a string (e.g., "0.05" not 0.05). Always parse as float from string.
  • Last histogram bin has no end (extends to infinity).
  • Densities sum to approximately 1.0.
  • 404 = no data (insufficient Chrome traffic). Not an auth error.
  • Updated daily ~04:00 UTC with ~2 day lag.

Rate Limits

  • 150 QPM shared between CrUX and CrUX History APIs
  • Free, no paid increase available

CrUX History API (Weekly)

Endpoint: POST https://chromeuxreport.googleapis.com/v1/records:queryHistoryRecord

Send the API key in the X-Goog-Api-Key header, not in the URL.

Same request format as CrUX API. Returns up to 25 weekly collection periods.

Response Differences from CrUX API

Instead of single values, returns timeseries:

{
  "record": {
    "metrics": {
      "largest_contentful_paint": {
        "histogramTimeseries": [
          { "start": 0, "end": 2500, "densities": [0.70, 0.71, 0.72, ...] },
          { "start": 2500, "end": 4000, "densities": [0.19, 0.18, 0.18, ...] },
          { "start": 4000, "densities": [0.11, 0.11, 0.10, ...] }
        ],
        "percentilesTimeseries": {
          "p75s": [2200, 2150, 2100, ...]
        }
      }
    },
    "collectionPeriods": [
      {
        "firstDate": { "year": 2025, "month": 9, "day": 29 },
        "lastDate": { "year": 2025, "month": 10, "day": 26 }
      },
      ...
    ]
  }
}

NaN Handling

  • "NaN" string for densities in ineligible periods
  • null for percentile values in ineligible periods
  • Always check for these before numeric operations

Update Schedule

  • Updated Mondays ~04:00 UTC
  • Each period = 28-day rolling average ending on a Sunday

Core Web Vitals Thresholds

Current as of 2026-07-09; no threshold changes were announced. INP replaced FID on March 12, 2024.

Metric Good Needs Improvement Poor
LCP ≤ 2,500ms 2,500–4,000ms > 4,000ms
INP ≤ 200ms 200–500ms > 500ms
CLS ≤ 0.1 0.1–0.25 > 0.25
FCP ≤ 1,800ms 1,800–3,000ms > 3,000ms
TTFB ≤ 800ms 800–1,800ms > 1,800ms

FID was removed from Chrome's field-data tools (CrUX, PSI) on September 9, 2024. Never reference FID in outputs.

references/rate-limits-quotas.md (verbatim)

Google API Rate Limits & Quotas

Consolidated Quota Table

API Per-Minute Per-Day Cost Auth Type Scope
GSC Search Analytics 1,200 QPM/user, 1,200 QPM/site 30M QPD/project Free Service Account Per user + per site
GSC URL Inspection 600 QPM/site 2,000 QPD/site Free Service Account Per site
GSC Sitemaps Standard Standard Free Service Account Per site
PageSpeed Insights v5 240 QPM 25,000 QPD Free API Key Per project
CrUX API 150 QPM (shared) Unlimited Free API Key Per project
CrUX History API 150 QPM (shared with CrUX) Unlimited Free API Key Per project
Indexing API 380 RPM total, 180 read/min 200 publish/day Free Service Account Per project
GA4 Data API 10 concurrent ~25K tokens/day Free Service Account Per property/project
Knowledge Graph -- 100,000 QPD Free API Key Per project
Custom Search -- 10,000 QPD max 100 free, $5/1K API Key Per project
Web Risk 6,000 QPM 100K/month Free tier API Key Per project

Key distinction: "Per site" quotas are scoped to a specific GSC property. "Per project" quotas are shared across all properties in a GCP project. "Per user" quotas are per authenticated user (service account).

Exponential Backoff Strategy

When receiving 429 or 5xx errors:

Attempt 1: wait 1 second
Attempt 2: wait 2 seconds
Attempt 3: wait 4 seconds
Attempt 4: wait 8 seconds
Attempt 5: wait 16 seconds
Max: give up after 5 retries

Add random jitter (0-500ms) to each wait to avoid thundering herd.

Common Error Codes

Code Meaning Applies To Action
400 Bad request All Check URL format, request body
401 Unauthorized Service Account APIs Refresh credentials
403 Forbidden GSC, GA4, Indexing Check permissions (service account access)
404 Not found CrUX, GSC Insufficient traffic (CrUX) or invalid property (GSC)
429 Rate limited All Backoff and retry. Check Retry-After header.
500 Server error All Retry with backoff
503 Service unavailable All Retry with backoff

Retry-After Header

Some Google APIs return a Retry-After header with 429 responses. When present, use this value (in seconds) instead of exponential backoff.

GA4 Token Budgeting

GA4 uses a token system rather than simple request counts:

  • Simple 1-dimension, 1-metric report: ~1-5 tokens
  • Complex multi-dimension, multi-metric: ~10-100 tokens
  • Set returnPropertyQuota: true to monitor consumption
  • Daily limit: 25,000 tokens per property per project
  • Hourly limit: 5,000 tokens per property per project
  • Concurrent: max 10 simultaneous requests

CrUX Shared Quota

The CrUX API and CrUX History API share the same 150 QPM quota per project. Plan accordingly if querying both APIs in the same workflow.

Cost Summary

All APIs used by seo-google are free at normal usage levels. No billing is required for:

  • PSI, CrUX, CrUX History (API key, unlimited free)
  • GSC (service account, 30M QPD)
  • Indexing API (service account, 200 publish/day)
  • GA4 Data API (service account, 25K tokens/day)
  • Knowledge Graph (API key, 100K QPD)

Only Custom Search and Web Risk have paid tiers at high volumes.

references/supplementary-apis.md (verbatim)

Supplementary Google APIs for SEO

Knowledge Graph Search API

Verify brand/entity presence in Google's Knowledge Graph.

Endpoint: GET https://kgsearch.googleapis.com/v1/entities:search

Param Description
query Search query
ids Specific entity IDs (e.g., /m/0d6lp)
languages Language codes (e.g., en)
types Schema.org types to filter (e.g., Organization, Person)
limit Max results (1-500)
key API key (required)

Response:

{
  "itemListElement": [{
    "result": {
      "@id": "kg:/m/0d6lp",
      "name": "Google",
      "@type": ["Organization", "Corporation"],
      "description": "Technology company",
      "detailedDescription": {
        "articleBody": "Google LLC is an American...",
        "url": "https://en.wikipedia.org/wiki/Google"
      },
      "image": { "url": "..." },
      "url": "https://www.google.com"
    },
    "resultScore": 4892.5
  }]
}

Use for SEO: Verify if a brand has a Knowledge Panel, check entity disambiguation, find related entities.

Quota: 100,000 reads/day. Free. API key only.


Custom Search JSON API

Programmatic Google search results (limited).

Endpoint: GET https://customsearch.googleapis.com/customsearch/v1

Param Description
key API key (required)
cx Programmable Search Engine ID (required)
q Search query
num Results per page (1-10)
start Start index (max 91)
dateRestrict Date restriction (e.g., d30 for 30 days)
gl Country (e.g., us)
lr Language restriction
searchType image for image search
siteSearch Restrict to a domain

Limitations:

  • Max 100 total results per query (10 pages x 10 results)
  • CLOSED to new customers as of 2025. Existing customers must migrate by January 2027.
  • 100 queries/day free, $5 per 1,000 up to 10,000/day

For SERP data, prefer DataForSEO (/seo dataforseo serp) which has no such limitations.


Web Risk API

Check if URLs are flagged as unsafe by Google Safe Browsing.

Endpoint: GET https://webrisk.googleapis.com/v1/uris:search

Param Description
threatTypes MALWARE, SOCIAL_ENGINEERING, UNWANTED_SOFTWARE, SOCIAL_ENGINEERING_EXTENDED_COVERAGE
uri URL to check
key API key (required)

Response (clean URL): Empty threat object.

Response (flagged URL):

{
  "threat": {
    "threatTypes": ["MALWARE"],
    "expireTime": "2026-04-01T00:00:00Z"
  }
}

Use for SEO: Check if pages are flagged (could explain deindexing), verify competitor safety, audit outbound links.

Quota: 6,000 QPM. 100,000/month free tier. Requires billing enabled on GCP project.

Back to seo skill (claude-seo: 25 sub-skills, 18 sub-agents) or Agent skills.