# 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 `` | 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.