scyllaly/hcaptcha
Scyllaly/hCaptcha is a Laravel wrapper for hCaptcha, providing a Blade directive to render the widget plus a validation rule and server-side verification to protect forms from bots. Simple config for site and secret keys makes it a drop-in spam solution for Laravel apps.
Architecture fit. The package is a thin, idiomatic Laravel wrapper: a service provider, a config file, a Blade directive/helper for rendering the widget, and a custom validation rule that calls hCaptcha's siteverify endpoint server-side. That maps cleanly onto Laravel's existing validation and service-container conventions, so it introduces no new architectural pattern a team has to learn. It occupies the same slot as google/recaptcha-style integrations: one rule on the request, one script tag on the form. Footprint is small and it is easily isolated behind a single validation rule, which keeps it swappable.
Integration feasibility. composer require scyllaly/hcaptcha, publish config, set site/secret keys in env, add the rule to form requests, render the widget in Blade. Realistic effort for a single form is under a day; fleet-wide rollout is dominated by form inventory and QA, not by the package. No database migrations, no queue workers, no new infrastructure. The main unknown is behavioural, not mechanical: whether the rule's default failure handling matches our desired fail-open/fail-closed posture per form.
Technical risk. Code risk is low — the surface area is small and the underlying protocol (POST token to siteverify, read success) is stable. The material risks are supply-chain and lifecycle:
remoteip, enforces hostname checks, or surfaces hCaptcha's score/error-codes — all of which matter for abuse resistance and for debugging production rejections.Key questions for the POC.
remoteip forwarding, hostname validation, and Enterprise score thresholds, or only pass/fail?HCaptcha::fake() or equivalent) so CI does not call the live API?Stack fit. Best fit is a conventional Laravel monolith or Blade/Livewire app on Laravel 8–11, PHP 8.1+, where forms are server-rendered. SPA/API architectures are a weaker fit: the package is oriented toward request-bound validation, so token handling from a decoupled frontend needs a custom endpoint regardless of the package.
Migration path. From reCAPTCHA the swap is small: replace the rule name, replace the widget markup/script, and align the request field name (h-captcha-response vs g-recaptcha-response) in any custom request classes or JS. Keep the old integration in place behind a feature flag until the new one has cleared a full traffic cycle, so rollback is a config flip rather than a deploy.
Compatibility. Verified-range support across Laravel 5–11 means the package will install almost anywhere, which is convenient but not the same as tested on our version. Pin an exact version, and gate upgrades on a CI job that runs the app's form tests against the new tag.
Sequencing.
| Phase | Scope | Exit criteria |
|---|---|---|
| 0 — Audit | Dependency/licence review, read source, confirm API surface | Questions above answered; source reviewed line-by-line (it is small) |
| 1 — POC | One low-risk form in staging, live keys, failure injection | Latency and failure behaviour measured; fake-based test written |
| 2 — Config | Env/secret management across environments, key rotation runbook | Keys in secret store, not .env on disk; rotation rehearsed |
| 3 — Pilot | One production form, 100% traffic, 2 weeks | No unexplained rejection-rate change; support tickets flat |
| 4 — Rollout | Remaining forms in batches by criticality | Per-batch rollback flag documented |
| 5 — Decommission | Retire reCAPTCHA keys and scripts | Old vendor keys revoked |
Sequence the highest-value, lowest-blast-radius form first (newsletter signup, not checkout), and explicitly decide fail-open vs fail-closed per form before Phase 3.
Maintenance. Low ongoing effort but non-zero ownership: someone must watch for Laravel major releases and confirm a compatible tag exists before we upgrade. Pin the version, subscribe to repo releases, and budget roughly a day per Laravel major. Given the small codebase, maintain an exit option — either an in-house equivalent (a few hundred lines) or a maintained alternative — as a documented contingency rather than an active project.
Support. Community-only, no SLA. Internal support load is dominated by two ticket types: users who cannot solve the challenge (accessibility, corporate proxies, aggressive privacy extensions) and misconfigured keys per environment. Pre-empt both with an accessibility fallback link and a startup config check.
Scaling. Negligible compute cost; the only scaling concern is a synchronous outbound HTTP call per submission, adding roughly 100–300 ms to form latency and creating a per-request dependency on a third party. Set aggressive timeouts (2–3 s), use a pooled/keep-alive client, and exclude the captcha call from any tight rate-limit paths.
Failure modes.
Ramp-up. Roughly half a day for a Laravel-fluent engineer to integrate the first form, plus the same again for tests and runbook. No new skills required. The real ramp-up cost is organisational: getting product to agree the fail-open/fail-closed policy and the privacy position on shipping user traffic to hCaptcha. Treat that as the critical path, not the code.
How can I help you explore Laravel packages today?