victor-prdh/recaptcha-bundle
A Symfony bundle for integrating Google reCAPTCHA into forms and controllers, with configurable keys, server-side verification, and simple validators to help protect your application from spam and automated abuse.
Architecture fit
The first thing to flag: despite being queued as a "Laravel/PHP package," victor-prdh/recaptcha-bundle is a Symfony bundle, not a Laravel package. It ships a Symfony DI extension, bundle class, and YAML configuration — there is no ServiceProvider, no publishable config/recaptcha.php, and no Laravel validation rule. It cannot be installed and used inside a Laravel application the way the intake ticket implies.
What is framework-agnostic and reusable is the underlying dependency, google/recaptcha, which is a plain PHP library (one verification call, one secret, one token). That is the real integration surface for us; the bundle is essentially a thin Symfony wiring layer around it.
Scope-wise this is also server-side verification only. No client-side widget, no JS, no blade/view helpers. Front-end integration (v2 checkbox, v3 score token issuance) remains our responsibility either way.
Net: architecture fit for this package in a Laravel estate is low. Fit for its core dependency is medium-high.
Integration feasibility
Feasible, but only by deliberately bypassing the bundle:
google/recaptcha directly, pin it, and write a ~150-line Laravel binding: config file, singleton registration, a Recaptcha facade/contract, and a recaptcha validation rule.The 2.2.0 release adds no bundle-level functionality — it is a single-line constraint widening (google/recaptcha now allows 2.x alongside the existing 1.x). So it does not change the integration calculus for us; it only changes which underlying library version Composer may resolve.
Technical risk
Overall: Medium, and almost all of it is transitive rather than in the release itself.
| Risk | Severity | Note |
|---|---|---|
Dual-major dependency support (^1.x || ^2.x) |
Medium | The resolved google/recaptcha version now varies per consuming project; bundle behavior may diverge between paths and CI may only exercise one |
Transitive major bump on composer update |
Medium | google/recaptcha 2.x raises the PHP floor (8.1+) and swaps bundled Guzzle for PSR-18/PSR-17 client injection — a silent platform requirement change for anyone who updates loosely |
| Two code paths in one bundle release | Low-Medium | No evidence in the notes that the test matrix covers both majors |
| Bus factor | Medium | Single-maintainer project; this release includes a first-time contributor, which is healthy but does not reduce concentration risk |
| Abandonment / maintenance cadence | Medium | Must be verified before we depend on it — reCAPTCHA integrations rot quietly when the wrapper stops tracking Google API changes |
| Wrong-framework adoption | High (avoidable) | Attempting to load a Symfony bundle in Laravel is a guaranteed dead end; keep this out of the backlog as a "Laravel package" candidate |
Nothing here is a breaking change for existing bundle consumers — 2.2.0 is additive. Urgency is low; this release is not a reason to adopt or accelerate.
Key questions
google/recaptcha 1.x and 2.x, or is the wider constraint aspirational?google/recaptcha, do we pin ^2.0 only (recommended) to keep a single code path?Stack fit
Laravel 10/11 on PHP 8.2 fits google/recaptcha 2.x cleanly: it wants PHP 8.1+, a PSR-18 HTTP client and a PSR-17 request factory, and Laravel already ships Guzzle 7, whose Client implements PSR-18. So wiring is a container binding, not a dependency fight.
The Symfony bundle itself does not fit and should not be forced. Do not attempt to register Symfony bundles or the Symfony DI container inside a Laravel app.
Migration path
Assuming an existing call-site set (custom code, or an older Laravel wrapper on google/recaptcha 1.x):
"google/recaptcha": "^2.0" — do not mirror the bundle's ^1 || ^2 tolerance. One code path only.new ReCaptcha($secret) to the 2.x creation surface, injecting Laravel's Guzzle client.verify() return shape, setScoreThreshold(), and any error/exception handling differences.Recaptcha contract resolved from the container, plus a recaptcha validation rule, so future library bumps touch one file.Compatibility
guzzlehttp/guzzle and guzzlehttp/psr7 against existing Laravel dependencies.Sequencing
google/recaptcha:^2.0, verify a real token end-to-end in staging.recaptcha.enabled), enable per-endpoint, starting with the lowest-traffic protected form.Maintenance
Runtime surface is tiny — one outbound verification call per protected request — but we own the Laravel binding, because the bundle won't provide it. Budget roughly 1–2 days per year for dependency bumps and re-verification against Google API changes. Pin to a single google/recaptcha major and treat major bumps as planned work, not composer update noise.
Support
Two decisions need to be made explicitly and documented, because they will otherwise be made accidentally during an incident:
Log every verification outcome with the score and the failure reason; that is the only signal you'll have when conversion drops.
Scaling
CPU cost is negligible. The real cost is latency: a synchronous outbound HTTPS call to Google adds ~50–200 ms to any request that verifies a token. Mitigations:
Failure modes
| Failure | Symptom | Handling |
|---|---|---|
| Google unreachable / timeout | All verifications fail | Fail-open/closed policy per endpoint; alert on error-rate spike |
| Invalid or rotated secret | 100% verification failure | Boot-time config check; distinct log reason code |
| Hostname/domain mismatch | Valid tokens rejected | Verify allowed-domains config per environment |
| Token replay or expiry (~2 min) | Intermittent user-facing failures | Reject single-use reuse; surface a clear retry message |
| Score below threshold (v3) | Silent drop in conversions | Log scores; tune threshold from real data, not defaults |
Wrong google/recaptcha major resolved |
Behavior differs by deploy | Explicit ^2.0 pin; lockfile committed |
| Fail-open misconfiguration | Bot traffic passes silently | Assert policy at boot; monitor submit-rate anomaly |
Ramp-up
Low. A Laravel developer needs roughly half a day to learn the google/recaptcha verification API and the v2/v3 distinction. No Symfony knowledge is required, because no one on the team should be touching the bundle. The larger ramp-up cost is organizational: correcting the assumption that this is a drop-in Laravel package, and re-running intake against Laravel-native candidates or an in-house binding before committing to a path.
How can I help you explore Laravel packages today?