Files
odoo-expertos.com/growth/SEO-REPORT-2026-10-24.md
Hermes Agent 1dde14a821 Add first SEO report (2026-10-24)
Produced by the new 'seo' profile from live data: webhook (Plausible + Search
Console), audit_site.py, git log. Scorecard, technical progress, ranking
opportunities, 8 action items, open risks. All figures cross-checked against
the scripts (317 hreflang pages, 679 broken targets, 1,370 occurrences,
23 relative canonicals, 18 missing canonicals, sitemap 1,191 of 1,202).
2026-10-24 19:41:03 +00:00

222 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SEO report — odoo-expertos.com — 2026-10-24
Data sources: `website_stats.py` (n8n webhook: Plausible + Search Console, range
2026-01-01 → 2026-10-24), `audit_site.py . /tmp/seo_audit.json`, `git log`, and live
`curl` checks. Baseline: `growth/BASELINE.md`, captured the same day.
## Executive summary
Across 4,745 impressions in ten months the site earned **9 clicks (CTR 0.19%, average
position 24.7)**, and the money cluster — 33 hosting queries, 538 impressions — sits at
**position 27.5 with 1 click**, so almost nobody who sees the site reaches a hosting page.
The technical cleanup did land: broken internal link occurrences fell from 4,029 to 1,370
and 136 canonicals that pointed at dead URLs were repaired. But this first report has no
elapsed time — the baseline was captured today — so every Search Console and Plausible
number below is identical by construction; the only measured change is technical. Two
things are therefore unknown rather than good: affiliate clicks have no Plausible goal, and
Plausible recorded 2 visitors, both owner/test traffic, which is too small to read as demand.
## Scorecard
Baseline and "now" are the same snapshot (both 2026-10-24), so "trend" is flat by
definition. This table becomes a trend table from the 2026-10-31 run onward.
| metric | baseline (2026-10-24) | now (2026-10-24) | trend |
|---|---|---|---|
| GSC impressions | 4,745 | 4,745 | flat — same snapshot |
| GSC clicks | 9 | 9 | flat — same snapshot |
| GSC CTR | 0.19% | 0.19% | flat — same snapshot |
| GSC average position | 24.7 | 24.7 | flat — same snapshot |
| Money-cluster position (`hosting*`) | 27.5 (33q, 538 impr, 1 click) | 27.5 (33q, 538 impr, 1 click) | flat — same snapshot |
| Plausible visitors | 2 | 2 (2 visits, 3 pageviews) | flat — same snapshot |
| Affiliate clicks | n/a | n/a | n/a — no `Affiliate Click` goal exists |
Why affiliate clicks are n/a: the Plausible goal block (`event:goal`) returns only one row,
the page goal `Visit /` with 1 visitor. No `Affiliate Click` or `Outbound Click` goal is
configured, so the custom events are not countable in the payload even if they fire. The
north-star metric is currently unmeasured, not zero. Separately, commission attribution on
odoo4projects.com is not visible from this environment and is not reported here.
Context for the 2 visitors: both are in the week of 2026-10-19 (United States and Paraguay),
consistent with owner/test traffic. No organic traffic signal exists yet.
## Technical progress
Commit `a6cff06` ("Cleanup: fix 2,659 dead internal URLs…", 2026-10-24 19:25 UTC) is the
change this section measures. It is pushed: `HEAD` and `origin/main` are both `8b80c6c`.
| item | before | after | evidence |
|---|---|---|---|
| Broken internal link occurrences | 4,029 | 1,370 | commit `a6cff06` body; audit `broken_internal_count: 1370` |
| Unique broken targets remaining | — | 679 | full scan with `audit_site.resolve/exists`: 1,370 occurrences across 679 targets; audit JSON details only the top 60 |
| Canonicals pointing at a case variant that 404s | 93 | 0 | commit `a6cff06` body |
| Canonicals pointing at a deleted path | 43 | 0 (now self-canonical) | commit `a6cff06` body |
| Dead `<link rel=alternate icon href=/favicon.ico>` | 1,197 | 0 | commit `a6cff06` body |
| Dead `/styles/*.css` (Next.js leftovers) | 96 | 0 | commit `a6cff06` body |
| `/_vercel/insights` scripts (previous host) | 3 | 0 | commit `a6cff06` body |
| Missing assets | — | 0 | audit `missing_assets_count: 0` |
| Bad in-page anchors | — | 0 | audit `bad_anchor_count: 0` |
| Duplicate titles / descriptions | — | 0 / 0 | audit `duplicate_titles: []`, `duplicate_descriptions: []` |
| Images without alt | — | 0 | audit `img_without_alt: 0` |
| HTML files | 1,208 | 1,202 | audit `pages: 1202`; 1,208 minus 3 duplicate pages deleted and 3 archived audit HTML files the audit excludes |
Remaining broken targets, first entries in the audit's capped list: `/contacto/`,
`/servicios`, `/servicios-implementacion-odoo`, `/servicios-consulta-odoo`,
`/implementacion-odoo`, `/about`, `/odoo-ai/odoo-chatbot-ai-atencion-client-2025/`,
`/odoo-ai/odoo-dashboard-ai-paneles-smarts-2025/`, plus cross-locale links into French and
German 2026 hosting pages (`/fr/odoo-hosting/meilleur-hebergement-odoo-2026/`,
`/de/odoo-hosting/odoo-sh-alternativen-2026/`, and others). Two were confirmed live:
`https://www.odoo-expertos.com/servicios` → HTTP 404, and
`https://www.odoo-expertos.com/odoo-ai/odoo-chatbot-ai-atencion-client-2025/` → HTTP 404.
Note that `/odoo-ai/` failures are not case drift — the real section is `/odoo-ia/`, a
different path, so the case-insensitive rewrite could not fix them.
## Ranking opportunities
### Page-1 zero-click queries
17 queries rank on page 1 (position ≤ 10) with zero clicks and ≥ 20 impressions, holding
**1,090 impressions — 23.0% of all impressions** (per `website_stats.py`).
| query | impressions | position | clicks |
|---|---:|---:|---:|
| odo ia | 279 | 6.8 | 0 |
| odoo de donde es | 154 | 5.3 | 0 |
| de donde es odoo | 115 | 4.9 | 0 |
| odoo honduras | 81 | 9.4 | 0 |
| .odo ia | 66 | 7.6 | 0 |
| odoo origen | 60 | 7.7 | 0 |
| odoobot que es | 56 | 8.8 | 0 |
| ,odo ia | 32 | 6.9 | 0 |
| docker odoo 20 | 32 | 6.6 | 0 |
| odoo 20 docker | 32 | 6.5 | 0 |
| odoo de que pais es | 32 | 6.8 | 0 |
| hosting economicos | 30 | 3.9 | 0 |
| odoo inmobiliaria | 27 | 9.4 | 0 |
| odoo bot | 25 | 8.3 | 0 |
| odoo de donde es originario | 25 | 4.5 | 0 |
| odoo empresa de donde es | 23 | 5.4 | 0 |
| quien creo odoo | 21 | 6.4 | 0 |
At a 1.5% CTR these impressions would produce roughly 16 clicks over the same window,
taking site-wide CTR from 0.19% to about 0.53% (25 clicks / 4,745 impressions). That is
arithmetic on current impressions, not a forecast of ranking movement.
### Position 8–20 clusters
34 queries with ≥10 impressions rank between positions 8 and 20, totaling 1,094
impressions. Grouped by topic (a query appears in one group only):
| cluster | queries | impressions | clicks | avg position | examples |
|---|---:|---:|---:|---:|---|
| LatAm | 5 | 214 | 3 | 9.7 | odoo bolivia (84 @ 8.4, 3 clicks), odoo honduras (81 @ 9.4, 0) |
| AI / Odoo IA | 3 | 183 | 0 | 14.0 | odoo ia (118 @ 15.0), ia odoo (43 @ 12.5) |
| Brand / company | 4 | 176 | 1 | 13.0 | odoo experts (75 @ 13.7, 0 clicks) |
| Demo | 3 | 145 | 1 | 15.1 | demo odoo (63 @ 12.4), odoo demo (63 @ 17.0) |
| Chatbot / OdooBot | 4 | 138 | 1 | 9.0 | odoobot (34 @ 10.4), odoo bot (25 @ 8.3) |
| Hosting / deployment | 6 | 104 | 0 | 15.4 | odoo vps (24 @ 14.6), odoo digitalocean (22 @ 17.5), odoo docker (20 @ 14.1) |
The LatAm group already converts (3 of the 9 site-wide clicks); the AI and hosting groups
sit one page short of visibility with no clicks. `odoo experts` is the clearest brand
miss: the domain is odoo-expertos.com but the query ranks 13.7 with 75 impressions and 0
clicks.
Head-term anchors for later comparison: `odoo hosting` 298 impressions, 1 click, position
31.5; `hosting odoo` 85 impressions, 0 clicks, position 28.5; `odoo beratung` 155
impressions, 0 clicks, position 51.5.
## Action items
Ordered by expected value. "Scheduled" means it already appears in `PLAN.md` weeks 2–7.
**1. Create the `Affiliate Click` and `Outbound Click` goals in Plausible — S — not scheduled.**
Why: the plan's north-star metric cannot be read today; the goal block returns only
`Visit /`. Expected effect: no traffic change, but it turns every later verdict from
opinion into data. Proves it: the `event:goal` block returns rows named `Affiliate Click`
and `Outbound Click` with non-null events. Note the skill documents that adding a partner
is one line in `js/plausible-events.js`; the goals themselves are dashboard settings, not a
code change.
**2. Rewrite title + meta description for the page-1 zero-click queries — M — scheduled weeks 3–6.**
Why: 1,090 impressions already reach page 1 and get 0 clicks; the snippet, not the
ranking, is failing. Expected effect: at 1.5% CTR, ~16 clicks over an equivalent window.
Proves it: CTR on those 17 queries. Start with `odo ia` (279), `odoo de donde es` (154),
`de donde es odoo` (115), `odoo honduras` (81). Four pages per week as planned.
**3. Strip the fabricated testimonials, ISO 27001 / SOC 2 / "200+ proyectos" badges and the placeholder phone — S — scheduled week 2.**
Why: invented proof is an E-E-A-T and legal liability and weakens the affiliate pitch.
Expected effect: no ranking gain assumed; the value is risk removal and trust. Proves it:
impressions on the affected URLs must not fall (guardrail), with outbound CTR as the
secondary read. There are 3 testimonials and 8 pages with the placeholder phone per
`BASELINE.md`; remove rather than replace with new claims, and use the host's real customer
list only if each site still loads.
**4. Consolidate the ~40 near-duplicate `/odoo-hosting/*` pages per locale — L — scheduled weeks 8–10 (outside 2–7).**
Why: they cannibalize the hub for the money terms; `odoo hosting` is at 31.5 and
`hosting odoo` at 28.5. Expected effect: consolidating authority should move the surviving
hub toward page 2 and then page 1. Proves it: position of `hosting odoo` and `odoo hosting`,
plus hub impressions. Do not delete any URL with impressions before checking it in GSC.
**5. Fix the remaining 1,370 broken internal link occurrences (679 unique targets) — M — not scheduled.**
Why: 1,370 dead ends waste crawl paths and send readers to 404s; `/servicios` and the
`/odoo-ai/...` articles are live 404s today. Expected effect: no direct ranking number —
it removes 1,370 failure points and restores internal link flow to real pages. Proves it:
`broken_internal_count` from `audit_site.py` reaches 0. Many targets are site-wide
navigation links, so the fix is a handful of templates, not 1,370 edits.
**6. Fix the `odoo experts` brand query — S — not scheduled.**
Why: 75 impressions at position 13.7 with 0 clicks from a query that matches the domain
name is a lost brand click. Expected effect: page-1 entry for the brand query; small
volume, high relevance. Proves it: position and CTR for `odoo experts`. Likely a
title/H1 mismatch on the English homepage.
**7. Fill or remove the 0-byte PT page — S — scheduled week 7.**
Why: `pt/odoo-ia/odoo-sistema-reservas-booking-ia-2025/index.html` is 0 bytes, returns
HTTP 200 with 0 bytes, and is in the PT sitemap. Expected effect: removes one empty
soft-404 and an index-coverage defect. Proves it: the URL either has substantial content
or is gone from `sitemap-pt.xml` after `./generate_sitemap.sh`.
**8. Resolve the 23 relative canonicals and 18 pages without a canonical — M — not scheduled.**
Why: 23 canonicals on `en/` and `fr/` pages are host-relative (e.g. `en/odoo-ia/index.html`
→ `/odoo-ia/`), so the canonical host depends on which host served the page, and apex and
www both serve 200 without redirecting. Expected effect: removes ambiguity about which URL
is canonical; protects the 153 cross-locale canonicals that are intentional strategy.
Proves it: `canonical_not_www` and `no_canonical` in the audit reach 0 (excluding the
legal/404 pages deliberately left without one). Do not change cross-locale canonicals
themselves — that is a strategy, and touching it re-indexes ~150 pages.
## Open risks
- **Empty page is indexable.** `pt/odoo-ia/odoo-sistema-reservas-booking-ia-2025/` is 0
bytes on disk, returns `200` with `size_download 0` live, and is listed in the PT
sitemap. That is a soft-404 candidate.
- **Relative canonicals lack a host.** Audit `canonical_not_www: 23`; all are on `en/` and
`fr/` pages and use paths such as `/odoo-ia/`. Because the apex serves the same bytes as
www with no redirect, the canonical resolves to whichever host the crawler used.
- **18 pages have no canonical at all** (`no_canonical: 18`), including `404.html`,
`cookie-policy.html`, `terms-of-use.html`, `privacy-policy.html`, and locale duplicates
of the same article.
- **hreflang coverage is 26%.** 317 of 1,202 audited HTML files contain an `hreflang` tag, while
153 pages canonicalise to another locale. Pages that are cross-locale canonicalised
without hreflang give Google no signal that a translation exists.
- **1,370 broken internal links across 679 unique targets.** Confirmed live 404s:
`/servicios` and `/odoo-ai/odoo-chatbot-ai-atencion-client-2025/`. The audit also reports
`h1_not_one: 19` and `pages_without_title: 1` / `pages_without_description: 1`; the
0-byte PT page would produce the latter.
- **Sitemap does not cover the site.** `sitemap_url_count: 1191` against 1,202 audited HTML pages,
so 11 pages are not in any sitemap. Some are legal/404 pages by design; that has not been
verified page by page.
- **Internal strategy is publicly readable.** `https://www.odoo-expertos.com/growth/PLAN.md`
returns HTTP 200 with 7,426 bytes. `robots.txt` carries `Disallow: /*.md$`, which is
advisory only and does not restrict direct access. Anything committed under `growth/` is
public.
- **No attribution visibility.** Affiliate clicks are unmeasured (no goal) and commission
reported by odoo4projects.com is not accessible here. Nothing in this report should be
read as revenue evidence.
## Next review date
2026-10-31. The 2026-10-31 run is the first one with an elapsed week, so it is the first
that can show a real trend rather than a same-snapshot comparison.