Docker Self-Hosting
Deploy Tymeslot with Docker Compose on any VPS or home server. Includes reverse proxy setup, file upload volumes, and WebSocket configuration for LiveView.
Protect your signup and booking forms from bots with Google reCAPTCHA v3 — invisible verification with no user friction.
Technical Product Builder & AI Developer
You will need:
google.com/recaptcha/admin
tymeslot.yourdomain.com) — reCAPTCHA tokens are domain-bound and do not work on
localhost
By the end of this guide, your signup and booking forms will be protected against bot submissions with invisible reCAPTCHA v3.
reCAPTCHA v3 (also called "invisible CAPTCHA" or "score-based CAPTCHA") runs entirely in the background. It assigns a score from 0.0 (very likely a bot) to 1.0 (very likely human) based on user behaviour signals, and Tymeslot rejects submissions below your configured threshold. Legitimate users see no challenge, no checkbox, and no puzzle.
Do not confuse it with reCAPTCHA v2 (the "I'm not a robot" checkbox — that is a different product) or hCaptcha (a different provider entirely). Tymeslot integrates with v3 only.
reCAPTCHA is optional and disabled by default. The next section helps you decide whether to enable it.
Enable reCAPTCHA if you are experiencing any of the following:
A surge of accounts with random email patterns (e.g.,
xk3m9@mailinator.com
) signals automated account creation. Bots target open signup forms to harvest confirmed email addresses or abuse free-tier limits. reCAPTCHA's behaviour scoring catches these scripts before they complete registration.
Meetings booked with fake names or throwaway email addresses pollute your calendar and trigger confirmation emails to addresses no one reads. Booking forms are particularly exposed because they require no login — enabling reCAPTCHA on the booking form blocks automated submission scripts with a permissive threshold that does not affect real visitors.
Repeated failed login attempts against your users' accounts indicate an automated credential-stuffing attack — bots cycling through leaked username and password lists. reCAPTCHA scores each login attempt and rejects low-confidence requests before they reach your authentication logic, reducing the blast radius without requiring users to solve puzzles.
You can safely skip reCAPTCHA for small or private deployments where your scheduling link is shared only with known contacts. There is no security benefit in adding friction to a closed deployment.
tymeslot.yourdomain.com. Do not include
https://
or a trailing slash.
Add the following environment variables to your Tymeslot instance. Restart the application after making changes.
# reCAPTCHA v3 keys from google.com/recaptcha/admin\nRECAPTCHA_SITE_KEY=6Le...your-site-key\nRECAPTCHA_SECRET_KEY=6Le...your-secret-key\n\n# Accepted hostname — only tokens generated on this domain are accepted.\n# Prevents token replay attacks (see explanation below).\nRECAPTCHA_EXPECTED_HOSTNAMES=tymeslot.yourdomain.com\n\n# Protect the signup form\nRECAPTCHA_SIGNUP_ENABLED=true\nRECAPTCHA_SIGNUP_MIN_SCORE=0.5\nRECAPTCHA_SIGNUP_ACTION=signup_form\n\n# Protect the booking form\nRECAPTCHA_BOOKING_ENABLED=true\nRECAPTCHA_BOOKING_MIN_SCORE=0.3\nRECAPTCHA_BOOKING_ACTION=booking_form
Why does
RECAPTCHA_EXPECTED_HOSTNAMES
matter?
A reCAPTCHA token is tied to the domain that generated it, but without hostname verification an attacker could generate a valid token on their own site and replay it against your Tymeslot instance. Setting this variable to your exact domain causes Tymeslot to reject any token that was not generated on your site.
Google scores each interaction from 0.0 to 1.0. Tymeslot blocks submissions whose score falls below your configured minimum. Use this table as a reference:
0.0
Very likely a bot — automated traffic with no human signals
0.3
Suspicious — recommended minimum for booking forms
0.5
Neutral — recommended minimum for signup forms
0.7
Likely human — confident interaction pattern
1.0
Very likely human — strong human interaction signals
Why different thresholds for signup and booking? Booking forms are often the first touch point for people who just received a scheduling link from a colleague — they are real humans, but Google may score them lower because they have no prior interaction history with your site. A more permissive threshold (0.3) prevents blocking these legitimate users. Signup forms attract more determined bots and can safely use a higher threshold (0.5) — a false positive just means the user tries again.
reCAPTCHA is automatically disabled in the development environment regardless of how your environment variables are set. You do not need to add any variables to your local
.env
file, and no code changes are required for local testing. All forms accept submissions normally in dev.
google.com/recaptcha/admin, select your site, and view the
[Analytics]
tab to confirm that the score appeared. This verifies end-to-end integration before real users are affected.
Once reCAPTCHA is live, use the admin console to understand how your real users are scoring and decide whether your thresholds need adjusting:
google.com/recaptcha/admin
and select your site.
Lower
RECAPTCHA_BOOKING_MIN_SCORE
to 0.2
or 0.1
and monitor the reCAPTCHA admin console to see if score distributions shift. Users on mobile or with certain browser extensions can score lower than expected.
Check that
RECAPTCHA_EXPECTED_HOSTNAMES
exactly matches your production domain — no trailing slash, no
https://
prefix. The value must be the bare hostname as it appears in the browser address bar.
Verify that the Site Key
used in environment variables matches the key shown in the reCAPTCHA admin console for your site. Also confirm that
RECAPTCHA_SIGNUP_ENABLED
or
RECAPTCHA_BOOKING_ENABLED
is set to true
(not 1
or yes).
That is expected behaviour. reCAPTCHA v3 is invisible — it runs silently in the background and never presents a challenge to the user. If you suspect it is not running at all, open the reCAPTCHA admin console at google.com/recaptcha/admin, select your site, and check the
Analytics
tab. If no scores appear after submitting the form, verify that
RECAPTCHA_SITE_KEY
is correct and that your domain is registered under the site key settings.
Tymeslot uses reCAPTCHA v3 exclusively. It is invisible to users — no checkbox, no image puzzle, and no interruption to the form flow. Google's systems observe user behaviour signals in the background and return a score between 0.0 (likely a bot) and 1.0 (likely human). Tymeslot rejects submissions whose score falls below your configured threshold.
No. Tymeslot integrates with the reCAPTCHA v3 Score API only. A v2 site key will not work — the two versions use different APIs and different token formats. When creating your site in the reCAPTCHA admin console, you must select Score based (v3).
In the Google reCAPTCHA admin console at google.com/recaptcha/admin, open your site's settings and locate the
Domains
section. Add your domain exactly as it appears in the browser address bar — for example
tymeslot.yourdomain.com
— without the
https://
prefix or a trailing slash. Subdomains are covered automatically once the root domain is listed.
reCAPTCHA v3 validates tokens against a registered domain list.
localhost
is not trusted by default. You can add it explicitly in the reCAPTCHA admin console under your site key's
Domains
settings. Alternatively, leave
localhost
unregistered — Tymeslot automatically disables reCAPTCHA in the development environment, so local testing is unaffected by production reCAPTCHA configuration.
https://
prefix)
RECAPTCHA_SITE_KEY
and
RECAPTCHA_SECRET_KEY
are set in environment variables
RECAPTCHA_EXPECTED_HOSTNAMES
is set to your exact production domain
Deploy Tymeslot with Docker Compose on any VPS or home server. Includes reverse proxy setup, file upload volumes, and WebSocket configuration for LiveView.
Install Tymeslot on Cloudron in minutes. PostgreSQL, SSL certificates, email relay, and automatic updates are all provisioned and managed for you.
Deploy Tymeslot to Railway with one click. PostgreSQL is provisioned and connected automatically — set two environment variables and your instance is live.