SEO matomo skill
Matomo Reporting API extension.
by AgriciDaniel·MIT license·GitHub ↗
★ 17,394 Stars on the repo·Checked
npx degit AgriciDaniel/claude-seo/extensions/matomo/skills/seo-matomo#main ~/.claude/skills/seo-matomoFiles of SEO matomo
Files 1 file
Show the full text112 lines
seo-matomo
Self-hosted analytics surface. Use Matomo as a privacy-first GA4 alternative
when you own your analytics data, want zero Google dependency, or operate
behind a strict data-residency boundary. The same seo-matomo skill works
against Matomo Cloud and self-hosted instances.
Prerequisites
- Run
extensions/matomo/install.shorinstall.ps1. - A Matomo instance URL (https://analytics.example.com).
- A Matomo API
token_authwithviewaccess on the sites you analyze. - (Optional) A default
idSiteto avoid passing--site-idon every call.
Routing
| Command | Underlying script |
|---|---|
/seo matomo check |
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_auth.py --check |
/seo matomo organic [site-id] |
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py organic --site-id <id> |
/seo matomo top-pages |
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py top-pages |
/seo matomo device |
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py device |
/seo matomo country |
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py country |
/seo matomo referrers |
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py referrers |
/seo matomo keywords |
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py keywords |
All commands accept --days (default 28), --limit, --site-id, and
--json. The site ID falls back to MATOMO_SITE_ID from settings.
When this skill applies
- The user wants Google-free analytics or has a Matomo instance already configured. Common in EU privacy-first setups, regulated industries, and teams who own their analytics.
- The user explicitly says "Matomo", "self-hosted analytics", or asks to
replace GA4. For Google Search performance use
seo-google; this skill is the reporting substitute. - The user is migrating from GA4 and wants the same report types (organic trend, landing pages, device / country split, referrer split) sourced from Matomo's Reporting API.
Cross-skill delegation
- For Google Search Console / CrUX / Indexing, route to
seo-google.seo-matomocovers reporting (visits / pages / referrers), not search performance metrics. - For AI Overview / GEO citability work, route to
seo-geo. Matomo offers no LLM-specific signals. - During
/seo audit, the orchestrator spawns theseo-matomoagent (analogous toseo-google) whenever"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_auth.py --checksucceeds. Both agents can be active simultaneously when the user has both GA4 and Matomo configured.
Self-hosted instance on a private address
Every Matomo request goes through claude-seo's SSRF guard: the instance URL
is validated and DNS-pinned, and a redirect off the instance is refused.
Private, loopback, and link-local addresses are refused by default. When the
user's instance lives on one (http://matomo.internal:8080,
http://192.168.1.20, http://localhost:8080), tell them to name it in the
CLAUDE_SEO_LOCAL_TARGETS allowlist:
export CLAUDE_SEO_LOCAL_TARGETS="matomo.internal:8080"
Entries are host or host:port, comma-separated, matched exactly. The
allowlist covers only the top-level instance URL; redirect targets and every
other host stay fail-closed, and cloud metadata addresses are refused even
when listed. Never suggest disabling the guard or editing url_safety.py:
the allowlist is the supported route. Details in
extensions/matomo/docs/MATOMO-SETUP.md and SECURITY.md.
Error Handling
- Refused by the SSRF guard (error names
CLAUDE_SEO_LOCAL_TARGETS): the instance is on a private address that has not been allowlisted. Give the user the exact export line from the error, which already carries the righthost:port. - Refused redirect: the instance answered a 30x pointing at another host.
MATOMO_URLis pointing at a redirector rather than at the Reporting API. Ask the user for the URL their instance actually serves the API from. - Missing credentials: report which env vars / config keys are unset and
remind the user to run
extensions/matomo/install.shor"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_auth.py --setup. - HTTP 401/403 from Matomo: the token lacks view access for the given site. Verify the token scope in Matomo Administration -> Personal -> Security -> API Tokens. The skill never logs the token.
result=errorpayloads from Matomo (e.g. invalididSite): surface the message verbatim; do not guess.- Connection / SSL / timeout: report the network failure class
(
ConnectionError,SSLError,timeout) and confirmMATOMO_URLresolves.
Output Formatting
- Tables for time-series, device, and country data.
- Critical / High / Medium / Low priority for any cross-skill actions surfaced from Matomo data.
- Always label the data source as "Matomo Reporting API (live)" to distinguish from GA4, CrUX, or static crawl analysis.
- For organic keywords, surface the
anonymized_share_pctprominently. Many keywords will be "(not provided)" due to browser privacy and Matomo's anonymization rules; this is normal, not a data bug.
| 1 | |
| 2 | name seo-matomo |
| 3 | description Matomo Reporting API extension. Self-hosted or Matomo Cloud analytics as a GA4 alternative or complement. Organic traffic, landing pages, device / country breakdowns, referrers, search keywords. Triggers on "Matomo", "self-hosted analytics", "analytics ohne Google", "GA4 alternative", "Matomo Reporting", "Piwik". |
| 4 | metadata |
| 5 | version "2.4.0" |
| 6 | compatibility "Requires a Matomo instance URL and API token in ~/.config/claude-seo/matomo.json (0600), or MATOMO_URL / MATOMO_API_TOKEN / MATOMO_SITE_ID in the environment. Run extensions/matomo/install.sh to configure." |
| 7 | |
| 8 | |
| 9 | # seo-matomo |
| 10 | |
| 11 | Self-hosted analytics surface. Use Matomo as a privacy-first GA4 alternative |
| 12 | when you own your analytics data, want zero Google dependency, or operate |
| 13 | behind a strict data-residency boundary. The same `seo-matomo` skill works |
| 14 | against Matomo Cloud and self-hosted instances. |
| 15 | |
| 16 | ## Prerequisites |
| 17 | |
| 18 | Run `extensions/matomo/install.sh` or `install.ps1`. |
| 19 | A Matomo instance URL (https://analytics.example.com). |
| 20 | A Matomo API `token_auth` with `view` access on the sites you analyze. |
| 21 | (Optional) A default `idSite` to avoid passing `--site-id` on every call. |
| 22 | |
| 23 | ## Routing |
| 24 | |
| 25 | | Command | Underlying script | |
| 26 | |---|---| |
| 27 | | `/seo matomo check` | `"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_auth.py --check` | |
| 28 | | `/seo matomo organic [site-id]` | `"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py organic --site-id <id>` | |
| 29 | | `/seo matomo top-pages` | `"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py top-pages` | |
| 30 | | `/seo matomo device` | `"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py device` | |
| 31 | | `/seo matomo country` | `"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py country` | |
| 32 | | `/seo matomo referrers` | `"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py referrers` | |
| 33 | | `/seo matomo keywords` | `"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_report.py keywords` | |
| 34 | |
| 35 | All commands accept `--days` (default 28), `--limit`, `--site-id`, and |
| 36 | `--json`. The site ID falls back to `MATOMO_SITE_ID` from settings. |
| 37 | |
| 38 | ## When this skill applies |
| 39 | |
| 40 | The user wants Google-free analytics or has a Matomo instance already |
| 41 | configured. Common in EU privacy-first setups, regulated industries, |
| 42 | and teams who own their analytics. |
| 43 | The user explicitly says "Matomo", "self-hosted analytics", or asks to |
| 44 | replace GA4. For Google Search performance use `seo-google`; this |
| 45 | skill is the reporting substitute. |
| 46 | The user is migrating from GA4 and wants the same report types |
| 47 | (organic trend, landing pages, device / country split, referrer split) |
| 48 | sourced from Matomo's Reporting API. |
| 49 | |
| 50 | ## Cross-skill delegation |
| 51 | |
| 52 | For Google Search Console / CrUX / Indexing, route to `seo-google`. |
| 53 | `seo-matomo` covers reporting (visits / pages / referrers), not search |
| 54 | performance metrics. |
| 55 | For AI Overview / GEO citability work, route to `seo-geo`. Matomo |
| 56 | offers no LLM-specific signals. |
| 57 | During `/seo audit`, the orchestrator spawns the `seo-matomo` agent |
| 58 | (analogous to `seo-google`) whenever `"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_auth.py |
| 59 | --check` succeeds. Both agents can be active simultaneously when the |
| 60 | user has both GA4 and Matomo configured. |
| 61 | |
| 62 | ## Self-hosted instance on a private address |
| 63 | |
| 64 | Every Matomo request goes through claude-seo's SSRF guard: the instance URL |
| 65 | is validated and DNS-pinned, and a redirect off the instance is refused. |
| 66 | Private, loopback, and link-local addresses are refused by default. When the |
| 67 | user's instance lives on one (`http://matomo.internal:8080`, |
| 68 | `http://192.168.1.20`, `http://localhost:8080`), tell them to name it in the |
| 69 | `CLAUDE_SEO_LOCAL_TARGETS` allowlist: |
| 70 | |
| 71 | |
| 72 | export CLAUDE_SEO_LOCAL_TARGETS="matomo.internal:8080" |
| 73 | |
| 74 | |
| 75 | Entries are `host` or `host:port`, comma-separated, matched exactly. The |
| 76 | allowlist covers only the top-level instance URL; redirect targets and every |
| 77 | other host stay fail-closed, and cloud metadata addresses are refused even |
| 78 | when listed. Never suggest disabling the guard or editing `url_safety.py`: |
| 79 | the allowlist is the supported route. Details in |
| 80 | `extensions/matomo/docs/MATOMO-SETUP.md` and SECURITY.md. |
| 81 | |
| 82 | ## Error Handling |
| 83 | |
| 84 | Refused by the SSRF guard (error names `CLAUDE_SEO_LOCAL_TARGETS`): the |
| 85 | instance is on a private address that has not been allowlisted. Give the |
| 86 | user the exact export line from the error, which already carries the right |
| 87 | `host:port`. |
| 88 | Refused redirect: the instance answered a 30x pointing at another host. |
| 89 | `MATOMO_URL` is pointing at a redirector rather than at the Reporting API. |
| 90 | Ask the user for the URL their instance actually serves the API from. |
| 91 | Missing credentials: report which env vars / config keys are unset and |
| 92 | remind the user to run `extensions/matomo/install.sh` or |
| 93 | `"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run matomo_auth.py --setup`. |
| 94 | HTTP 401/403 from Matomo: the token lacks view access for the given |
| 95 | site. Verify the token scope in Matomo Administration -> Personal -> |
| 96 | Security -> API Tokens. The skill never logs the token. |
| 97 | `result=error` payloads from Matomo (e.g. invalid `idSite`): surface |
| 98 | the message verbatim; do not guess. |
| 99 | Connection / SSL / timeout: report the network failure class |
| 100 | (`ConnectionError`, `SSLError`, `timeout`) and confirm |
| 101 | `MATOMO_URL` resolves. |
| 102 | |
| 103 | ## Output Formatting |
| 104 | |
| 105 | Tables for time-series, device, and country data. |
| 106 | Critical / High / Medium / Low priority for any cross-skill actions |
| 107 | surfaced from Matomo data. |
| 108 | Always label the data source as "Matomo Reporting API (live)" to |
| 109 | distinguish from GA4, CrUX, or static crawl analysis. |
| 110 | For organic keywords, surface the `anonymized_share_pct` prominently. |
| 111 | Many keywords will be "(not provided)" due to browser privacy and |
| 112 | Matomo's anonymization rules; this is normal, not a data bug. |
Discussion
Browse more free Claude skills or everything in Marketing.