optbrew 0.0.0-stage → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +6 -0
- package/.claude-plugin/plugin.json +6 -0
- package/.codex-plugin/plugin.json +13 -0
- package/CHANGELOG.md +50 -0
- package/LICENSE +21 -0
- package/README.ko.md +149 -0
- package/README.md +148 -2
- package/THIRD_PARTY_NOTICES.md +10 -0
- package/bin/optbrew.mjs +4 -0
- package/docs/platforms.md +107 -0
- package/docs/release.md +14 -0
- package/lib/cli.mjs +116 -0
- package/lib/doctor.mjs +45 -0
- package/lib/install.mjs +158 -0
- package/lib/paths.mjs +30 -0
- package/lib/records.mjs +44 -0
- package/lib/reinstall.mjs +92 -0
- package/lib/transaction.mjs +205 -0
- package/lib/update.mjs +189 -0
- package/package.json +39 -4
- package/plugin.json +13 -0
- package/skills/optbrew/LICENSE +21 -0
- package/skills/optbrew/SKILL.md +17 -0
- package/skills/optbrew/THIRD_PARTY_NOTICES.md +10 -0
- package/skills/optbrew/agents/openai.yaml +4 -0
- package/skills/optbrew/bundle-manifest.json +687 -0
- package/skills/optbrew/licenses/firecrawl-seo-audit.txt +15 -0
- package/skills/optbrew/licenses/magnus-seo.txt +21 -0
- package/skills/optbrew/licenses/marketing-search.txt +21 -0
- package/skills/optbrew/licenses/mblode-seo.txt +21 -0
- package/skills/optbrew/licenses/naver-searchadvisor.txt +29 -0
- package/skills/optbrew/licenses/seranking-seo.txt +21 -0
- package/skills/optbrew/modules/firecrawl-seo-audit/GUIDE.md +64 -0
- package/skills/optbrew/modules/magnus-seo/GUIDE.md +79 -0
- package/skills/optbrew/modules/magnus-seo/README.md +45 -0
- package/skills/optbrew/modules/magnus-seo/assets/audit-report-template.md +76 -0
- package/skills/optbrew/modules/magnus-seo/references/aeo-methodology.md +105 -0
- package/skills/optbrew/modules/magnus-seo/references/agent-readable-content.md +28 -0
- package/skills/optbrew/modules/magnus-seo/references/content-and-entity-architecture.md +100 -0
- package/skills/optbrew/modules/magnus-seo/references/content-strategy-seo.md +142 -0
- package/skills/optbrew/modules/magnus-seo/references/discovery-and-freshness.md +47 -0
- package/skills/optbrew/modules/magnus-seo/references/evidence-boundaries.md +75 -0
- package/skills/optbrew/modules/magnus-seo/references/ghost-metadata.md +204 -0
- package/skills/optbrew/modules/magnus-seo/references/implementation-playbook.md +114 -0
- package/skills/optbrew/modules/magnus-seo/references/measurement-and-experimentation.md +47 -0
- package/skills/optbrew/modules/magnus-seo/references/onpage-seo.md +154 -0
- package/skills/optbrew/modules/magnus-seo/references/platform-guidance.md +30 -0
- package/skills/optbrew/modules/magnus-seo/references/schema-markup.md +244 -0
- package/skills/optbrew/modules/magnus-seo/references/source-index.md +36 -0
- package/skills/optbrew/modules/magnus-seo/references/structured-data.md +56 -0
- package/skills/optbrew/modules/magnus-seo/references/technical-seo.md +99 -0
- package/skills/optbrew/modules/magnus-seo/scripts/aeo_audit.py +158 -0
- package/skills/optbrew/modules/magnus-seo/scripts/build_prompt_matrix.py +52 -0
- package/skills/optbrew/modules/magnus-seo/templates/aeo-implementation-plan.md +53 -0
- package/skills/optbrew/modules/magnus-seo/templates/citation-observation-log.md +16 -0
- package/skills/optbrew/modules/magnus-seo/templates/llms.txt.template +15 -0
- package/skills/optbrew/modules/magnus-seo/templates/question-cluster.md +27 -0
- package/skills/optbrew/modules/magnus-seo/templates/robots-ai-crawlers.txt +23 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/GUIDE.md +483 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/agent-readiness.md +57 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/citations-vs-recommendations.md +85 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/content-patterns.md +287 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/content-types.md +71 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/format-volatility.md +98 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/okf.md +104 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/platform-ranking-factors.md +154 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/youtube-ai-citations.md +60 -0
- package/skills/optbrew/modules/marketing-search/skills/analytics/GUIDE.md +303 -0
- package/skills/optbrew/modules/marketing-search/skills/analytics/references/event-library.md +260 -0
- package/skills/optbrew/modules/marketing-search/skills/analytics/references/ga4-implementation.md +300 -0
- package/skills/optbrew/modules/marketing-search/skills/analytics/references/gtm-implementation.md +390 -0
- package/skills/optbrew/modules/marketing-search/skills/content-strategy/GUIDE.md +432 -0
- package/skills/optbrew/modules/marketing-search/skills/content-strategy/references/content-distribution.md +83 -0
- package/skills/optbrew/modules/marketing-search/skills/content-strategy/references/headless-cms.md +194 -0
- package/skills/optbrew/modules/marketing-search/skills/programmatic-seo/GUIDE.md +231 -0
- package/skills/optbrew/modules/marketing-search/skills/programmatic-seo/references/playbooks.md +308 -0
- package/skills/optbrew/modules/marketing-search/skills/schema/GUIDE.md +172 -0
- package/skills/optbrew/modules/marketing-search/skills/schema/references/schema-examples.md +398 -0
- package/skills/optbrew/modules/marketing-search/skills/seo-audit/GUIDE.md +492 -0
- package/skills/optbrew/modules/marketing-search/skills/seo-audit/references/ai-writing-detection.md +200 -0
- package/skills/optbrew/modules/marketing-search/skills/seo-audit/references/international-seo.md +230 -0
- package/skills/optbrew/modules/marketing-search/skills/site-architecture/GUIDE.md +350 -0
- package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/mermaid-templates.md +216 -0
- package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/navigation-patterns.md +305 -0
- package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/site-type-templates.md +293 -0
- package/skills/optbrew/modules/mblode-seo/GUIDE.md +74 -0
- package/skills/optbrew/modules/mblode-seo/references/answer-engines.md +58 -0
- package/skills/optbrew/modules/mblode-seo/references/audit.md +78 -0
- package/skills/optbrew/modules/mblode-seo/references/brief-template.md +47 -0
- package/skills/optbrew/modules/mblode-seo/references/monitoring.md +56 -0
- package/skills/optbrew/modules/mblode-seo/references/nextjs-implementation.md +65 -0
- package/skills/optbrew/modules/mblode-seo/references/research-protocol.md +37 -0
- package/skills/optbrew/modules/mblode-seo/references/sources.md +47 -0
- package/skills/optbrew/modules/mblode-seo/references/validation-evidence.md +21 -0
- package/skills/optbrew/modules/naver-searchadvisor/GUIDE.md +75 -0
- package/skills/optbrew/modules/naver-searchadvisor/NOTICE.md +59 -0
- package/skills/optbrew/modules/naver-searchadvisor/references/INDEX.md +97 -0
- package/skills/optbrew/modules/naver-searchadvisor/scripts/audit.mjs +742 -0
- package/skills/optbrew/modules/naver-searchadvisor/scripts/robots.mjs +77 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-ai-search-share-of-voice/GUIDE.md +94 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-api/GUIDE.md +186 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/api-surface-map.md +207 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/auth-and-keys.md +182 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/integration-patterns.md +283 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/rate-limits-and-credits.md +235 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-competitor-gap-analysis/GUIDE.md +117 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/GUIDE.md +155 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/references/cite.md +84 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/references/core-eeat.md +147 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/templates/verdict.md +63 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-firecrawl/GUIDE.md +141 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-firecrawl/references/preflight.md +73 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-geo/GUIDE.md +159 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/GUIDE.md +393 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/cwv-audit-report.md +48 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/gsc-performance-report.md +44 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/indexation-status-report.md +43 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/auth-setup.md +160 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/cross-skill-integration.md +187 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/ga4-data-api.md +184 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/indexing-api.md +109 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/keyword-planner-api.md +66 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/nlp-api.md +55 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/pagespeed-crux-api.md +204 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/rate-limits-quotas.md +75 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/search-console-api.md +156 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/supplementary-apis.md +99 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/youtube-api.md +49 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-keyword-niche/GUIDE.md +174 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-page/GUIDE.md +174 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-plan/GUIDE.md +220 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/GUIDE.md +135 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/references/google-rich-results.md +89 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/article.json +23 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/breadcrumb-list.json +18 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/faq-page.json +22 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/local-business.json +32 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/product.json +25 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-sitemap/GUIDE.md +128 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-technical-audit/GUIDE.md +235 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-technical-audit/references/severity-mapping.md +133 -0
- package/skills/optbrew/references/ai-crawlers.json +21 -0
- package/skills/optbrew/references/ai-crawlers.md +24 -0
- package/skills/optbrew/references/api.md +45 -0
- package/skills/optbrew/references/check-registry.json +28 -0
- package/skills/optbrew/references/evidence.md +9 -0
- package/skills/optbrew/references/intake.md +9 -0
- package/skills/optbrew/references/measurement.md +29 -0
- package/skills/optbrew/references/policies.md +7 -0
- package/skills/optbrew/references/profiles.json +13 -0
- package/skills/optbrew/references/remediations.json +12 -0
- package/skills/optbrew/references/report.md +29 -0
- package/skills/optbrew/references/routing.md +15 -0
- package/skills/optbrew/references/schemas/contract.schema.json +51 -0
- package/skills/optbrew/references/scoring.md +62 -0
- package/skills/optbrew/scripts/adapters/anthropic.mjs +116 -0
- package/skills/optbrew/scripts/adapters/imports.mjs +81 -0
- package/skills/optbrew/scripts/audit.mjs +124 -0
- package/skills/optbrew/scripts/cli.mjs +41 -0
- package/skills/optbrew/scripts/core/bootstrap.mjs +31 -0
- package/skills/optbrew/scripts/core/bundle.mjs +73 -0
- package/skills/optbrew/scripts/core/capabilities.mjs +19 -0
- package/skills/optbrew/scripts/core/collector.mjs +250 -0
- package/skills/optbrew/scripts/core/compare.mjs +47 -0
- package/skills/optbrew/scripts/core/contracts.mjs +144 -0
- package/skills/optbrew/scripts/core/cost-ledger.mjs +95 -0
- package/skills/optbrew/scripts/core/crawlers.mjs +11 -0
- package/skills/optbrew/scripts/core/derive.mjs +168 -0
- package/skills/optbrew/scripts/core/facts.mjs +189 -0
- package/skills/optbrew/scripts/core/findings.mjs +54 -0
- package/skills/optbrew/scripts/core/html.mjs +53 -0
- package/skills/optbrew/scripts/core/metrics.mjs +97 -0
- package/skills/optbrew/scripts/core/protocol.mjs +125 -0
- package/skills/optbrew/scripts/core/report.mjs +742 -0
- package/skills/optbrew/scripts/core/scope.mjs +52 -0
- package/skills/optbrew/scripts/core/score.mjs +71 -0
- package/skills/optbrew/scripts/core/weights.mjs +139 -0
- package/skills/optbrew/source-lock.json +2686 -0
- package/source-lock.json +2686 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Google API Authentication Setup
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Three credential types serve different APIs:
|
|
6
|
+
|
|
7
|
+
| Type | Used By | Cost |
|
|
8
|
+
|------|---------|------|
|
|
9
|
+
| **API Key** | PageSpeed Insights, CrUX, CrUX History, Knowledge Graph, YouTube, NLP, Web Risk | Free |
|
|
10
|
+
| **Service Account** | Search Console, Indexing API, GA4 | Free |
|
|
11
|
+
| **Google Ads developer token** | Keyword Planner (volumes / suggestions) | Free (token approval ~24h) |
|
|
12
|
+
| **Both** | Full seo-google skill | Free |
|
|
13
|
+
|
|
14
|
+
## Step 1: Create a Google Cloud Project
|
|
15
|
+
|
|
16
|
+
1. Go to [console.cloud.google.com](https://console.cloud.google.com)
|
|
17
|
+
2. Click **Select a project** > **New Project**
|
|
18
|
+
3. Name it (e.g., "Claude SEO") and note the project ID
|
|
19
|
+
4. Select the project after creation
|
|
20
|
+
|
|
21
|
+
## Step 2: Enable APIs
|
|
22
|
+
|
|
23
|
+
Navigate to **APIs & Services > Library** and enable:
|
|
24
|
+
|
|
25
|
+
| API | Required For |
|
|
26
|
+
|-----|-------------|
|
|
27
|
+
| Google Search Console API | GSC Search Analytics, URL Inspection, Sitemaps |
|
|
28
|
+
| PageSpeed Insights API | PSI Lighthouse lab data |
|
|
29
|
+
| Chrome UX Report API | CrUX field data + History |
|
|
30
|
+
| Web Search Indexing API | Indexing API v3 |
|
|
31
|
+
| Google Analytics Data API | GA4 organic traffic |
|
|
32
|
+
| Google Analytics Admin API | `ga4-properties` (account/property discovery) |
|
|
33
|
+
| Knowledge Graph Search API | Entity verification |
|
|
34
|
+
| YouTube Data API v3 | `youtube` / `youtube-video` commands |
|
|
35
|
+
| Cloud Natural Language API | `nlp` / `entities` commands |
|
|
36
|
+
| Web Risk API | `safety` command (malware / social-engineering check) |
|
|
37
|
+
| Google Ads API | `keywords` / `volume` commands (also requires a Google Ads developer token — see [`keyword-planner-api.md`](keyword-planner-api.md)) |
|
|
38
|
+
|
|
39
|
+
## Step 3: Create an API Key
|
|
40
|
+
|
|
41
|
+
1. **APIs & Services > Credentials > Create Credentials > API key**
|
|
42
|
+
2. Click **Restrict key**:
|
|
43
|
+
- Under **API restrictions**, select: PageSpeed Insights API, Chrome UX Report API, Knowledge Graph Search API, YouTube Data API v3, Cloud Natural Language API, Web Risk API
|
|
44
|
+
3. Copy the key (starts with `AIzaSy...`)
|
|
45
|
+
|
|
46
|
+
## Step 4: Create a Service Account
|
|
47
|
+
|
|
48
|
+
1. **IAM & Admin > Service Accounts > Create Service Account**
|
|
49
|
+
2. Name: `seo-skills` (or similar)
|
|
50
|
+
3. Skip optional permissions steps
|
|
51
|
+
4. Click on the created service account > **Keys > Add Key > Create new key > JSON**
|
|
52
|
+
5. Download the JSON file and store it securely (e.g., `~/.config/seo-skills/service_account.json`)
|
|
53
|
+
|
|
54
|
+
The JSON file looks like:
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"type": "service_account",
|
|
58
|
+
"project_id": "your-project-id",
|
|
59
|
+
"private_key_id": "...",
|
|
60
|
+
"private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
|
|
61
|
+
"client_email": "seo-skills@your-project.iam.gserviceaccount.com",
|
|
62
|
+
"client_id": "...",
|
|
63
|
+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
|
64
|
+
"token_uri": "https://oauth2.googleapis.com/token"
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The `client_email` field is what you add to GSC and GA4.
|
|
69
|
+
|
|
70
|
+
## Step 5: Grant Search Console Access
|
|
71
|
+
|
|
72
|
+
1. Go to [Google Search Console](https://search.google.com/search-console)
|
|
73
|
+
2. Select your property
|
|
74
|
+
3. **Settings > Users and permissions > Add user**
|
|
75
|
+
4. Paste the service account `client_email`
|
|
76
|
+
5. Set permission level:
|
|
77
|
+
- **Full** for read-only (Search Analytics, URL Inspection, Sitemaps)
|
|
78
|
+
- **Owner** if you also need the Indexing API
|
|
79
|
+
|
|
80
|
+
## Step 6: Grant GA4 Access
|
|
81
|
+
|
|
82
|
+
1. Go to [Google Analytics](https://analytics.google.com)
|
|
83
|
+
2. **Admin > Property Access Management > Add users** (the + icon)
|
|
84
|
+
3. Paste the service account `client_email`
|
|
85
|
+
4. Set role: **Viewer** (minimum for read-only reporting)
|
|
86
|
+
5. Note the numeric property ID from **Admin > Property Details** (e.g., `123456789`)
|
|
87
|
+
|
|
88
|
+
## Step 7: Create Config File
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
mkdir -p ~/.config/seo-skills
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Save to `~/.config/seo-skills/google-api.json`:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"service_account_path": "~/.config/seo-skills/service_account.json",
|
|
99
|
+
"api_key": "AIzaSy...",
|
|
100
|
+
"default_property": "sc-domain:example.com",
|
|
101
|
+
"ga4_property_id": "properties/123456789"
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Property URL Formats
|
|
106
|
+
|
|
107
|
+
| Format | Example | When to Use |
|
|
108
|
+
|--------|---------|-------------|
|
|
109
|
+
| Domain property | `sc-domain:example.com` | Covers all URLs on the domain (recommended) |
|
|
110
|
+
| URL-prefix property | `https://example.com/` | Covers only that specific prefix |
|
|
111
|
+
|
|
112
|
+
## Step 8: Verify Setup
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
upstream script excluded; use optbrew capability routing
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Expected output at Tier 2 (full):
|
|
119
|
+
```
|
|
120
|
+
Credential Tier: 2 -- Full (API key + Service Account + GA4)
|
|
121
|
+
|
|
122
|
+
[OK] PageSpeed Insights v5
|
|
123
|
+
[OK] Chrome UX Report (CrUX) API
|
|
124
|
+
[OK] CrUX History API
|
|
125
|
+
[OK] Google Search Console API
|
|
126
|
+
Service account: seo-skills@your-project.iam.gserviceaccount.com
|
|
127
|
+
[OK] Google Indexing API v3
|
|
128
|
+
[OK] GA4 Data API v1beta
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Environment Variable Alternatives
|
|
132
|
+
|
|
133
|
+
Instead of (or in addition to) the config file:
|
|
134
|
+
|
|
135
|
+
| Variable | Purpose |
|
|
136
|
+
|----------|---------|
|
|
137
|
+
| `GOOGLE_API_KEY` | API key for PSI/CrUX |
|
|
138
|
+
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to service account JSON |
|
|
139
|
+
| `GA4_PROPERTY_ID` | GA4 property (e.g., `properties/123456789`) |
|
|
140
|
+
| `GSC_PROPERTY` | Default GSC property (e.g., `sc-domain:example.com`) |
|
|
141
|
+
|
|
142
|
+
## OAuth Scopes Used
|
|
143
|
+
|
|
144
|
+
| Scope | APIs |
|
|
145
|
+
|-------|------|
|
|
146
|
+
| `https://www.googleapis.com/auth/webmasters.readonly` | GSC (read) |
|
|
147
|
+
| `https://www.googleapis.com/auth/webmasters` | GSC (read/write, needed for sitemap submission) |
|
|
148
|
+
| `https://www.googleapis.com/auth/indexing` | Indexing API |
|
|
149
|
+
| `https://www.googleapis.com/auth/analytics.readonly` | GA4 (read) |
|
|
150
|
+
|
|
151
|
+
## Troubleshooting
|
|
152
|
+
|
|
153
|
+
| Error | Fix |
|
|
154
|
+
|-------|-----|
|
|
155
|
+
| `403 Forbidden` on GSC | Service account email not added to GSC property, or wrong permission level |
|
|
156
|
+
| `403 Forbidden` on GA4 | Service account email not added to GA4 property as Viewer |
|
|
157
|
+
| `404 Not Found` on GSC | Wrong property URL format. Use `sc-domain:` or include trailing slash for URL-prefix |
|
|
158
|
+
| `404 Not Found` on CrUX | Site has insufficient Chrome traffic. Not a credentials issue. |
|
|
159
|
+
| `429 Rate Limit` | Wait and retry. See rate-limits-quotas.md for per-API limits |
|
|
160
|
+
| `API not enabled` | Enable the specific API in GCP Console > APIs & Services > Library |
|
package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/cross-skill-integration.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Cross-skill integration: enriching other skills with real Google field data
|
|
2
|
+
|
|
3
|
+
This file is the contract other skills follow to enrich their deliverables with Google-API field data **without** spawning the full `seo-google` skill. Each enrichment is a single Python script call that returns JSON; the calling skill parses it and folds the data into its primary deliverable.
|
|
4
|
+
|
|
5
|
+
The pattern was adapted from `AgriciDaniel/claude-seo`'s wiring across `seo-audit`, `seo-technical`, and `seo-drift`. Config path is namespaced to `~/.config/seo-skills/` so the two plugins coexist cleanly.
|
|
6
|
+
|
|
7
|
+
## Trigger pattern (every enrichment-aware skill)
|
|
8
|
+
|
|
9
|
+
Add this near the top of the skill's Process steps, immediately after the existing preflight (credit balance / Firecrawl detection):
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
**Google data availability check.** Run `upstream script excluded; use optbrew capability routing`
|
|
13
|
+
and parse the result. If `tier >= 0` (any creds present), Google enrichment runs in step
|
|
14
|
+
N (see below). If `tier == -1` or the file is missing, the skill proceeds without
|
|
15
|
+
Google enrichment and notes "Google field data: not configured (run `optbrew capability setup (see top-level routing)`)" in the deliverable.
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The `google_auth.py --check --json` output shape:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"tier": 1,
|
|
23
|
+
"available": ["pagespeed", "crux", "crux-history", "gsc", "inspect", "sitemaps", "index"],
|
|
24
|
+
"missing": ["ga4", "ga4-pages", "keywords", "volume"],
|
|
25
|
+
"config_path": "/Users/.../.config/seo-skills/google-api.json"
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The skill should branch on `available`. Each enrichment lists its required entry below.
|
|
30
|
+
|
|
31
|
+
## Per-skill enrichment recipes
|
|
32
|
+
|
|
33
|
+
### `seo-technical-audit` — CrUX field data + per-URL Inspection (Tier 0 + Tier 1)
|
|
34
|
+
|
|
35
|
+
Replaces the audit's lab-only CWV with actual Chrome user metrics from CrUX, and adds per-URL indexation reality from GSC URL Inspection.
|
|
36
|
+
|
|
37
|
+
**Step 8b — CrUX (Tier 0):**
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Domain-level CrUX (origin)
|
|
41
|
+
upstream script excluded; use optbrew capability routing "https://{domain}" --crux-only --json
|
|
42
|
+
|
|
43
|
+
# 25-week trend (catches degradation we'd otherwise miss until next month's audit)
|
|
44
|
+
upstream script excluded; use optbrew capability routing "https://{domain}" --origin --json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Surface in `TECH-AUDIT.md` as "## Core Web Vitals (field data)" with p75 LCP / INP / CLS, source label "CrUX 28-day origin", and the 25-week trend direction.
|
|
48
|
+
|
|
49
|
+
If CrUX has no field data for the origin (low-traffic site), surface "CrUX: insufficient data for {domain}" and continue.
|
|
50
|
+
|
|
51
|
+
**Step 8c — Per-URL Inspection (Tier 1, mirrors theirs at `seo-technical/GUIDE.md:164`):**
|
|
52
|
+
|
|
53
|
+
For each of the top 5 traffic URLs from step 5 (or homepage + key landing pages):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
upstream script excluded; use optbrew capability routing "{url}" --site-url "{config.default_property}" --json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Capture `indexStatusVerdict`, `coverageState`, `googleCanonical` vs `userCanonical`, and `lastCrawlTime`.
|
|
60
|
+
|
|
61
|
+
Cross-check against the audit's noindex / canonical findings:
|
|
62
|
+
- GSC says `INDEXED` but audit flagged `noindex` → audit is stale, flag for re-audit.
|
|
63
|
+
- GSC says `EXCLUDED` for a "healthy" page → hidden indexability issue invisible to SE Ranking's audit.
|
|
64
|
+
- `userCanonical ≠ googleCanonical` on a top-traffic page → elevated to Critical in the Top-10 fix list regardless of `severity-mapping.md` defaults.
|
|
65
|
+
|
|
66
|
+
Surface in `TECH-AUDIT.md` as "## Indexation reality check (GSC URL Inspection)" with one row per URL.
|
|
67
|
+
|
|
68
|
+
If property not verified in this account: "GSC: {domain} not verified — add it in Search Console" and skip 8c only (8b still runs).
|
|
69
|
+
|
|
70
|
+
### `seo-page` — GSC URL performance + URL Inspection (Tier 1 — `gsc`, `inspect` available)
|
|
71
|
+
|
|
72
|
+
Replaces inferred-from-SE-Ranking traffic with first-party Google data for the target URL.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# GSC search analytics for the URL (requires default_property in config to be set
|
|
76
|
+
# to a verified property that owns this URL — sc-domain:example.com)
|
|
77
|
+
upstream script excluded; use optbrew capability routing "{config.default_property}" --url "{target_url}" --days 28 --json
|
|
78
|
+
|
|
79
|
+
# URL Inspection (real indexation status, canonical Google sees, last crawl date)
|
|
80
|
+
upstream script excluded; use optbrew capability routing "{target_url}" --site-url "{config.default_property}" --json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Surface in `PAGE.md` "## Snapshot" as new rows:
|
|
84
|
+
- GSC last 28d: `{clicks} clicks / {impressions} impressions / {ctr}% CTR / pos {position}`
|
|
85
|
+
- Google sees: `index status: {INDEXED|EXCLUDED|...}`, canonical: `{userCanonical} → {googleCanonical}`, last crawled: `{date}`
|
|
86
|
+
|
|
87
|
+
Feed into the verdict heuristic:
|
|
88
|
+
- `INDEXED` + impressions > 100 + position 4–10 → harden REFRESH (clear quick-win territory).
|
|
89
|
+
- `EXCLUDED` (any reason) → harden KILL or CONSOLIDATE.
|
|
90
|
+
- googleCanonical ≠ userCanonical → flag in PAGE.md as a critical issue regardless of verdict.
|
|
91
|
+
|
|
92
|
+
If the URL's domain isn't a verified GSC property, surface "GSC: {target_domain} not verified — add it in Search Console" and continue.
|
|
93
|
+
|
|
94
|
+
### `seo-content-audit` — GA4 organic traffic on the audited URL (Tier 2 — `ga4-pages` available)
|
|
95
|
+
|
|
96
|
+
Replaces estimated traffic with measured organic traffic for the audited URL.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
upstream script excluded; use optbrew capability routing top-pages --days 28 --json
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Filter the result client-side for the audited URL's path. Surface in `VERDICT.md` "## Snapshot" alongside the existing AIO citation cross-check:
|
|
103
|
+
- GA4 organic last 28d: `{sessions} sessions / {users} users / avg engagement time {n}s`
|
|
104
|
+
- If the audited URL doesn't appear in the top-100 organic landing pages: "GA4: not in top-100 organic landing pages last 28d — low or zero traffic."
|
|
105
|
+
|
|
106
|
+
This is a *signal*, not a veto. Low GA4 traffic on a YMYL page with high E-E-A-T is informative ("we're not earning the visibility our content quality should support") but doesn't change the publish decision.
|
|
107
|
+
|
|
108
|
+
### `seo-drift` — CrUX-history + indexation drift + SSRF protection (Tier 0+1)
|
|
109
|
+
|
|
110
|
+
Three additions versus the bare-MCP drift run.
|
|
111
|
+
|
|
112
|
+
**SSRF protection (always, mirrors theirs at `seo-drift/GUIDE.md:97`):**
|
|
113
|
+
|
|
114
|
+
Before any URL fetch (Firecrawl, WebFetch, Google APIs), validate via:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from scripts.google_auth import validate_url
|
|
118
|
+
if not validate_url(target_url):
|
|
119
|
+
abort("URL rejected: loopback, private IP, link-local, or metadata endpoint")
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Or invoke as a one-liner:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
python3 -c "from scripts.google_auth import validate_url; import sys; sys.exit(0 if validate_url('{url}') else 1)"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`validate_url()` (defined at `upstream script excluded; use optbrew capability routing:366`) rejects: loopback (127.0.0.1, ::1, localhost), RFC1918 private ranges (10/8, 172.16/12, 192.168/16), link-local (169.254/16), and Google metadata endpoints. Refuses non-http(s) schemes.
|
|
129
|
+
|
|
130
|
+
**`--skip-cwv` flag** (mirrors theirs at `seo-drift/GUIDE.md:107, 131`): skips the entire Google field-data snapshot (step 4b) even when `google-api.json` is configured. Useful when you only care about content/structural drift, or when CrUX rate-limit concerns outweigh CWV coverage.
|
|
131
|
+
|
|
132
|
+
**Field-data drift** (the actual enrichment):
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# CWV drift over 25 weeks (origin or per-URL based on baseline scope)
|
|
136
|
+
upstream script excluded; use optbrew capability routing "{baseline_url_or_origin}" --json
|
|
137
|
+
|
|
138
|
+
# Indexation drift: re-run Inspection on each baselined URL and diff
|
|
139
|
+
upstream script excluded; use optbrew capability routing "{url}" --site-url "{config.default_property}" --json
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Compare against the previous baseline's stored CrUX + Inspection JSON. New drift triggers:
|
|
143
|
+
- LCP p75 increased ≥20% → red.
|
|
144
|
+
- INP p75 increased ≥20% → red.
|
|
145
|
+
- CLS p75 increased ≥0.05 absolute → yellow.
|
|
146
|
+
- FCP / TTFB p75 increased ≥30% → yellow.
|
|
147
|
+
- Inspection status changed from `INDEXED` to anything else → red.
|
|
148
|
+
- googleCanonical changed → yellow.
|
|
149
|
+
- last crawl date >60 days old → yellow.
|
|
150
|
+
|
|
151
|
+
Append to `DRIFT-REPORT.md` "## Field-data drift" section.
|
|
152
|
+
|
|
153
|
+
**Skip note when `--skip-cwv` was passed:** "Field-data drift: skipped — `--skip-cwv` flag passed at baseline (or this compare)."
|
|
154
|
+
|
|
155
|
+
### `seo-plan` — Phase-0 auto-spawn (any tier)
|
|
156
|
+
|
|
157
|
+
Plan composes other skills' outputs. If creds are present and the user hasn't already run `seo-google` in this session, Phase-0 should print:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
> Google APIs detected (tier {n}). For real CWV / GSC / GA4 enrichment in
|
|
161
|
+
> downstream phases, run `seo-google {pagespeed,gsc,ga4-pages} <domain>`
|
|
162
|
+
> before re-running this plan. Continue without Google enrichment? (y/n)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
If user continues, plan proceeds with SE Ranking data only and notes the limitation in PLAN.md. If user opts to run `seo-google` first, plan exits and re-runs after.
|
|
166
|
+
|
|
167
|
+
This is the lightest possible auto-spawn — plan doesn't dispatch the skill itself (transferring friction is theirs' anti-pattern we critiqued in EVAL_RESULT_v2.md), it just tells the user there's a richer path available.
|
|
168
|
+
|
|
169
|
+
## Failure modes (handle gracefully across all skills)
|
|
170
|
+
|
|
171
|
+
| Failure | Detection | Skill response |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| Config file missing | `google_auth.py --check` exits non-zero | Note "Google field data: not configured" and skip enrichment |
|
|
174
|
+
| API key invalid | Script returns `{"error": "API_KEY_INVALID"}` | Note "Google API key rejected — re-check `~/.config/seo-skills/google-api.json`" and skip |
|
|
175
|
+
| Property not verified (GSC) | `gsc_query.py` returns `{"error": "PROPERTY_NOT_VERIFIED"}` | Note "GSC property `{x}` not verified for this account" and skip GSC enrichment only |
|
|
176
|
+
| GA4 property not configured | `ga4_property_id` empty in config | Note "GA4: property ID not configured (Tier 2 setup required)" and skip GA4 only |
|
|
177
|
+
| Insufficient CrUX data | `pagespeed_check.py --crux-only` returns `{"crux": null}` | Note "CrUX: insufficient field data for `{url}` (low traffic)" and skip CrUX only |
|
|
178
|
+
| Rate-limit hit | Script returns HTTP 429 | Note "Google API rate-limit reached — try again in 1h" and skip the affected enrichment |
|
|
179
|
+
|
|
180
|
+
A skill **never** fails the run because Google enrichment failed. Enrichment is optional uplift; the SE Ranking-based deliverable always ships.
|
|
181
|
+
|
|
182
|
+
## Why this pattern (vs spawning `seo-google` as a sub-skill)
|
|
183
|
+
|
|
184
|
+
- One Python call per enrichment, returns JSON, parsed in-line — no extra agent context, no extra latency.
|
|
185
|
+
- Each skill stays self-contained; no orchestration logic in the calling skill.
|
|
186
|
+
- Failure-isolated: a failed Google call doesn't pollute the SE Ranking-based primary deliverable.
|
|
187
|
+
- Mirrors the upstream wiring (`AgriciDaniel/claude-seo`'s `seo-technical/GUIDE.md:164` invokes the same scripts directly).
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# GA4 Data API v1beta Reference
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Google Analytics Data API v1beta provides programmatic access to GA4 report data. For SEO, the primary use case is organic traffic analysis.
|
|
6
|
+
|
|
7
|
+
**Base URL:** `https://analyticsdata.googleapis.com/v1beta`
|
|
8
|
+
|
|
9
|
+
## Key Methods
|
|
10
|
+
|
|
11
|
+
| Method | Description |
|
|
12
|
+
|--------|-------------|
|
|
13
|
+
| `properties.runReport` | Run a standard report |
|
|
14
|
+
| `properties.batchRunReports` | Up to 5 reports in one call |
|
|
15
|
+
| `properties.runRealtimeReport` | Last 30 minutes of data |
|
|
16
|
+
| `properties.getMetadata` | Available dimensions and metrics |
|
|
17
|
+
| `properties.checkCompatibility` | Verify dimension/metric combinations |
|
|
18
|
+
|
|
19
|
+
## runReport Request
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"property": "properties/123456789",
|
|
24
|
+
"dimensions": [
|
|
25
|
+
{ "name": "date" },
|
|
26
|
+
{ "name": "landingPage" }
|
|
27
|
+
],
|
|
28
|
+
"metrics": [
|
|
29
|
+
{ "name": "sessions" },
|
|
30
|
+
{ "name": "totalUsers" }
|
|
31
|
+
],
|
|
32
|
+
"dateRanges": [
|
|
33
|
+
{ "startDate": "28daysAgo", "endDate": "yesterday" }
|
|
34
|
+
],
|
|
35
|
+
"dimensionFilter": {
|
|
36
|
+
"filter": {
|
|
37
|
+
"fieldName": "sessionDefaultChannelGroup",
|
|
38
|
+
"stringFilter": {
|
|
39
|
+
"matchType": "EXACT",
|
|
40
|
+
"value": "Organic Search"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"orderBys": [
|
|
45
|
+
{ "metric": { "metricName": "sessions" }, "desc": true }
|
|
46
|
+
],
|
|
47
|
+
"limit": 100,
|
|
48
|
+
"returnPropertyQuota": true
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## SEO-Relevant Dimensions
|
|
53
|
+
|
|
54
|
+
| Dimension | Description |
|
|
55
|
+
|-----------|-------------|
|
|
56
|
+
| `date` | Date in YYYYMMDD format |
|
|
57
|
+
| `pagePath` | Page path (e.g., `/blog/post`) |
|
|
58
|
+
| `landingPage` | Entry page path |
|
|
59
|
+
| `landingPagePlusQueryString` | Entry page with query params |
|
|
60
|
+
| `fullPageUrl` | Full page URL |
|
|
61
|
+
| `pageTitle` | Page title |
|
|
62
|
+
| `sessionSource` | Traffic source (e.g., `google`) |
|
|
63
|
+
| `sessionMedium` | Traffic medium (e.g., `organic`) |
|
|
64
|
+
| `sessionDefaultChannelGroup` | Channel grouping (e.g., `Organic Search`) |
|
|
65
|
+
| `country` | User country |
|
|
66
|
+
| `deviceCategory` | `desktop`, `mobile`, `tablet` |
|
|
67
|
+
| `hostName` | Domain name |
|
|
68
|
+
| `pageReferrer` | Referrer URL |
|
|
69
|
+
|
|
70
|
+
## SEO-Relevant Metrics
|
|
71
|
+
|
|
72
|
+
| Metric | Description |
|
|
73
|
+
|--------|-------------|
|
|
74
|
+
| `sessions` | Number of sessions |
|
|
75
|
+
| `totalUsers` | Total unique users |
|
|
76
|
+
| `newUsers` | First-time users |
|
|
77
|
+
| `activeUsers` | Users with engagement |
|
|
78
|
+
| `screenPageViews` | Page views |
|
|
79
|
+
| `bounceRate` | Bounce rate (0-1, multiply by 100 for %) |
|
|
80
|
+
| `averageSessionDuration` | Avg duration in seconds |
|
|
81
|
+
| `engagementRate` | Engaged session rate (0-1) |
|
|
82
|
+
| `keyEvents` | Key events (replaced deprecated `conversions`) |
|
|
83
|
+
| `eventCount` | Total event count |
|
|
84
|
+
|
|
85
|
+
## Filter Expressions
|
|
86
|
+
|
|
87
|
+
### String Filter
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"filter": {
|
|
92
|
+
"fieldName": "sessionDefaultChannelGroup",
|
|
93
|
+
"stringFilter": {
|
|
94
|
+
"matchType": "EXACT",
|
|
95
|
+
"value": "Organic Search"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Match types: `EXACT`, `BEGINS_WITH`, `ENDS_WITH`, `CONTAINS`, `FULL_REGEXP`, `PARTIAL_REGEXP`
|
|
102
|
+
|
|
103
|
+
### Combining Filters
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"andGroup": {
|
|
108
|
+
"expressions": [
|
|
109
|
+
{ "filter": { "fieldName": "country", "stringFilter": { "matchType": "EXACT", "value": "US" }}},
|
|
110
|
+
{ "filter": { "fieldName": "deviceCategory", "stringFilter": { "matchType": "EXACT", "value": "mobile" }}}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Also supports `orGroup` and `notExpression`.
|
|
117
|
+
|
|
118
|
+
## Date Range Shortcuts
|
|
119
|
+
|
|
120
|
+
| Value | Meaning |
|
|
121
|
+
|-------|---------|
|
|
122
|
+
| `today` | Current day |
|
|
123
|
+
| `yesterday` | Previous day |
|
|
124
|
+
| `NdaysAgo` | N days ago (e.g., `28daysAgo`) |
|
|
125
|
+
| `YYYY-MM-DD` | Specific date |
|
|
126
|
+
|
|
127
|
+
Up to 4 date ranges per request (for period-over-period comparison).
|
|
128
|
+
|
|
129
|
+
## Token-Based Quotas
|
|
130
|
+
|
|
131
|
+
| Quota | Limit | Scope |
|
|
132
|
+
|-------|-------|-------|
|
|
133
|
+
| Daily tokens | 25,000 | Per property per project |
|
|
134
|
+
| Hourly tokens | 5,000 | Per property per project |
|
|
135
|
+
| Concurrent requests | 10 | Per property per project |
|
|
136
|
+
| Hourly tokens (project-wide) | 1,250 | Per project per property per hour |
|
|
137
|
+
|
|
138
|
+
Set `returnPropertyQuota: true` to monitor consumption. Simple reports cost ~1-10 tokens; complex ones up to ~100.
|
|
139
|
+
|
|
140
|
+
## Python Example
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from google.analytics.data_v1beta import BetaAnalyticsDataClient
|
|
144
|
+
from google.analytics.data_v1beta.types import (
|
|
145
|
+
DateRange, Dimension, Filter, FilterExpression,
|
|
146
|
+
Metric, OrderBy, RunReportRequest,
|
|
147
|
+
)
|
|
148
|
+
from google.oauth2 import service_account
|
|
149
|
+
|
|
150
|
+
credentials = service_account.Credentials.from_service_account_file(
|
|
151
|
+
"service_account.json",
|
|
152
|
+
scopes=["https://www.googleapis.com/auth/analytics.readonly"],
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
client = BetaAnalyticsDataClient(credentials=credentials)
|
|
156
|
+
|
|
157
|
+
request = RunReportRequest(
|
|
158
|
+
property="properties/123456789",
|
|
159
|
+
dimensions=[Dimension(name="landingPage")],
|
|
160
|
+
metrics=[Metric(name="sessions"), Metric(name="totalUsers")],
|
|
161
|
+
date_ranges=[DateRange(start_date="28daysAgo", end_date="yesterday")],
|
|
162
|
+
dimension_filter=FilterExpression(
|
|
163
|
+
filter=Filter(
|
|
164
|
+
field_name="sessionDefaultChannelGroup",
|
|
165
|
+
string_filter=Filter.StringFilter(
|
|
166
|
+
match_type=Filter.StringFilter.MatchType.EXACT,
|
|
167
|
+
value="Organic Search",
|
|
168
|
+
),
|
|
169
|
+
)
|
|
170
|
+
),
|
|
171
|
+
order_bys=[OrderBy(metric=OrderBy.MetricOrderBy(metric_name="sessions"), desc=True)],
|
|
172
|
+
limit=50,
|
|
173
|
+
return_property_quota=True,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
response = client.run_report(request)
|
|
177
|
+
for row in response.rows:
|
|
178
|
+
print(f"{row.dimension_values[0].value}: {row.metric_values[0].value} sessions")
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Authentication
|
|
182
|
+
- **Scope:** `https://www.googleapis.com/auth/analytics.readonly`
|
|
183
|
+
- Service account must have **Viewer** role in GA4 property
|
|
184
|
+
- Add via GA4 Admin > Property Access Management
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
> optbrew distribution notice: Submission disabled. The POST publish and batch examples below document upstream behavior; do not execute them from optbrew. A separate user authority decision and approved submission path are required.
|
|
2
|
+
|
|
3
|
+
# Google Indexing API v3 Reference
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Indexing API allows you to notify Google when pages are added or removed.
|
|
8
|
+
|
|
9
|
+
**IMPORTANT:** Officially restricted to pages with **JobPosting** or **BroadcastEvent/VideoObject** structured data. Google may process other page types, but provides no guarantees. Always inform users of this limitation.
|
|
10
|
+
|
|
11
|
+
## Endpoints
|
|
12
|
+
|
|
13
|
+
### Publish Notification
|
|
14
|
+
|
|
15
|
+
**`POST https://indexing.googleapis.com/v3/urlNotifications:publish`**
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"url": "https://example.com/jobs/software-engineer",
|
|
20
|
+
"type": "URL_UPDATED"
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| Field | Values |
|
|
25
|
+
|-------|--------|
|
|
26
|
+
| `url` | The fully qualified URL |
|
|
27
|
+
| `type` | `URL_UPDATED` (page added/changed), `URL_DELETED` (page removed) |
|
|
28
|
+
|
|
29
|
+
**Response:**
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"urlNotificationMetadata": {
|
|
33
|
+
"url": "https://example.com/jobs/software-engineer",
|
|
34
|
+
"latestUpdate": {
|
|
35
|
+
"url": "https://example.com/jobs/software-engineer",
|
|
36
|
+
"type": "URL_UPDATED",
|
|
37
|
+
"notifyTime": "2026-03-27T10:00:00Z"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Get Notification Metadata
|
|
44
|
+
|
|
45
|
+
**`GET https://indexing.googleapis.com/v3/urlNotifications/metadata?url={ENCODED_URL}`**
|
|
46
|
+
|
|
47
|
+
Returns `latestUpdate` and `latestRemove` timestamps for the URL.
|
|
48
|
+
|
|
49
|
+
### Batch Requests
|
|
50
|
+
|
|
51
|
+
**`POST https://indexing.googleapis.com/batch`**
|
|
52
|
+
|
|
53
|
+
Up to **100 URLs** per batch request using `multipart/mixed` format:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
POST /batch HTTP/1.1
|
|
57
|
+
Content-Type: multipart/mixed; boundary=batch_boundary
|
|
58
|
+
|
|
59
|
+
--batch_boundary
|
|
60
|
+
Content-Type: application/http
|
|
61
|
+
Content-ID: <item1>
|
|
62
|
+
|
|
63
|
+
POST /v3/urlNotifications:publish HTTP/1.1
|
|
64
|
+
Content-Type: application/json
|
|
65
|
+
|
|
66
|
+
{"url": "https://example.com/jobs/1", "type": "URL_UPDATED"}
|
|
67
|
+
--batch_boundary
|
|
68
|
+
Content-Type: application/http
|
|
69
|
+
Content-ID: <item2>
|
|
70
|
+
|
|
71
|
+
POST /v3/urlNotifications:publish HTTP/1.1
|
|
72
|
+
Content-Type: application/json
|
|
73
|
+
|
|
74
|
+
{"url": "https://example.com/jobs/2", "type": "URL_UPDATED"}
|
|
75
|
+
--batch_boundary--
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Authentication
|
|
79
|
+
|
|
80
|
+
- **Scope:** `https://www.googleapis.com/auth/indexing`
|
|
81
|
+
- **Auth type:** Service account (OAuth 2.0)
|
|
82
|
+
- The service account must be **Owner** in Google Search Console for the target domain
|
|
83
|
+
|
|
84
|
+
## Quotas
|
|
85
|
+
|
|
86
|
+
| Limit | Value | Scope |
|
|
87
|
+
|-------|-------|-------|
|
|
88
|
+
| Publish requests | **200/day** (default) | Per project |
|
|
89
|
+
| Read-only requests | 180/min | Per project |
|
|
90
|
+
| Total requests | 380/min | Per project |
|
|
91
|
+
|
|
92
|
+
Request a quota increase: [Indexing API Quota Increase Form](https://developers.google.com/search/apis/indexing-api/v3/quota-increase)
|
|
93
|
+
|
|
94
|
+
## Error Codes
|
|
95
|
+
|
|
96
|
+
| Code | Meaning | Action |
|
|
97
|
+
|------|---------|--------|
|
|
98
|
+
| 400 | Malformed URL or request body | Check URL format |
|
|
99
|
+
| 403 | Permission denied or quota exceeded | Add service account as Owner in GSC, or check quota |
|
|
100
|
+
| 429 | Rate limit exceeded | Back off and retry with exponential delay |
|
|
101
|
+
| 500/503 | Server error | Retry with exponential backoff |
|
|
102
|
+
|
|
103
|
+
## Best Practices
|
|
104
|
+
|
|
105
|
+
1. Submit only URLs with actual content changes (don't spam updates)
|
|
106
|
+
2. Use `URL_DELETED` only when a page is permanently removed (returns 404/410)
|
|
107
|
+
3. Track daily quota usage -- the 200/day limit resets at midnight Pacific Time
|
|
108
|
+
4. For large-scale indexing, use XML sitemaps + Search Console instead
|
|
109
|
+
5. Batch requests count individually against the daily quota (100 batch = 100 quota)
|