| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Website (website)
• Discuss (mail) |
| Lines of code | 44 |
| Technical Name |
website_seo_protection |
| License | OPL-1 |
| Website | https://www.ganemo.co |
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Website (website)
• Discuss (mail) |
| Lines of code | 44 |
| Technical Name |
website_seo_protection |
| License | OPL-1 |
| Website | https://www.ganemo.co |
SEO Crawler Guard
Block Bots & Protect Your Odoo Server
Appointment URL crawler traps can kill your Odoo server workers via out-of-memory errors. This module stops the attack at the HTTP layer — before any database query runs.
What We're Solving
----------------
Appointment Crawler Traps
Odoo's appointment pager generates URLs with a
?domain= parameter containing a fresh
datetime.datetime() value — unique every millisecond.
Web crawlers follow every link, creating thousands of unique
requests that exhaust Odoo worker memory (signal 9, worker killed).
Calendar Date Indexing
Appointment calendar day-links include ?date= or ?datetime= parameters. While not malicious, they should not be indexed by search engines — they pollute your crawl budget and duplicate page content, hurting SEO rankings.
How It Works
Two-Layer HTTP Protection
Layer 1: Block Crawler Trap (HTTP 404)
Detects and destroys trap URLs before any Odoo code processes them:
- Checks if the request path is an appointment URL.
- Inspects
?domain=query parameter fordatetimepatterns.
- Returns HTTP 404 immediately — zero DB load.
- Also sets
X-Robots-Tag: noindexon the 404 response.
/[lang/]appointment[/page/N]?domain=...datetime.datetime(...)...
Layer 2: Noindex Calendar Pages
For valid appointment calendar links that should not be indexed:
Smart Detection
Only applies to HTML responses for appointment paths
that contain ?date= or ?datetime= parameters.
Other pages are untouched.
Header Injection
Adds X-Robots-Tag: noindex, nofollow to
the HTTP response header — the safest way to prevent indexing without
altering page markup.
Multilingual Support
Regex covers all Odoo language prefixes:
/en/, /es/, /pt_BR/,
/zh-hans/, and more.
Zero Performance Impact
No database queries. No ORM calls. Pure HTTP-level interception using Werkzeug/Odoo's existing dispatch hook.
Setup & User Manual
Step-by-Step Implementation
Step 1: Install the Module
The installation process takes less than 2 minutes and requires no technical background:
- Go to Apps in your Odoo backend (top navigation bar).
- Search for "Website SEO Protection" or "website_seo_protection".
- Click Install. There is no additional setup wizard.
- Once installed, the module is immediately active. No server restart required.
website module to be installed (it is always present on Enterprise with Website activated). It is NOT compatible with Odoo Online (Community SaaS) due to custom code restrictions.
Step 2: Verify the Protection Is Active
Since this module has no UI, use a quick HTTP test to confirm everything is running:
Test Layer 1 — Block Trap
Open your browser and navigate to:
/appointment?domain=[('date','>=',datetime.datetime(2026,1,1,0,0,0,1))]
Expected: Browser shows an HTTP 404 error page. No Odoo content is rendered. Response headers include X-Robots-Tag: noindex.
Test Layer 2 — Noindex Header
Navigate to your appointment page and click a calendar day. URL will become:
/appointment?date=2026-04-15
Expected: Page loads normally (HTTP 200). Open DevTools → Network → click the request → Response Headers. You should see x-robots-tag: noindex, nofollow.
curl -I "https://yoursite.com/appointment?date=2026-04-15" in a terminal to inspect response headers directly.
Step 3: Daily Operation — Zero Maintenance
Once installed, this module is completely transparent. Here is what happens automatically on every request:
Real Users
Users navigating your site manually are completely unaffected. No bookings are blocked. No pages fail. The protection is invisible to humans.
SEO Bots (Googlebot)
Legitimate crawlers such as Googlebot receive a noindex, nofollow header on calendar date pages — preventing crawl budget waste and duplicate content indexing.
Malicious Crawlers
Bots that crawl ?domain=datetime(...) trap URLs receive an instant HTTP 404 with zero database interaction. Worker memory is fully protected.
Important Considerations & Side Effects
What you should know before deploying:
- No settings page, no menu, no database records created. Nothing is stored. This is intentional — it ensures zero performance overhead on normal traffic.
- If you uninstall the module, protection stops immediately. Trap URLs will again generate full Odoo requests. Reinstall takes seconds.
- The Appointment module is NOT required. If you install this on a site that doesn't use Odoo appointments, Layer 1 and Layer 2 simply never trigger. There is no harm in pre-installing it as a precaution.
- Multi-language environments are fully supported. URLs prefixed with
/en/,/es/,/pt_BR/,/zh-hans/, etc. are all correctly recognized. - Multi-website (Odoo Website multi-tenant) works correctly. The protection runs at the HTTP dispatch level, before any website context is resolved.
- Google Search Console: If you had pre-existing crawl trap URLs indexed by Google, they will return 404 after installation. This is SEO-positive: Google will de-index those pages over time. You can submit a Remove URL request in Google Search Console to accelerate the process.
- Server logs: Blocked Layer 1 requests are not logged at the Odoo application level (they never reach Odoo's routing layer). They appear as quick HTTP 404s in your web server or Odoo.SH access log.
Global Ready | Multi-Language Support
This module is fully translated into English and Spanish (en_US, es_ES, es_PE, es_MX), ensuring a professional experience for international organizations.
Why Choose Ganemo?
----------------
Ganemo is the world's leading Odoo App developer and a multi-award-winning Gold Partner. For over 5 years, we have been recognized as the #1 seller of high-quality apps on the Odoo App Store. Trusted as the "Best Partner" in USA, Mexico, Chile, Spain, Colombia, Ecuador, and Peru, we deliver robust, secure, and localization-compliant solutions for global businesses.
Get a Quote & Resolve Commercial Doubts
Join thousands of satisfied clients on Odoo. Contact our sales team directly.
Official WhatsApp
Fastest response time.
LINK
+1 (828) 672-6150
Book a Demo
Let's explore your needs.
LINK
Schedule Meeting
Need More? We Do It All
Professional Odoo Services
ERP Implementation
Transform your business with a full Odoo implementation. We analyze, configure, and train your team to maximize productivity. From Accounting to Inventory, we handle the complexity so you can focus on growth.
Module Dev & Migration
Need a custom feature? Or stuck on an older version? We develop high-performance custom modules and migrate your existing code to Odoo 18/19 with zero data loss. Expert developers at your service.
QA / User Testing Scenarios
Validation Plan
Scenario 1: Crawler Trap Blocked (Layer 1)
- Ensure the module is installed.
- In your browser, open:
/appointment?domain=[('date','>=',datetime.datetime(2026,1,1,0,0,0,123456))] - Expected result: The server returns HTTP 404.
No Odoo worker memory is consumed. Response includes
X-Robots-Tag: noindex. - Check server logs: no ORM query should have been executed for this URL.
Scenario 2: Calendar Links Get Noindex (Layer 2)
- Navigate to your public appointment page.
- Click a day in the calendar — URL becomes
/appointment?date=2026-04-15 - Expected result: The page loads normally (HTTP 200) but the response
includes
X-Robots-Tag: noindex, nofollow. - Verify with browser DevTools → Network → Response Headers.
Scenario 3: Multilingual URL Support
- Enable a second language (e.g., Spanish) in Odoo Settings.
- Open:
/es/appointment?domain=[...datetime.datetime(...)...] - Expected result: Also returns HTTP 404. The language prefix is correctly detected.
- Repeat with
/en/appointment,/pt_BR/appointment— all should behave identically.
Scenario 4: Normal Appointment Pages Unaffected
- Navigate to
/appointment(no query parameters). - Expected result: Page loads normally (HTTP 200) with no
X-Robots-Tagheader. - Book an appointment — the booking flow works as expected.
Scenario 5: Paginated Crawler Traps Blocked
- The appointment pager generates URLs like
/appointment/page/2?domain=[...datetime.datetime(...)...]. - In your browser, open:
/appointment/page/3?domain=[('date','>=',datetime.datetime(2026,1,1,0,0,0,1))] - Expected result: HTTP 404. The
/page/Npattern is also covered by the regex — no page in a paginated crawl trap sequence will pass through. - Confirm with DevTools that the response header includes
X-Robots-Tag: noindex.
Scenario 6: Zero Database Queries on Blocked Requests
- Enable Odoo query logging or use the Monitoring tab in Odoo.SH.
- Send a crawler trap URL (e.g.,
/appointment?domain=[...datetime...]). - Expected result: No SQL query appears in the log for this request. The module intercepts the request at the WSGI dispatch level, before any ORM code runs.
- Compare with a normal
/appointmentrequest which should show several DB queries — confirming the dramatic difference in server load.
Scenario 7: Full Booking Flow — End-to-End
- As a real user, open the public appointment page:
/appointment. - Select an appointment type, then choose a staff member.
- Click a date in the calendar. URL changes to
/appointment/TYPE-ID?date=YYYY-MM-DD. - Select a time slot and fill out the booking form.
- Submit the booking. Expected: Booking confirmation is received. No errors.
- Verify that the confirmation email is sent correctly (if configured).
- Conclusion: The protection module does not interfere with any part of the human booking journey.
Scenario 8: Uninstall & Reinstall Cycle
- Go to Apps and uninstall Website SEO Protection.
- Navigate to a trap URL. Expected: Odoo now processes it normally (HTTP 200 or DB-heavy response) — protection is off.
- Reinstall the module.
- Navigate to the same trap URL. Expected: Immediately returns HTTP 404 again.
- Conclusion: The module leaves no residual data. It can be safely installed and uninstalled without affecting any Odoo data.
Scenario 9: Non-Appointment URLs Are Not Affected
- Navigate to any non-appointment page with query parameters, e.g.,
/shop?categ_id=5&order=price+asc,/blog?tag=odoo, or/jobs?domain=[...]. - Expected result: All pages load normally (HTTP 200) with standard headers. No X-Robots-Tag is injected.
- The protection is surgical: it only activates on paths that match
/appointmentpatterns. Every other URL on your site is completely untouched.
Scenario 10: High-Volume Bot Simulation (Load / Stress Test)
- Using
ab(Apache Benchmark) orlocust, send 1,000 concurrent requests to the trap URL:/appointment?domain=[('date','>=',datetime.datetime(2026,1,1,0,0,0,1))]. - Monitor Odoo.SH worker memory and CPU usage (Monitoring tab).
- Expected result: Workers remain idle (0% memory growth). All 1,000 requests return 404 almost instantly. The server is not degraded.
- Run the same load without the module (or on a non-appointment URL with equivalent complexity) and observe the difference in server resource consumption.
- Conclusion: Demonstrates the module's core value proposition — linear, near-zero cost per trap request.
FAQ & Troubleshooting
Common Resolutions
My appointment page returns 404 for some visitors.
Reason: The visitor's link contains a ?domain=
parameter with a datetime pattern — this is a crawler trap URL.
Fix: This is correct behavior. No real human generates those URLs manually. If a legitimate user is hitting 404, check their link source — it likely came from an indexed crawler trap URL.
Does this break the appointment booking flow?
Answer: No. The module only blocks URLs with
?domain= + datetime patterns. Normal booking URLs are unaffected.
Detail: Run Scenario 4 to verify booking works correctly after installation.
Does it need configuration after install?
Answer: No. Zero configuration. Install and it works.
Detail: There are no settings, no fields, no menus. It operates entirely at the HTTP layer.
Can I use it if I don't have the Appointment module?
Answer: Yes. The module depends only on website.
If appointments are not installed or used, Layer 1 and Layer 2 simply never activate —
no performance overhead.
Safe to install on any Odoo 18 website instance.
Will it affect Google's ability to crawl my appointment pages?
Answer: Only in a positive way. Layer 2 adds X-Robots-Tag: noindex, nofollow to calendar date pages — pages that should never be indexed.
Your main appointment listing page (/appointment with no parameters) is never touched and remains fully indexable by Google.
Typical outcome: improved crawl efficiency and cleaner Google Search Console coverage.
My Odoo server was already OOM-crashing before I installed this. Will it recover?
Answer: Yes. Once installed, all new trap requests are blocked instantly. Existing in-flight requests would still complete, but as soon as the crawl wave stops being fed, workers will naturally recover.
Recommendation: After installing, restart Odoo workers once (Odoo.SH → Restart) to clear any accumulated memory pressure from pre-installation requests.
How can I confirm a crawler trap is being blocked in Odoo.SH logs?
Answer: In Odoo.SH → Logs, open the Access Log. Trap URLs blocked by Layer 1 appear as very fast 404 responses with near-zero response time (typically <5ms). This is the footprint: fast 404 with no accompanying SQL log line.
Tip: Filter by "appointment" and "404" to isolate blocked requests. Normal Odoo 404s take much longer than these sub-5ms interceptions.
Is this compatible with Odoo multi-website?
Answer: Yes. The module intercepts at the WSGI ir.http._dispatch level — before Odoo resolves which website is being requested. It works correctly regardless of how many websites you manage in a single Odoo instance.
All configured website domains are protected automatically.
Will uninstalling this module delete any of my data?
Answer: No. This module adds no database tables, no records, and no configuration. It operates entirely in memory at the HTTP layer. Uninstalling it is a clean, zero-impact operation — you lose only the protection, not any data.
Fully reversible: reinstall at any time to restore protection.
Our appointment booking uses a custom URL pattern — will Layer 1 still protect it?
Answer: Layer 1 is triggered by two conditions: the URL path must contain /appointment, AND the ?domain= parameter must include a datetime string. If your custom URL starts with /appointment, it is automatically protected. If it uses a completely different path (e.g., /reservations), it would not be covered by this module.
Recommendation: Contact ayuda@ganemo.com if you need the regex extended for a custom booking path.
Commercial & Sales
For inquiries about licenses, demos, or partnerships.
Official WhatsApp
Fastest response time.
LINK
+1 (828) 672-6150
Book a Demo
Let's explore your needs.
LINK
Technical Support
Existing customers regarding module functionality.
Help Desk
Exclusive channel for technical assistance and bug reports.
help@ganemo.com
Odoo Proprietary License v1.0 This software and associated files (the "Software") may only be used (executed, modified, executed after modifications) if you have purchased a valid license from the authors, typically via Odoo Apps, or if you have received a written agreement from the authors of the Software (see the COPYRIGHT file). You may develop Odoo modules that use the Software as a library (typically by depending on it, importing it and using its resources), but without copying any source code or material from the Software. You may distribute those modules under the license of your choice, provided that this license is compatible with the terms of the Odoo Proprietary License (For example: LGPL, MIT, or proprietary licenses similar to this one). It is forbidden to publish, distribute, sublicense, or sell copies of the Software or modified copies of the Software. The above copyright notice and this permission notice must be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Please log in to comment on this module