Marketing Foundation
Compact two-skill starter: clarify positioning and choose a lead magnet. Use Marketing Launch for the broader eight-skill go-to-market workflow.
The tunnel uses the same cards as the catalogue. Browse only as deep as needed — or load a broad bundle immediately.
SEO, Sales, Agents or another broad area → one bundle call → work.
Read-only access to published skills. Default 8, maximum 10 skills / 120,000 characters.
Compact two-skill starter: clarify positioning and choose a lead magnet. Use Marketing Launch for the broader eight-skill go-to-market workflow.
Build an evidence-led marketing plan from ICP and competition through positioning, campaigns, growth and measurement.
Diagnose architecture and context, plan agent-team responsibilities, then organize project context and session handoffs. Memory and cost-runtime reviews remain outside this pack.
Review the journey from landing page and lead capture through registration, first value and transparent upgrades.
Plan a campaign, draft its channel content and review the work against actual brand guidance.
Prioritize an editorial roadmap and plan how to launch and distribute it across suitable channels.
Understand customer needs, compare competitors and plan a community around real member value.
Choose a relevant lead magnet, then draft a permission-based nurture journey with entry, suppression and exit rules.
Define the API contract, then plan how to observe its latency, failures and retries. Guidance and checklist; no production changes.
Profile a dataset, choose and interpret statistical methods, then validate calculations and conclusions before sharing.
Define the target account, prioritize buying signals, plan a human LinkedIn engagement routine and prepare evidence-led responses to buyer concerns.
Plans Search Console analysis and operational decisions without OAuth or property changes.
---
name: search-console
description: >
Pull Google Search Console data and perform search performance analysis.
Use when asked about search rankings, clicks, impressions, CTR, index coverage,
Core Web Vitals, or sitemap status. Trigger phrases: "search console", "GSC",
"search performance", "clicks and impressions", "CTR analysis", "index coverage",
"core web vitals", "URL inspection", "sitemap status", "ranking data",
"search queries", "keyword positions".
---
# 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
```bash
# 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
```bash
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
```bash
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
```bash
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
```bash
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
| Dimension | Description |
|-----------|-------------|
| `query` | Search query |
| `page` | URL |
| `country` | Country code (ISO 3166-1 alpha-3) |
| `device` | `DESKTOP`, `MOBILE`, `TABLET` |
| `date` | Individual date |
| `searchAppearance` | Rich result type |
### Response Parsing
```bash
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.
```bash
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:
```bash
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
```bash
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
| Field | Description |
|-------|-------------|
| `inspectionResult.indexStatusResult.coverageState` | `Submitted and indexed`, `Crawled - currently not indexed`, etc. |
| `inspectionResult.indexStatusResult.robotsTxtState` | `ALLOWED` or `DISALLOWED` |
| `inspectionResult.indexStatusResult.indexingState` | `INDEXING_ALLOWED` or `INDEXING_NOT_ALLOWED` |
| `inspectionResult.indexStatusResult.lastCrawlTime` | When Googlebot last crawled |
| `inspectionResult.indexStatusResult.crawledAs` | `DESKTOP` or `MOBILE` |
| `inspectionResult.mobileUsabilityResult.verdict` | `PASS`, `FAIL`, or `VERDICT_UNSPECIFIED` |
---
## 4. Sitemaps
List and check sitemap status.
### List Sitemaps
```bash
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
```bash
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.
```bash
# 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:
print(f\"{row['keys'][0]:<40} {row['keys'][1][-40:]:<40} {row['impressions']:>6} {row['ctr']*100:>6.1f}% {row['position']:>5.1f}\")
"
```
### Striking Distance: Position 5-20
Queries ranking on page 1-2 that could be pushed to top 5 with content optimization.
```bash
# Filter for position between 5 and 20 with decent impressions
curl -s -X POST "..." | python3 -c "
import json, sys
data = json.load(sys.stdin)
print('== Striking Distance Keywords (Position 5-20) ==')
opps = [r for r in data.get('rows',[]) if 5 <= r['position'] <= 20 and r['impressions'] > 50]
opps.sort(key=lambda x: x['impressions'], reverse=True)
for row in opps[:30]:
print(f\"{row['keys'][0]:<50} Pos: {row['position']:>5.1f} Impr: {row['impressions']:>6} Clicks: {row['clicks']:>4}\")
"
```
### Cannibalization Detection
Find queries where multiple pages compete for the same keyword.
```bash
# Pull query+page data, then group by query to find duplicates
curl -s -X POST "..." | python3 -c "
import json, sys
from collections import defaultdict
data = json.load(sys.stdin)
query_pages = defaultdict(list)
for row in data.get('rows', []):
query_pages[row['keys'][0]].append({
'page': row['keys'][1],
'clicks': row['clicks'],
'impressions': row['impressions'],
'position': row['position']
})
print('== Keyword Cannibalization (multiple pages for same query) ==')
for query, pages in sorted(query_pages.items(), key=lambda x: -sum(p['impressions'] for p in x[1])):
if len(pages) > 1:
total_impr = sum(p['impressions'] for p in pages)
if total_impr > 100:
print(f\"\nQuery: {query} ({total_impr} total impressions)\")
for p in sorted(pages, key=lambda x: -x['impressions']):
print(f\" {p['page'][-60:]} Pos: {p['position']:.1f} Impr: {p['impressions']} Clicks: {p['clicks']}\")
"
```
---
## Workflow: Full Search Performance Audit
When asked for a complete GSC audit:
1. **Overall Metrics**: Total clicks, impressions, avg CTR, avg position for last 90 days vs previous 90 days
2. **Top 30 Queries**: By clicks, with CTR and position
3. **Top 20 Pages**: By clicks, with CTR and position
4. **Device Breakdown**: Desktop vs mobile performance
5. **Low-Hanging Fruit**: High impressions + low CTR opportunities
6. **Striking Distance**: Position 5-20 keywords with optimization potential
7. **Cannibalization**: Queries with multiple competing pages
8. **Index Coverage**: Spot-check important URLs
9. **Sitemap Health**: Verify sitemaps are submitted and indexed
### Report Format
```
## Search Console Audit: {domain}
### Period: {date range}
### Summary
| Metric | Current | Previous | Change |
|--------|---------|----------|--------|
| Clicks | X | Y | +Z% |
| Impressions | X | Y | +Z% |
| Avg CTR | X% | Y% | +Z pp |
| Avg Position | X | Y | +Z |
### Top Queries
| Query | Clicks | Impressions | CTR | Position |
|-------|--------|-------------|-----|----------|
| ... | ... | ... | ... | ... |
### Optimization Opportunities
#### Title/Description Optimization (High Impressions, Low CTR)
1. "{query}" - {impressions} impressions, {ctr}% CTR, position {pos}
- Page: {url}
- Recommendation: ...
#### Content Optimization (Striking Distance)
1. "{query}" - position {pos}, {impressions} impressions
- Action: Add {query} to H2, expand section on {topic}
#### Cannibalization Fixes
1. "{query}" appears on {n} pages
- Consolidate to: {best_url}
- Redirect/noindex: {other_urls}
```
---
## Rate Limits
- Search Analytics API: 1,200 queries per minute
- URL Inspection API: 2,000 inspections per day per property
- Data freshness: Search data is typically 2-3 days behind
## Common Errors
| Error | Cause | Fix |
|-------|-------|-----|
| 403 | No access to this property | Verify ownership in GSC |
| 400 | Invalid date range | Dates must be within last 16 months |
| Empty rows | No data matching filters | Broaden date range or remove filters |
Plans Search Console analysis and operational decisions without OAuth or property changes.
The complete original guide with source attribution and explicit delivery limits.
Clarify evidence and scope, apply the method as planning guidance, then separate recommendations from any authorized external action.
Task context, user-supplied or authorized evidence, constraints and an accountable owner for any external work.
Original documentation is published under the repository MIT license at the pinned revision. It is reference guidance only. Referenced API keys, OAuth tokens, environment files, CLIs, scripts, runtimes and third-party services are not available, read or executed. Loading this source does not authorize credential use, external requests, account changes, content publication, messages, payment, deployment, installation or script execution.
Use Google Search Console Operations for [TASK]. Establish the evidence, permissions and constraints first. Return a bounded, reviewable plan with assumptions and open questions. Do not use credentials, call services or perform external actions.
Reading credentials, issuing API calls, installing tools, publishing content or making account changes.
M11 added German routing, source integrity and runtime boundaries. Original documentation is published under the repository MIT license at the pinned revision. It is reference guidance only. Referenced API keys, OAuth tokens, environment files, CLIs, scripts, runtimes and third-party services are not available, read or executed. Loading this source does not authorize credential use, external requests, account changes, content publication, messages, payment, deployment, installation or script execution.
MIT License Copyright (c) 2026 OpenClaudia Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copy the text below, then paste it into your chat.