Self-contained (no external assets), dark theme matching the site accent, print friendly. Carries a machine-readable <script id=seo-metrics> JSON block so next week's run can diff against it instead of re-deriving last week's numbers. The Friday job now renders from templates/seo-report.html.
257 lines
19 KiB
HTML
257 lines
19 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="robots" content="noindex, nofollow">
|
||
<title>SEO report — odoo-expertos.com — 2026-10-24</title>
|
||
<style>
|
||
:root{
|
||
--bg:#0e1116; --panel:#161b22; --line:#272d36; --text:#e6edf3; --muted:#8b949e;
|
||
--accent:#ff6b35; --good:#3fb950; --warn:#d29922; --bad:#f85149; --blue:#58a6ff;
|
||
}
|
||
*{box-sizing:border-box}
|
||
body{margin:0;background:var(--bg);color:var(--text);
|
||
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||
-webkit-font-smoothing:antialiased}
|
||
.wrap{max-width:1080px;margin:0 auto;padding:40px 24px 80px}
|
||
header{border-bottom:1px solid var(--line);padding-bottom:24px;margin-bottom:32px}
|
||
.eyebrow{color:var(--accent);font-size:12px;letter-spacing:.14em;text-transform:uppercase;font-weight:700}
|
||
h1{font-size:30px;line-height:1.2;margin:8px 0 10px}
|
||
h2{font-size:19px;margin:40px 0 14px;padding-bottom:8px;border-bottom:1px solid var(--line)}
|
||
h3{font-size:15px;margin:24px 0 10px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}
|
||
p{margin:0 0 14px}
|
||
.meta{color:var(--muted);font-size:13px}
|
||
.chip{display:inline-block;padding:2px 9px;border:1px solid var(--line);border-radius:999px;
|
||
font-size:12px;color:var(--muted);margin:6px 6px 0 0}
|
||
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin:24px 0 4px}
|
||
.kpi{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:16px}
|
||
.kpi .label{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}
|
||
.kpi .value{font-size:26px;font-weight:700;margin-top:6px;font-variant-numeric:tabular-nums}
|
||
.kpi .sub{font-size:12px;color:var(--muted);margin-top:2px}
|
||
.flat{color:var(--muted)}
|
||
.na{color:var(--warn)}
|
||
table{width:100%;border-collapse:collapse;margin:14px 0 8px;font-size:14px}
|
||
th,td{text-align:left;padding:9px 10px;border-bottom:1px solid var(--line)}
|
||
th{color:var(--muted);font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.05em}
|
||
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}
|
||
tbody tr:hover{background:#1b2029}
|
||
.bar{height:6px;background:var(--accent);border-radius:3px;min-width:2px;display:inline-block;vertical-align:middle}
|
||
.barwrap{width:120px;display:inline-block}
|
||
.callout{background:#1b2029;border-left:3px solid var(--accent);padding:14px 16px;border-radius:0 8px 8px 0;margin:16px 0}
|
||
.callout.warn{border-left-color:var(--warn)}
|
||
.action{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:16px 18px;margin:12px 0}
|
||
.action h4{margin:0 0 6px;font-size:15px}
|
||
.action .why{color:var(--muted);font-size:14px;margin:0 0 10px}
|
||
.action .row{display:flex;flex-wrap:wrap;gap:8px}
|
||
.pill{font-size:11.5px;padding:3px 9px;border-radius:999px;border:1px solid var(--line);color:var(--muted)}
|
||
.pill.s{color:var(--good);border-color:#1f6f3a}
|
||
.pill.m{color:var(--warn);border-color:#6b5320}
|
||
.pill.l{color:var(--bad);border-color:#7d2b28}
|
||
.pill.sched{color:var(--blue);border-color:#1f4b7a}
|
||
.num-badge{display:inline-flex;width:22px;height:22px;border-radius:50%;background:var(--accent);
|
||
color:#0e1116;font-weight:700;font-size:12px;align-items:center;justify-content:center;margin-right:8px}
|
||
ul.risks{padding-left:18px}
|
||
ul.risks li{margin:8px 0}
|
||
code{background:#21262d;padding:1px 6px;border-radius:4px;font-size:13px}
|
||
footer{margin-top:56px;padding-top:20px;border-top:1px solid var(--line);color:var(--muted);font-size:13px}
|
||
@media print{
|
||
body{background:#fff;color:#111}
|
||
.kpi,.action,.callout{border-color:#ddd;background:#fafafa}
|
||
h2{border-color:#ddd}
|
||
a{color:#111}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
|
||
<header>
|
||
<div class="eyebrow">SEO report</div>
|
||
<h1>odoo-expertos.com</h1>
|
||
<div class="meta">2026-10-24 · first report · Search Console range 2026-01-01 → 2026-10-24</div>
|
||
<div>
|
||
<span class="chip">website_stats.py — Plausible + GSC</span>
|
||
<span class="chip">audit_site.py</span>
|
||
<span class="chip">git log</span>
|
||
<span class="chip">live curl checks</span>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="callout">
|
||
<strong>The number that matters:</strong> the money cluster (33 hosting queries, 538 impressions)
|
||
sits at <strong>position 27.5 with 1 click</strong>, while the site earns 4,745 impressions and
|
||
9 clicks overall at 0.19% CTR. Almost nobody who sees the site reaches a hosting page.
|
||
The technical cleanup landed — broken internal links fell from 4,029 to 1,370 — but this is the
|
||
first report, so no metric has had time to move.
|
||
</div>
|
||
|
||
<div class="kpis">
|
||
<div class="kpi"><div class="label">Impressions</div><div class="value">4,745</div><div class="sub flat">baseline — no prior period</div></div>
|
||
<div class="kpi"><div class="label">Clicks</div><div class="value">9</div><div class="sub flat">10 months</div></div>
|
||
<div class="kpi"><div class="label">CTR</div><div class="value">0.19%</div><div class="sub flat">page 1 would be 1.5%+</div></div>
|
||
<div class="kpi"><div class="label">Avg position</div><div class="value">24.7</div><div class="sub flat">money cluster 27.5</div></div>
|
||
<div class="kpi"><div class="label">Plausible visitors</div><div class="value">2</div><div class="sub flat">owner/test traffic</div></div>
|
||
<div class="kpi"><div class="label">Affiliate clicks</div><div class="value na">n/a</div><div class="sub">no goal configured</div></div>
|
||
</div>
|
||
|
||
<h2>Scorecard</h2>
|
||
<p class="meta">Baseline and “now” are the same snapshot, so the trend is flat by construction. This becomes a real trend table from the 2026-10-31 run.</p>
|
||
<table>
|
||
<thead><tr><th>Metric</th><th class="num">Baseline</th><th class="num">Now</th><th>Trend</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>GSC impressions</td><td class="num">4,745</td><td class="num">4,745</td><td class="flat">flat — same snapshot</td></tr>
|
||
<tr><td>GSC clicks</td><td class="num">9</td><td class="num">9</td><td class="flat">flat — same snapshot</td></tr>
|
||
<tr><td>GSC CTR</td><td class="num">0.19%</td><td class="num">0.19%</td><td class="flat">flat — same snapshot</td></tr>
|
||
<tr><td>Average position</td><td class="num">24.7</td><td class="num">24.7</td><td class="flat">flat — same snapshot</td></tr>
|
||
<tr><td>Money cluster (<code>hosting*</code>)</td><td class="num">27.5</td><td class="num">27.5</td><td class="flat">33q · 538 impr · 1 click</td></tr>
|
||
<tr><td>Plausible visitors</td><td class="num">2</td><td class="num">2</td><td class="flat">2 visits · 3 pageviews</td></tr>
|
||
<tr><td>Affiliate clicks</td><td class="num">n/a</td><td class="num">n/a</td><td class="na">no <code>Affiliate Click</code> goal</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="meta">Affiliate clicks are unmeasured, not zero: the Plausible goal block returns only the page goal <code>Visit /</code> with 1 visitor. Commission attribution on odoo4projects.com is not visible from this environment and is not reported here.</p>
|
||
|
||
<h2>Technical progress</h2>
|
||
<p>Commit <code>a6cff06</code> is the change this section measures; <code>HEAD</code> is <code>0d2ecdb</code>.</p>
|
||
<table>
|
||
<thead><tr><th>Item</th><th class="num">Before</th><th class="num">After</th><th>Evidence</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Broken internal link occurrences</td><td class="num">4,029</td><td class="num">1,370</td><td class="flat">audit <code>broken_internal_count</code></td></tr>
|
||
<tr><td>Unique broken targets</td><td class="num">—</td><td class="num">679</td><td class="flat">full scan</td></tr>
|
||
<tr><td>Canonicals pointing at a 404</td><td class="num">136</td><td class="num">0</td><td class="flat">93 case-drift + 43 dead</td></tr>
|
||
<tr><td>Dead favicon / styles / analytics tags</td><td class="num">1,296</td><td class="num">0</td><td class="flat">1,197 + 96 + 3</td></tr>
|
||
<tr><td>Missing assets</td><td class="num">3</td><td class="num">0</td><td class="flat">audit <code>missing_assets_count</code></td></tr>
|
||
<tr><td>Bad in-page anchors</td><td class="num">—</td><td class="num">0</td><td class="flat">audit <code>bad_anchor_count</code></td></tr>
|
||
<tr><td>Duplicate titles / descriptions</td><td class="num">—</td><td class="num">0 / 0</td><td class="flat">audit</td></tr>
|
||
<tr><td>HTML pages</td><td class="num">1,208</td><td class="num">1,202</td><td class="flat">3 duplicate pages deleted</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="meta">Still broken and unfixable automatically: <code>/contacto/</code>, <code>/servicios</code>,
|
||
<code>/implementacion-odoo</code>, <code>/about</code> (old-site routes, 70 occurrences) and 35 locale
|
||
hosting pages that were never created (175 occurrences). <code>/odoo-ai/…</code> is not case drift —
|
||
the real section is <code>/odoo-ia/</code>, a different path.</p>
|
||
|
||
<h2>Ranking opportunities</h2>
|
||
|
||
<h3>Page 1, zero clicks — 17 queries, 1,090 impressions (23% of all)</h3>
|
||
<table>
|
||
<thead><tr><th>Query</th><th class="num">Impressions</th><th></th><th class="num">Position</th><th class="num">Clicks</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>odo ia</td><td class="num">279</td><td><span class="barwrap"><span class="bar" style="width:100%"></span></span></td><td class="num">6.8</td><td class="num">0</td></tr>
|
||
<tr><td>odoo de donde es</td><td class="num">154</td><td><span class="barwrap"><span class="bar" style="width:55%"></span></span></td><td class="num">5.3</td><td class="num">0</td></tr>
|
||
<tr><td>de donde es odoo</td><td class="num">115</td><td><span class="barwrap"><span class="bar" style="width:41%"></span></span></td><td class="num">4.9</td><td class="num">0</td></tr>
|
||
<tr><td>odoo honduras</td><td class="num">81</td><td><span class="barwrap"><span class="bar" style="width:29%"></span></span></td><td class="num">9.4</td><td class="num">0</td></tr>
|
||
<tr><td>.odo ia</td><td class="num">66</td><td><span class="barwrap"><span class="bar" style="width:24%"></span></span></td><td class="num">7.6</td><td class="num">0</td></tr>
|
||
<tr><td>odoo origen</td><td class="num">60</td><td><span class="barwrap"><span class="bar" style="width:22%"></span></span></td><td class="num">7.7</td><td class="num">0</td></tr>
|
||
<tr><td>odoobot que es</td><td class="num">56</td><td><span class="barwrap"><span class="bar" style="width:20%"></span></span></td><td class="num">8.8</td><td class="num">0</td></tr>
|
||
<tr><td>docker odoo 20 · odoo 20 docker</td><td class="num">64</td><td><span class="barwrap"><span class="bar" style="width:23%"></span></span></td><td class="num">6.6</td><td class="num">0</td></tr>
|
||
<tr><td>odoo de que pais es</td><td class="num">32</td><td><span class="barwrap"><span class="bar" style="width:11%"></span></span></td><td class="num">6.8</td><td class="num">0</td></tr>
|
||
<tr><td>hosting economicos</td><td class="num">30</td><td><span class="barwrap"><span class="bar" style="width:11%"></span></span></td><td class="num">3.9</td><td class="num">0</td></tr>
|
||
<tr><td>odoo inmobiliaria</td><td class="num">27</td><td><span class="barwrap"><span class="bar" style="width:10%"></span></span></td><td class="num">9.4</td><td class="num">0</td></tr>
|
||
<tr><td>odoo bot</td><td class="num">25</td><td><span class="barwrap"><span class="bar" style="width:9%"></span></span></td><td class="num">8.3</td><td class="num">0</td></tr>
|
||
<tr><td>odoo de donde es originario</td><td class="num">25</td><td><span class="barwrap"><span class="bar" style="width:9%"></span></span></td><td class="num">4.5</td><td class="num">0</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="meta">At a 1.5% CTR these impressions would produce roughly 16 clicks over the same window.</p>
|
||
|
||
<h3>Positions 8–20 — 34 queries, 1,094 impressions</h3>
|
||
<table>
|
||
<thead><tr><th>Cluster</th><th class="num">Queries</th><th class="num">Impressions</th><th class="num">Clicks</th><th class="num">Avg pos</th><th>Example</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>LatAm</td><td class="num">5</td><td class="num">214</td><td class="num">3</td><td class="num">9.7</td><td><code>odoo bolivia</code> 84 @ 8.4</td></tr>
|
||
<tr><td>AI / Odoo IA</td><td class="num">3</td><td class="num">183</td><td class="num">0</td><td class="num">14.0</td><td><code>odoo ia</code> 118 @ 15.0</td></tr>
|
||
<tr><td>Brand / company</td><td class="num">4</td><td class="num">176</td><td class="num">1</td><td class="num">13.0</td><td><code>odoo experts</code> 75 @ 13.7</td></tr>
|
||
<tr><td>Demo</td><td class="num">3</td><td class="num">145</td><td class="num">1</td><td class="num">15.1</td><td><code>demo odoo</code> 63 @ 12.4</td></tr>
|
||
<tr><td>Chatbot / OdooBot</td><td class="num">4</td><td class="num">138</td><td class="num">1</td><td class="num">9.0</td><td><code>odoobot</code> 34 @ 10.4</td></tr>
|
||
<tr><td>Hosting / deployment</td><td class="num">6</td><td class="num">104</td><td class="num">0</td><td class="num">15.4</td><td><code>odoo vps</code> 24 @ 14.6</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="meta">Head terms for later comparison: <code>odoo hosting</code> 298 impr · pos 31.5 · 1 click;
|
||
<code>hosting odoo</code> 85 · 28.5 · 0; <code>odoo beratung</code> 155 · 51.5 · 0.</p>
|
||
|
||
<h2>Action items</h2>
|
||
|
||
<div class="action">
|
||
<h4><span class="num-badge">1</span>Create the Affiliate Click and Outbound Click goals</h4>
|
||
<p class="why">The north-star metric cannot be read today — the goal block returns only <code>Visit /</code>. No traffic change, but it turns every later verdict from opinion into data. Proves it: the <code>event:goal</code> block returns both names with non-null events.</p>
|
||
<div class="row"><span class="pill s">Effort S</span><span class="pill">not scheduled</span><span class="pill">dashboard setting, not code</span></div>
|
||
</div>
|
||
|
||
<div class="action">
|
||
<h4><span class="num-badge">2</span>Rewrite title + meta for the page-1 zero-click queries</h4>
|
||
<p class="why">1,090 impressions already reach page 1 and earn 0 clicks — the snippet is failing, not the ranking. At 1.5% CTR that is ~16 clicks. Start with <code>odo ia</code>, <code>odoo de donde es</code>, <code>de donde es odoo</code>, <code>odoo honduras</code>.</p>
|
||
<div class="row"><span class="pill m">Effort M</span><span class="pill sched">PLAN weeks 3–6</span><span class="pill">metric: CTR on those 17</span></div>
|
||
</div>
|
||
|
||
<div class="action">
|
||
<h4><span class="num-badge">3</span>Strip the fabricated testimonials, ISO/SOC badges and placeholder phone</h4>
|
||
<p class="why">Invented proof is an E-E-A-T and legal liability. 3 testimonials, 113 pages claiming ISO 27001, 80 claiming SOC 2, 8 pages with a placeholder phone. Value is risk removal, not ranking.</p>
|
||
<div class="row"><span class="pill s">Effort S</span><span class="pill sched">PLAN week 2</span><span class="pill">guardrail: impressions must not fall</span></div>
|
||
</div>
|
||
|
||
<div class="action">
|
||
<h4><span class="num-badge">4</span>Consolidate the ~40 near-duplicate hosting pages per locale</h4>
|
||
<p class="why">They cannibalize the hub for the money terms. <code>odoo hosting</code> 31.5, <code>hosting odoo</code> 28.5. Check GSC per URL before deleting anything with impressions.</p>
|
||
<div class="row"><span class="pill l">Effort L</span><span class="pill sched">PLAN weeks 8–10</span><span class="pill">metric: position of both head terms</span></div>
|
||
</div>
|
||
|
||
<div class="action">
|
||
<h4><span class="num-badge">5</span>Fix the remaining 1,370 broken internal links (679 targets)</h4>
|
||
<p class="why">Dead ends waste crawl paths and send readers to 404s. <code>/servicios</code> and the <code>/odoo-ai/…</code> articles are live 404s now. Many are site-wide navigation links, so the fix is a handful of templates.</p>
|
||
<div class="row"><span class="pill m">Effort M</span><span class="pill">not scheduled</span><span class="pill">metric: broken_internal_count → 0</span></div>
|
||
</div>
|
||
|
||
<div class="action">
|
||
<h4><span class="num-badge">6</span>Fix the <code>odoo experts</code> brand query</h4>
|
||
<p class="why">75 impressions at position 13.7 with 0 clicks on a query that matches the domain name. Likely a title/H1 mismatch on the English homepage.</p>
|
||
<div class="row"><span class="pill s">Effort S</span><span class="pill">not scheduled</span><span class="pill">metric: position + CTR</span></div>
|
||
</div>
|
||
|
||
<div class="action">
|
||
<h4><span class="num-badge">7</span>Fill or remove the 0-byte PT page</h4>
|
||
<p class="why"><code>pt/odoo-ia/odoo-sistema-reservas-booking-ia-2025/</code> is 0 bytes, returns 200 with an empty body and sits in the PT sitemap. A soft-404 candidate.</p>
|
||
<div class="row"><span class="pill s">Effort S</span><span class="pill sched">PLAN week 7</span><span class="pill">metric: index coverage</span></div>
|
||
</div>
|
||
|
||
<div class="action">
|
||
<h4><span class="num-badge">8</span>Resolve 23 relative canonicals and 18 pages without one</h4>
|
||
<p class="why">Canonicals like <code>/odoo-ia/</code> carry no host, so they resolve to whichever host served the page — and apex and www both answer 200. Do not touch the cross-locale canonicals; that is intentional strategy.</p>
|
||
<div class="row"><span class="pill m">Effort M</span><span class="pill">not scheduled</span><span class="pill">metric: canonical_not_www → 0</span></div>
|
||
</div>
|
||
|
||
<h2>Open risks</h2>
|
||
<ul class="risks">
|
||
<li><strong>Empty page is indexable.</strong> 0 bytes on disk, HTTP 200 with an empty body live, listed in the PT sitemap.</li>
|
||
<li><strong>Relative canonicals lack a host.</strong> 23 of them, on <code>en/</code> and <code>fr/</code> pages.</li>
|
||
<li><strong>18 pages have no canonical</strong>, including the legal pages and some locale duplicates.</li>
|
||
<li><strong>hreflang coverage is 26%</strong> — 317 of 1,202 pages, while 153 pages canonicalise to another locale.</li>
|
||
<li><strong>1,370 broken internal links across 679 targets</strong>, with <code>/servicios</code> and one <code>/odoo-ai/…</code> article confirmed 404 live.</li>
|
||
<li><strong>Sitemap covers 1,191 of 1,202 pages</strong> — 11 pages are in no sitemap; some are legal/404 by design, unverified page by page.</li>
|
||
<li><strong>Internal strategy is publicly readable</strong> — <code>/growth/PLAN.md</code> returns 200 with 7,426 bytes. <code>Disallow: /*.md$</code> is advisory only.</li>
|
||
<li><strong>No attribution visibility.</strong> Nothing here is revenue evidence.</li>
|
||
</ul>
|
||
|
||
<footer>
|
||
Next review: <strong>2026-10-31</strong> — the first run with an elapsed week, and therefore the
|
||
first that can show a real trend instead of a same-snapshot comparison.<br>
|
||
Generated by the <code>seo</code> Hermes profile from live tool output. No estimated or invented figures.
|
||
</footer>
|
||
|
||
</div>
|
||
<script type="application/json" id="seo-metrics">
|
||
{
|
||
"date": "2026-10-24",
|
||
"gsc": {"impressions": 4745, "clicks": 9, "ctr": 0.19, "position": 24.7, "queries": 447},
|
||
"money_cluster": {"queries": 33, "impressions": 538, "clicks": 1, "position": 27.5},
|
||
"plausible": {"visitors": 2, "visits": 2, "pageviews": 3},
|
||
"affiliate_clicks": null,
|
||
"technical": {"broken_links": 1370, "broken_targets": 679, "canonicals_fixed": 136,
|
||
"pages": 1202, "hreflang_pages": 317, "no_canonical": 18,
|
||
"relative_canonicals": 23, "sitemap_urls": 1191},
|
||
"opportunities": {"page1_zero_click_queries": 17, "page1_zero_click_impressions": 1090,
|
||
"pos8_20_queries": 34, "pos8_20_impressions": 1094}
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|