bmad-plus 0.4.0 → 0.4.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/CHANGELOG.md +29 -0
- package/README.md +13 -56
- package/osint-agent-package/skills/bmad-osint-investigate/osint/SKILL.md +452 -452
- package/osint-agent-package/skills/bmad-osint-investigate/osint/assets/dossier-template.md +116 -116
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/content-extraction.md +100 -100
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/platforms.md +130 -130
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/psychoprofile.md +69 -69
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/tools.md +281 -281
- package/osint-agent-package/skills/bmad-osint-investigate/osint/scripts/mcp-client.py +136 -136
- package/package.json +1 -1
- package/readme-international/README.de.md +1 -1
- package/readme-international/README.es.md +1 -1
- package/readme-international/README.fr.md +1 -1
- package/tools/cli/commands/install.js +88 -59
- package/tools/cli/i18n.js +501 -0
- package/oveanet-pack/animated-website/DEPLOYMENT.md +0 -104
- package/oveanet-pack/animated-website/README.md +0 -63
- package/oveanet-pack/animated-website/agent.yaml +0 -63
- package/oveanet-pack/seo-audit-360/DEPLOYMENT.md +0 -115
- package/oveanet-pack/seo-audit-360/README.md +0 -66
- package/oveanet-pack/seo-audit-360/agent.yaml +0 -70
- package/oveanet-pack/seo-audit-360/extensions/google-analytics/EXTENSION.md +0 -79
- package/oveanet-pack/seo-audit-360/extensions/google-analytics/ga4_client.py +0 -200
- package/oveanet-pack/seo-audit-360/extensions/google-analytics/requirements.txt +0 -4
- package/oveanet-pack/seo-audit-360/extensions/google-search-console/EXTENSION.md +0 -109
- package/oveanet-pack/seo-audit-360/extensions/google-search-console/gsc_client.py +0 -186
- package/oveanet-pack/seo-audit-360/extensions/google-search-console/requirements.txt +0 -4
- package/oveanet-pack/seo-audit-360/hooks/seo-check.sh +0 -95
- package/oveanet-pack/seo-audit-360/requirements.txt +0 -14
- package/oveanet-pack/seo-audit-360/scripts/__pycache__/seo_crawl.cpython-314.pyc +0 -0
- package/oveanet-pack/seo-audit-360/scripts/__pycache__/seo_parse.cpython-314.pyc +0 -0
- package/oveanet-pack/seo-audit-360/scripts/install.ps1 +0 -53
- package/oveanet-pack/seo-audit-360/scripts/install.sh +0 -48
- package/oveanet-pack/seo-audit-360/scripts/seo_apis.py +0 -464
- package/oveanet-pack/seo-audit-360/scripts/seo_crawl.py +0 -282
- package/oveanet-pack/seo-audit-360/scripts/seo_fetch.py +0 -231
- package/oveanet-pack/seo-audit-360/scripts/seo_parse.py +0 -255
- package/oveanet-pack/seo-audit-360/scripts/seo_report.py +0 -403
- package/oveanet-pack/seo-audit-360/scripts/seo_screenshot.py +0 -202
- package/oveanet-pack/seo-audit-360/tests/__pycache__/test_crawl.cpython-314-pytest-9.0.2.pyc +0 -0
- package/oveanet-pack/seo-audit-360/tests/__pycache__/test_parse.cpython-314-pytest-9.0.2.pyc +0 -0
- package/oveanet-pack/seo-audit-360/tests/fixtures/sample_page.html +0 -62
- package/oveanet-pack/seo-audit-360/tests/test_apis.py +0 -75
- package/oveanet-pack/seo-audit-360/tests/test_crawl.py +0 -121
- package/oveanet-pack/seo-audit-360/tests/test_fetch.py +0 -70
- package/oveanet-pack/seo-audit-360/tests/test_parse.py +0 -184
- package/oveanet-pack/universal-backup/DEPLOYMENT.md +0 -80
- package/oveanet-pack/universal-backup/README.md +0 -58
- package/oveanet-pack/universal-backup/agent.yaml +0 -45
- /package/{oveanet-pack/animated-website/agent → src/bmad-plus/agents/pack-animated}/animated-website-agent.md +0 -0
- /package/{oveanet-pack/animated-website → src/bmad-plus/agents/pack-animated}/templates/animated-website-workflow.md +0 -0
- /package/{oveanet-pack/universal-backup/agent → src/bmad-plus/agents/pack-backup}/backup-agent.md +0 -0
- /package/{oveanet-pack/universal-backup → src/bmad-plus/agents/pack-backup}/templates/backup-workflow.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/SKILL.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/checklist.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/pagespeed-playbook.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/ref/audit-schema.json +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/ref/cwv-thresholds.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/ref/eeat-criteria.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/ref/geo-signals.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/ref/hreflang-rules.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/ref/quality-gates.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/ref/schema-catalog.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/ref/schema-templates.json +0 -0
- /package/{oveanet-pack/seo-audit-360/agent → src/bmad-plus/agents/pack-seo}/seo-chief.md +0 -0
- /package/{oveanet-pack/seo-audit-360/agent → src/bmad-plus/agents/pack-seo}/seo-judge.md +0 -0
- /package/{oveanet-pack/seo-audit-360/agent → src/bmad-plus/agents/pack-seo}/seo-scout.md +0 -0
- /package/{oveanet-pack/seo-audit-360 → src/bmad-plus/agents/pack-seo}/templates/seo-audit-workflow.md +0 -0
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
name: animated-website
|
|
2
|
-
version: 1.0.0
|
|
3
|
-
title: "Animated Website"
|
|
4
|
-
description: "Convertit des vidéos MP4 en sites web animés de luxe avec scroll frame-by-frame"
|
|
5
|
-
author: Laurent ROCHETTA AI
|
|
6
|
-
icon: "🎬"
|
|
7
|
-
tags: [animation, scroll, video, luxury, canvas, webp]
|
|
8
|
-
triggers:
|
|
9
|
-
- "animated website"
|
|
10
|
-
- "scroll animation"
|
|
11
|
-
- "video to website"
|
|
12
|
-
- "Apple-style page"
|
|
13
|
-
- "scroll-driven site"
|
|
14
|
-
- "frame animation"
|
|
15
|
-
- "site animé"
|
|
16
|
-
requires:
|
|
17
|
-
tools:
|
|
18
|
-
- name: ffmpeg
|
|
19
|
-
install:
|
|
20
|
-
windows: "winget install FFmpeg"
|
|
21
|
-
mac: "brew install ffmpeg"
|
|
22
|
-
linux: "sudo apt install ffmpeg"
|
|
23
|
-
- name: python3
|
|
24
|
-
install:
|
|
25
|
-
windows: "winget install Python.Python.3"
|
|
26
|
-
mac: "brew install python3"
|
|
27
|
-
linux: "sudo apt install python3"
|
|
28
|
-
scripts:
|
|
29
|
-
- "scripts/extract_frames.py"
|
|
30
|
-
commands: []
|
|
31
|
-
workflow:
|
|
32
|
-
- step: 1
|
|
33
|
-
name: "Analyze Video"
|
|
34
|
-
tool: "ffprobe"
|
|
35
|
-
- step: 2
|
|
36
|
-
name: "Extract Frames"
|
|
37
|
-
tool: "extract_frames.py"
|
|
38
|
-
- step: 3
|
|
39
|
-
name: "Prepare Content"
|
|
40
|
-
tool: "agent"
|
|
41
|
-
- step: 4
|
|
42
|
-
name: "Generate HTML"
|
|
43
|
-
tool: "agent"
|
|
44
|
-
- step: 5
|
|
45
|
-
name: "Preview"
|
|
46
|
-
tool: "python http.server"
|
|
47
|
-
platforms:
|
|
48
|
-
bmad:
|
|
49
|
-
target: "_bmad/core/agents/"
|
|
50
|
-
file: "animated-website-agent.md"
|
|
51
|
-
claude:
|
|
52
|
-
target: ".claude/skills/"
|
|
53
|
-
skillName: "animated-website"
|
|
54
|
-
includeScripts: true
|
|
55
|
-
gemini:
|
|
56
|
-
target: ".agent/workflows/"
|
|
57
|
-
file: "animated-website.md"
|
|
58
|
-
opencode:
|
|
59
|
-
target: ".opencode/agents/"
|
|
60
|
-
file: "animated-website.md"
|
|
61
|
-
codex:
|
|
62
|
-
target: ".codex/agents/"
|
|
63
|
-
file: "animated-website.md"
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# Guide de Déploiement — Agent Audit SEO/GEO 360°
|
|
2
|
-
|
|
3
|
-
## Comment déployer cet agent dans un nouveau projet
|
|
4
|
-
|
|
5
|
-
### Prérequis
|
|
6
|
-
|
|
7
|
-
Votre projet doit utiliser le framework BMAD (dossier `_bmad/` à la racine).
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Méthode 1 : Déploiement BMAD (recommandé)
|
|
12
|
-
|
|
13
|
-
### Étape 1 — Copier l'agent
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
Copiez le fichier :
|
|
17
|
-
Audit SEO GEO 360/agent/seo-geo-360-auditor.md
|
|
18
|
-
|
|
19
|
-
Dans le dossier de votre projet :
|
|
20
|
-
{votre-projet}/_bmad/core/agents/seo-geo-360-auditor.md
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Étape 2 — Vérifier la config
|
|
24
|
-
|
|
25
|
-
Assurez-vous que votre `_bmad/core/config.yaml` contient :
|
|
26
|
-
|
|
27
|
-
```yaml
|
|
28
|
-
user_name: Laurent
|
|
29
|
-
communication_language: French
|
|
30
|
-
document_output_language: English
|
|
31
|
-
output_folder: "{project-root}/_bmad-output"
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Étape 3 — Activer l'agent
|
|
35
|
-
|
|
36
|
-
Demandez à votre IA :
|
|
37
|
-
> _"Charge l'agent `_bmad/core/agents/seo-geo-360-auditor.md` et active-le"_
|
|
38
|
-
|
|
39
|
-
L'agent affichera son menu avec les 8 commandes disponibles.
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## Méthode 2 : Usage standalone (sans BMAD)
|
|
44
|
-
|
|
45
|
-
### Étape 1 — Copier le dossier complet
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
Copiez le dossier entier :
|
|
49
|
-
Audit SEO GEO 360/
|
|
50
|
-
|
|
51
|
-
À la racine de votre projet :
|
|
52
|
-
{votre-projet}/Audit SEO GEO 360/
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Étape 2 — Utiliser la checklist
|
|
56
|
-
|
|
57
|
-
Ouvrez `checklist.md` et cochez les items un par un pendant votre audit.
|
|
58
|
-
|
|
59
|
-
### Étape 3 — Utiliser les templates
|
|
60
|
-
|
|
61
|
-
Copiez les fichiers depuis `templates/` vers la racine web de votre site :
|
|
62
|
-
|
|
63
|
-
| Template | Destination | Action |
|
|
64
|
-
|---|---|---|
|
|
65
|
-
| `templates/robots.txt` | `{site}/robots.txt` | Remplacez `YOUR-DOMAIN.com` |
|
|
66
|
-
| `templates/llms.txt` | `{site}/llms.txt` | Remplissez les `[BRACKETS]` |
|
|
67
|
-
| `templates/schema-templates.json` | Dans le `<head>` | Copiez les blocs JSON-LD nécessaires |
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## Structure de dossiers
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
votre-projet/
|
|
75
|
-
├── _bmad/
|
|
76
|
-
│ └── core/
|
|
77
|
-
│ ├── agents/
|
|
78
|
-
│ │ ├── bmad-master.md
|
|
79
|
-
│ │ └── seo-geo-360-auditor.md ← ICI (méthode BMAD)
|
|
80
|
-
│ ├── config.yaml
|
|
81
|
-
│ └── ...
|
|
82
|
-
├── website/ (ou public/, src/, etc.)
|
|
83
|
-
│ ├── robots.txt ← Généré par l'agent
|
|
84
|
-
│ ├── sitemap.xml ← Généré par l'agent
|
|
85
|
-
│ ├── llms.txt ← Généré par l'agent
|
|
86
|
-
│ └── index.php/html ← Schema.org injecté ici
|
|
87
|
-
└── _bmad-output/
|
|
88
|
-
└── seo-geo-audit-360.md ← Rapport d'audit généré
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## Commandes rapides une fois l'agent activé
|
|
94
|
-
|
|
95
|
-
| # | Commande | Ce que ça fait |
|
|
96
|
-
|---|---|---|
|
|
97
|
-
| `FA` | Audit complet 360° | Analyse tout et génère un rapport |
|
|
98
|
-
| `GF` | Génère les fichiers | Crée robots.txt, sitemap, llms.txt, Schema |
|
|
99
|
-
| `SC` | Scorecard | Scores rapides sur 10 par catégorie |
|
|
100
|
-
| `FAQ` | Génère la FAQ | Section FAQ + FAQPage Schema bilingue |
|
|
101
|
-
| `GA` | Audit GEO | Focus optimisation pour ChatGPT/Perplexity/Gemini |
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## Projets compatibles
|
|
106
|
-
|
|
107
|
-
Cet agent fonctionne avec **tout type de projet web** :
|
|
108
|
-
|
|
109
|
-
- PHP (WordPress, Laravel, sites statiques)
|
|
110
|
-
- JavaScript (Next.js, Nuxt, Vite, React)
|
|
111
|
-
- HTML statique
|
|
112
|
-
- Python (Django, Flask)
|
|
113
|
-
- Sites JAMstack (Astro, Gatsby, Hugo)
|
|
114
|
-
|
|
115
|
-
L'agent détecte automatiquement le framework et adapte ses recommandations.
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# SEO Engine v2.0 — BMAD+ SEO Audit 360
|
|
2
|
-
|
|
3
|
-
> **By Laurent Rochetta** | Oveanet × BMAD+
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
A comprehensive SEO audit engine with 3 multi-role agents, a 6-phase workflow, Python toolkit, and auto-fix generation. Built from scratch for the BMAD+ framework.
|
|
8
|
-
|
|
9
|
-
## Agents
|
|
10
|
-
|
|
11
|
-
| Agent | Roles | Purpose |
|
|
12
|
-
|-------|-------|---------|
|
|
13
|
-
| 🔎 **Scout** | Crawler, Inspector, Photographer | Technical scanning (9 categories) |
|
|
14
|
-
| ⚖️ **Judge** | Content Expert, Schema Master, GEO Analyst | Content quality, E-E-A-T, AI readiness |
|
|
15
|
-
| 👑 **Chief** | Scorer, Strategist, Reporter | Scoring (0-100), action plans, monitoring |
|
|
16
|
-
|
|
17
|
-
## Workflow (6 Phases)
|
|
18
|
-
|
|
19
|
-
1. **Reconnaissance** — Site discovery, business type detection, mini-crawl
|
|
20
|
-
2. **Deep Scan** — Scout + Judge in parallel (technical + content)
|
|
21
|
-
3. **AI Readiness** — GEO analysis for AI search visibility
|
|
22
|
-
4. **Scoring** — SEO Health Score (0-100) with weighted categories
|
|
23
|
-
5. **Action Plan** — Prioritized roadmap + auto-generated code fixes
|
|
24
|
-
5b. **PageSpeed Loop** — Iterative fixing to achieve 100% on all 4 categories
|
|
25
|
-
6. **Monitoring** — Score tracking over time
|
|
26
|
-
|
|
27
|
-
## Commands
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
/seo full <url> # Complete 6-phase audit
|
|
31
|
-
/seo quick <url> # Phases 1-4 only
|
|
32
|
-
/seo technical <url> # Technical audit
|
|
33
|
-
/seo content <url> # Content + E-E-A-T
|
|
34
|
-
/seo geo <url> # AI search readiness
|
|
35
|
-
/seo schema <url> # Schema validation
|
|
36
|
-
/seo pagespeed <url> # PageSpeed perfection loop
|
|
37
|
-
/seo plan <type> # Strategic plan (saas/ecommerce/local)
|
|
38
|
-
/seo fix # Auto-generate fixes
|
|
39
|
-
/seo history # Score history
|
|
40
|
-
/seo compare # Compare with previous audit
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Python Toolkit
|
|
44
|
-
|
|
45
|
-
| Script | Purpose |
|
|
46
|
-
|--------|---------|
|
|
47
|
-
| `seo_fetch.py` | Secure HTTP fetcher (SSRF protection, multi-UA) |
|
|
48
|
-
| `seo_parse.py` | HTML parser (meta, schema, links, word count) |
|
|
49
|
-
| `seo_crawl.py` | Recursive mini-crawler with sitemap discovery |
|
|
50
|
-
| `seo_screenshot.py` | Playwright viewport screenshots + above-fold analysis |
|
|
51
|
-
|
|
52
|
-
## Scoring System
|
|
53
|
-
|
|
54
|
-
| Category | Weight |
|
|
55
|
-
|----------|--------|
|
|
56
|
-
| Technical SEO | 20% |
|
|
57
|
-
| Content & E-E-A-T | 22% |
|
|
58
|
-
| On-Page SEO | 18% |
|
|
59
|
-
| Schema | 10% |
|
|
60
|
-
| Performance (CWV) | 12% |
|
|
61
|
-
| AI Readiness (GEO) | 12% |
|
|
62
|
-
| Images | 6% |
|
|
63
|
-
|
|
64
|
-
## License
|
|
65
|
-
|
|
66
|
-
MIT — By Laurent Rochetta
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
name: seo-audit-360
|
|
2
|
-
version: 2.0.0
|
|
3
|
-
author: Laurent Rochetta
|
|
4
|
-
brand: Oveanet × Laurent Rochetta
|
|
5
|
-
description: >
|
|
6
|
-
SEO Engine v2.0 — Complete SEO audit system with 3 multi-role agents,
|
|
7
|
-
6-phase workflow, Python toolkit, and PageSpeed perfection loop.
|
|
8
|
-
Covers technical SEO, E-E-A-T, schema validation, GEO (AI search),
|
|
9
|
-
Core Web Vitals, and auto-fix generation.
|
|
10
|
-
|
|
11
|
-
agents:
|
|
12
|
-
- id: seo-scout
|
|
13
|
-
name: Scout
|
|
14
|
-
file: agent/seo-scout.md
|
|
15
|
-
roles: [crawler, inspector, photographer]
|
|
16
|
-
description: Technical scanner — crawl, fetch, inspect, screenshot
|
|
17
|
-
|
|
18
|
-
- id: seo-judge
|
|
19
|
-
name: Judge
|
|
20
|
-
file: agent/seo-judge.md
|
|
21
|
-
roles: [content-expert, schema-master, geo-analyst]
|
|
22
|
-
description: Content & AI analyst — E-E-A-T, schema, GEO
|
|
23
|
-
|
|
24
|
-
- id: seo-chief
|
|
25
|
-
name: Chief
|
|
26
|
-
file: agent/seo-chief.md
|
|
27
|
-
roles: [scorer, strategist, reporter]
|
|
28
|
-
description: Strategist & reporter — scoring, action plans, monitoring
|
|
29
|
-
|
|
30
|
-
scripts:
|
|
31
|
-
- seo_fetch.py
|
|
32
|
-
- seo_parse.py
|
|
33
|
-
- seo_crawl.py
|
|
34
|
-
- seo_screenshot.py
|
|
35
|
-
|
|
36
|
-
references:
|
|
37
|
-
- ref/cwv-thresholds.md
|
|
38
|
-
- ref/schema-catalog.md
|
|
39
|
-
- ref/eeat-criteria.md
|
|
40
|
-
- ref/geo-signals.md
|
|
41
|
-
- ref/quality-gates.md
|
|
42
|
-
- ref/schema-templates.json
|
|
43
|
-
|
|
44
|
-
workflow: templates/seo-audit-workflow.md
|
|
45
|
-
|
|
46
|
-
commands:
|
|
47
|
-
- /seo full <url>
|
|
48
|
-
- /seo quick <url>
|
|
49
|
-
- /seo technical <url>
|
|
50
|
-
- /seo content <url>
|
|
51
|
-
- /seo geo <url>
|
|
52
|
-
- /seo schema <url>
|
|
53
|
-
- /seo images <url>
|
|
54
|
-
- /seo hreflang <url>
|
|
55
|
-
- /seo pagespeed <url>
|
|
56
|
-
- /seo plan <type>
|
|
57
|
-
- /seo fix
|
|
58
|
-
- /seo history
|
|
59
|
-
- /seo compare
|
|
60
|
-
|
|
61
|
-
platforms: [bmad, claude, gemini, opencode, codex]
|
|
62
|
-
|
|
63
|
-
dependencies:
|
|
64
|
-
required:
|
|
65
|
-
- python >= 3.10
|
|
66
|
-
optional:
|
|
67
|
-
- requests (pip install requests)
|
|
68
|
-
- beautifulsoup4 (pip install beautifulsoup4)
|
|
69
|
-
- lxml (pip install lxml)
|
|
70
|
-
- playwright (pip install playwright && playwright install chromium)
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# Google Analytics 4 Extension — BMAD+ SEO Engine
|
|
2
|
-
|
|
3
|
-
> Author: Laurent Rochetta | BMAD+ SEO Engine v2.1
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
This extension connects to Google Analytics 4 (GA4) Data API for organic traffic analysis. Uses the same OAuth2 credentials as the Search Console extension.
|
|
8
|
-
|
|
9
|
-
## Setup Guide
|
|
10
|
-
|
|
11
|
-
### Prerequisites
|
|
12
|
-
- Google Cloud project with **GA4 Data API** enabled
|
|
13
|
-
- OAuth2 credentials (same `credentials.json` as GSC extension)
|
|
14
|
-
- GA4 property ID (find in GA4 Admin > Property Settings)
|
|
15
|
-
|
|
16
|
-
### First Run
|
|
17
|
-
```bash
|
|
18
|
-
python ga4_client.py --setup --property 123456789
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Commands
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
# Organic traffic overview
|
|
25
|
-
python ga4_client.py --organic https://example.com --property 123456789 --days 30
|
|
26
|
-
|
|
27
|
-
# Top organic landing pages
|
|
28
|
-
python ga4_client.py --landing https://example.com --property 123456789 --days 30
|
|
29
|
-
|
|
30
|
-
# Conversions from organic
|
|
31
|
-
python ga4_client.py --conversions https://example.com --property 123456789 --days 30
|
|
32
|
-
|
|
33
|
-
# Full export
|
|
34
|
-
python ga4_client.py --all https://example.com --property 123456789 --json > ga4-data.json
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Output Examples
|
|
38
|
-
|
|
39
|
-
### Organic Traffic
|
|
40
|
-
```
|
|
41
|
-
Organic Traffic (30 days):
|
|
42
|
-
Sessions: 12,450
|
|
43
|
-
Users: 8,230
|
|
44
|
-
New Users: 6,120
|
|
45
|
-
Engagement Rate: 72.3%
|
|
46
|
-
Avg Duration: 2m 45s
|
|
47
|
-
Bounce Rate: 36.1%
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Top Landing Pages
|
|
51
|
-
```
|
|
52
|
-
Top Organic Landing Pages:
|
|
53
|
-
1. /blog/ai-development — 2,340 sessions, 78% engagement
|
|
54
|
-
2. / — 1,850 sessions, 65% engagement
|
|
55
|
-
3. /features — 1,120 sessions, 82% engagement
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Integration with SEO Engine
|
|
59
|
-
|
|
60
|
-
When installed, the SEO Engine can:
|
|
61
|
-
- Correlate crawled pages with actual organic traffic
|
|
62
|
-
- Identify high-traffic pages that need SEO optimization
|
|
63
|
-
- Track organic conversion attribution
|
|
64
|
-
- Detect pages with high impressions but low engagement (content quality issues)
|
|
65
|
-
|
|
66
|
-
## Dependencies
|
|
67
|
-
|
|
68
|
-
Same Google Auth libraries as GSC extension:
|
|
69
|
-
```
|
|
70
|
-
google-auth>=2.0.0
|
|
71
|
-
google-auth-oauthlib>=1.0.0
|
|
72
|
-
google-analytics-data>=0.18.0
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Security Notes
|
|
76
|
-
|
|
77
|
-
- Uses same `credentials.json` and `token.json` as GSC extension
|
|
78
|
-
- GA4 property ID is not sensitive but should be stored per-project
|
|
79
|
-
- Add credentials to `.gitignore`
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Google Analytics 4 Client — GA4 Data API client for organic traffic analysis.
|
|
4
|
-
|
|
5
|
-
Features:
|
|
6
|
-
- Organic traffic metrics (sessions, users, engagement)
|
|
7
|
-
- Landing page performance
|
|
8
|
-
- Conversion attribution
|
|
9
|
-
- Custom date ranges
|
|
10
|
-
|
|
11
|
-
Author: Laurent Rochetta
|
|
12
|
-
License: MIT
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
import argparse
|
|
16
|
-
import json
|
|
17
|
-
import os
|
|
18
|
-
import sys
|
|
19
|
-
from datetime import datetime, timedelta
|
|
20
|
-
|
|
21
|
-
SCOPES = ["https://www.googleapis.com/auth/analytics.readonly"]
|
|
22
|
-
CREDENTIALS_FILE = os.path.join(os.path.dirname(__file__), "..", "google-search-console", "credentials.json")
|
|
23
|
-
TOKEN_FILE = os.path.join(os.path.dirname(__file__), "..", "google-search-console", "token.json")
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def get_client(property_id: str):
|
|
27
|
-
"""Authenticate and return a GA4 BetaAnalyticsData client."""
|
|
28
|
-
try:
|
|
29
|
-
from google.oauth2.credentials import Credentials
|
|
30
|
-
from google_auth_oauthlib.flow import InstalledAppFlow
|
|
31
|
-
from google.auth.transport.requests import Request
|
|
32
|
-
from google.analytics.data_v1beta import BetaAnalyticsDataClient
|
|
33
|
-
from google.analytics.data_v1beta.types import (
|
|
34
|
-
DateRange, Dimension, Metric, RunReportRequest, FilterExpression,
|
|
35
|
-
Filter,
|
|
36
|
-
)
|
|
37
|
-
except ImportError:
|
|
38
|
-
print(
|
|
39
|
-
"Error: Missing dependencies. Install:\n"
|
|
40
|
-
" pip install google-auth google-auth-oauthlib google-analytics-data",
|
|
41
|
-
file=sys.stderr,
|
|
42
|
-
)
|
|
43
|
-
sys.exit(1)
|
|
44
|
-
|
|
45
|
-
creds = None
|
|
46
|
-
if os.path.exists(TOKEN_FILE):
|
|
47
|
-
creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
|
|
48
|
-
|
|
49
|
-
if not creds or not creds.valid:
|
|
50
|
-
if creds and creds.expired and creds.refresh_token:
|
|
51
|
-
creds.refresh(Request())
|
|
52
|
-
else:
|
|
53
|
-
if not os.path.exists(CREDENTIALS_FILE):
|
|
54
|
-
print(f"Error: credentials.json not found. See EXTENSION.md for setup.", file=sys.stderr)
|
|
55
|
-
sys.exit(1)
|
|
56
|
-
flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_FILE, SCOPES)
|
|
57
|
-
creds = flow.run_local_server(port=0)
|
|
58
|
-
|
|
59
|
-
with open(TOKEN_FILE, "w") as f:
|
|
60
|
-
f.write(creds.to_json())
|
|
61
|
-
|
|
62
|
-
return BetaAnalyticsDataClient(credentials=creds), property_id
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def run_organic_report(client, property_id: str, days: int = 30) -> dict:
|
|
66
|
-
"""Get organic traffic overview."""
|
|
67
|
-
from google.analytics.data_v1beta.types import (
|
|
68
|
-
DateRange, Metric, RunReportRequest, FilterExpression, Filter,
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
end_date = datetime.now().date()
|
|
72
|
-
start_date = end_date - timedelta(days=days)
|
|
73
|
-
|
|
74
|
-
request = RunReportRequest(
|
|
75
|
-
property=f"properties/{property_id}",
|
|
76
|
-
date_ranges=[DateRange(start_date=start_date.isoformat(), end_date=end_date.isoformat())],
|
|
77
|
-
metrics=[
|
|
78
|
-
Metric(name="sessions"),
|
|
79
|
-
Metric(name="totalUsers"),
|
|
80
|
-
Metric(name="newUsers"),
|
|
81
|
-
Metric(name="engagementRate"),
|
|
82
|
-
Metric(name="averageSessionDuration"),
|
|
83
|
-
Metric(name="bounceRate"),
|
|
84
|
-
],
|
|
85
|
-
dimension_filter=FilterExpression(
|
|
86
|
-
filter=Filter(
|
|
87
|
-
field_name="sessionDefaultChannelGroup",
|
|
88
|
-
string_filter=Filter.StringFilter(value="Organic Search"),
|
|
89
|
-
)
|
|
90
|
-
),
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
response = client.run_report(request)
|
|
94
|
-
|
|
95
|
-
if not response.rows:
|
|
96
|
-
return {"error": "No organic data available for this period"}
|
|
97
|
-
|
|
98
|
-
row = response.rows[0]
|
|
99
|
-
return {
|
|
100
|
-
"sessions": int(row.metric_values[0].value),
|
|
101
|
-
"users": int(row.metric_values[1].value),
|
|
102
|
-
"new_users": int(row.metric_values[2].value),
|
|
103
|
-
"engagement_rate": round(float(row.metric_values[3].value) * 100, 1),
|
|
104
|
-
"avg_duration_seconds": round(float(row.metric_values[4].value)),
|
|
105
|
-
"bounce_rate": round(float(row.metric_values[5].value) * 100, 1),
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
def run_landing_page_report(client, property_id: str, days: int = 30, limit: int = 20) -> list:
|
|
110
|
-
"""Get top organic landing pages."""
|
|
111
|
-
from google.analytics.data_v1beta.types import (
|
|
112
|
-
DateRange, Dimension, Metric, RunReportRequest, FilterExpression, Filter,
|
|
113
|
-
OrderBy,
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
end_date = datetime.now().date()
|
|
117
|
-
start_date = end_date - timedelta(days=days)
|
|
118
|
-
|
|
119
|
-
request = RunReportRequest(
|
|
120
|
-
property=f"properties/{property_id}",
|
|
121
|
-
date_ranges=[DateRange(start_date=start_date.isoformat(), end_date=end_date.isoformat())],
|
|
122
|
-
dimensions=[Dimension(name="landingPage")],
|
|
123
|
-
metrics=[
|
|
124
|
-
Metric(name="sessions"),
|
|
125
|
-
Metric(name="engagementRate"),
|
|
126
|
-
Metric(name="averageSessionDuration"),
|
|
127
|
-
],
|
|
128
|
-
dimension_filter=FilterExpression(
|
|
129
|
-
filter=Filter(
|
|
130
|
-
field_name="sessionDefaultChannelGroup",
|
|
131
|
-
string_filter=Filter.StringFilter(value="Organic Search"),
|
|
132
|
-
)
|
|
133
|
-
),
|
|
134
|
-
order_bys=[OrderBy(metric=OrderBy.MetricOrderBy(metric_name="sessions"), desc=True)],
|
|
135
|
-
limit=limit,
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
response = client.run_report(request)
|
|
139
|
-
|
|
140
|
-
return [{
|
|
141
|
-
"page": row.dimension_values[0].value,
|
|
142
|
-
"sessions": int(row.metric_values[0].value),
|
|
143
|
-
"engagement_rate": round(float(row.metric_values[1].value) * 100, 1),
|
|
144
|
-
"avg_duration": round(float(row.metric_values[2].value)),
|
|
145
|
-
} for row in response.rows]
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
# ── CLI ────────────────────────────────────────────────────────────
|
|
149
|
-
|
|
150
|
-
def main():
|
|
151
|
-
parser = argparse.ArgumentParser(
|
|
152
|
-
description="Google Analytics 4 Client (BMAD+ SEO Engine)"
|
|
153
|
-
)
|
|
154
|
-
parser.add_argument("--property", "-p", required=True, help="GA4 Property ID")
|
|
155
|
-
parser.add_argument("--organic", action="store_true", help="Organic traffic overview")
|
|
156
|
-
parser.add_argument("--landing", action="store_true", help="Top landing pages")
|
|
157
|
-
parser.add_argument("--all", action="store_true", help="All reports")
|
|
158
|
-
parser.add_argument("--days", type=int, default=30, help="Days lookback (default: 30)")
|
|
159
|
-
parser.add_argument("--limit", type=int, default=20, help="Max rows (default: 20)")
|
|
160
|
-
parser.add_argument("--json", "-j", action="store_true", help="Output as JSON")
|
|
161
|
-
parser.add_argument("--setup", action="store_true", help="Run OAuth2 setup")
|
|
162
|
-
|
|
163
|
-
args = parser.parse_args()
|
|
164
|
-
|
|
165
|
-
client, property_id = get_client(args.property)
|
|
166
|
-
|
|
167
|
-
if args.setup:
|
|
168
|
-
print("✅ OAuth2 setup complete for GA4.")
|
|
169
|
-
return
|
|
170
|
-
|
|
171
|
-
if args.organic or args.all:
|
|
172
|
-
data = run_organic_report(client, property_id, args.days)
|
|
173
|
-
if args.json:
|
|
174
|
-
print(json.dumps({"organic": data}, indent=2))
|
|
175
|
-
else:
|
|
176
|
-
print(f"\nOrganic Traffic ({args.days} days):")
|
|
177
|
-
if "error" in data:
|
|
178
|
-
print(f" {data['error']}")
|
|
179
|
-
else:
|
|
180
|
-
mins = data["avg_duration_seconds"] // 60
|
|
181
|
-
secs = data["avg_duration_seconds"] % 60
|
|
182
|
-
print(f" Sessions: {data['sessions']:,}")
|
|
183
|
-
print(f" Users: {data['users']:,}")
|
|
184
|
-
print(f" New Users: {data['new_users']:,}")
|
|
185
|
-
print(f" Engagement: {data['engagement_rate']}%")
|
|
186
|
-
print(f" Avg Duration: {mins}m {secs}s")
|
|
187
|
-
print(f" Bounce Rate: {data['bounce_rate']}%")
|
|
188
|
-
|
|
189
|
-
if args.landing or args.all:
|
|
190
|
-
pages = run_landing_page_report(client, property_id, args.days, args.limit)
|
|
191
|
-
if args.json:
|
|
192
|
-
print(json.dumps({"landing_pages": pages}, indent=2))
|
|
193
|
-
else:
|
|
194
|
-
print(f"\nTop Organic Landing Pages:")
|
|
195
|
-
for i, p in enumerate(pages, 1):
|
|
196
|
-
print(f" {i:2}. {p['page'][:55]} — {p['sessions']:,} sessions, {p['engagement_rate']}% engagement")
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if __name__ == "__main__":
|
|
200
|
-
main()
|