Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Captchavel Laravel Package

darkghosthunter/captchavel

Captchavel gives Laravel a single, unified API for reCAPTCHA, hCaptcha, and other CAPTCHA providers. It includes validation rules, Blade directives, middleware, and fakeable testing helpers, so you can protect forms without vendor lock-in.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: Captchavel is superseded. The v7.0.3 release notes are not a changelog entry, they are an end-of-life notice. The package has been replaced by Laragear/ReCaptcha, which is described as "very similar to Captchavel, plus some great additions and performance optimizations." Treat Captchavel as maintenance-only from here: it still works, but new features, and realistically security fixes, land in the successor.

What that means in practice:

  • New project? Install laragear/recaptcha instead. Do not adopt Captchavel.
  • Existing project? Stay on v7.0.3 for now, keep a migration ticket on the backlog (the API is close enough that migration is a small diff, see Implementation Patterns), and avoid building new abstractions on top of Captchavel that you will have to unpick.
  • Pinned to an old major? v7.0.3 is a patch release on the current major, so it is a safe bump if you are already on v7. There is no code change to review here — the notice is the news.

For the Captchavel workflow itself, the mental model is four steps and nothing more:

  1. composer require laragear/captchavel
  2. php artisan vendor:publish --tag=captchavel to get config/captchavel.php, then set the site key and secret key in .env from the Google reCAPTCHA admin console.
  3. Render the widget in your Blade form. Captchavel ships a Blade component/directive that emits the Google script and a response field (g-recaptcha-response) alongside your form fields.
  4. Validate the token server-side — either by adding the package's validation rule to your existing FormRequest, or by calling the Captchavel facade directly.

The first use case to wire up is a contact form. It is the lowest-risk place to learn the package: one form, one submit, one rule. Once you have that green, copy the pattern to registration, password reset, and login. Start by reading config/captchavel.php after publishing — the version switch (checkbox v2 / invisible v2 / v3 score-based) and the score threshold live there, and they determine how much of the rest of your integration looks.

Implementation Patterns

Validation rule as the default path. The idiomatic integration is the package's rule on the response field inside a FormRequest, sitting next to your other rules. This keeps the controller thin and gives you the standard $errors bag for free. Do not reimplement token verification in a controller when the rule already exists.

Facade for non-form paths. For API endpoints, Livewire actions, or queued jobs that receive a token out of band, call the facade (Captchavel::validate($token)) and return a 422 yourself. Wrap it in a small dedicated action or service class so you have one place to swap when you migrate.

Match the config mode to the form. The three modes are not interchangeable at the markup level:

  • v2 checkbox — user clicks, token appears, normal submit. Simplest, most intrusive.
  • v2 invisible — no checkbox; the widget is bound to your submit button and the script must be told when to execute. This is where people get stuck: the form must not submit until the token callback fires.
  • v3 score-based — no user interaction at all. The token carries an action name and a score; your server compares the score against the configured threshold and the action against what you expect. Use v3 where friction matters (login), v2 where you want an explicit human signal (registration abuse).

One widget per form. If a page has multiple forms (login + register in tabs), give each its own widget instance and its own response field name. Duplicate g-recaptcha-response inputs across two forms on one page is the single most common silent failure — the server reads a token generated for the other form's action and rejects it.

Layer it, don't lean on it. reCAPTCHA is an abuse signal, not authorization. Keep it stacked with Laravel's throttle middleware and your usual validation. If Google's API times out, decide explicitly whether you fail open (let the request through, log) or fail closed (reject). Fail-closed on a payment form, fail-open on a newsletter signup is a reasonable split.

Testing pattern. Do not hit Google in tests. Fake the outbound HTTP call and assert on the rule's pass/fail, and add one test that asserts a missing/blank token fails validation so you catch accidental removal of the rule. Keep a trait or helper that stubs a successful verification so every feature test that submits a protected form stays readable.

Migration pattern to Laragear/ReCaptcha. Because the successor is "very similar," the migration is mostly mechanical and can be done form-by-form rather than as a big bang:

  1. Install the new package alongside the old one; both can coexist.
  2. Re-publish and re-point config/env keys (expect renamed env vars — set the new ones, keep the old ones until the last form is migrated).
  3. Swap the rule name in one FormRequest, run the tests for that flow.
  4. Swap the Blade component/directive in the matching view.
  5. Repeat; delete Captchavel and its config when zero references remain.

Doing it in that order means every step is independently revertible and you never have a half-migrated form in production.

Gotchas and Tips

The deprecation is the biggest gotcha. A package that verifies bot traffic is security-adjacent. An unmaintained one will eventually drift from Google's API or from a Laravel major. Budget the migration rather than discovering it when a Laravel upgrade breaks the service provider.

Tokens are single-use and short-lived. Roughly two minutes, one verification. Do not validate in a middleware and in a FormRequest — the second call fails and you will chase a bug that looks like "the token is invalid" when it is "the token was already spent." Also do not re-render a form after a validation failure without generating a fresh token; the user's expired token will fail on the second submit.

v3 action and score must both be checked. Verifying only the score lets a token minted for a harmless action be replayed against a sensitive one. Pin the expected action per form. And do not set the threshold at 1.0 — legitimate users will be rejected. Start around 0.5 and tune from real traffic rather than guessing.

Config cache is the classic footgun. php artisan config:cache in deploy means an .env key change does nothing until you re-cache. Symptoms: works locally, "invalid key" in staging. If reCAPTCHA suddenly rejects everything after a deploy, check the cached config before you touch the code.

Key pairing and domains. The site key and secret key are a matched pair from the same reCAPTCHA registration — mixing keys from two registrations produces generic failures. Domain restrictions on the key also mean localhost and your staging host need to be registered, or use Google's public test keys in local dev (they always pass) so you are not blocked offline.

Local and CI environments. Tests and local dev should not depend on network access to Google. Use the test keys locally and HTTP fakes in the suite. If your CI suite suddenly fails on every form submission, this is almost always the cause.

Extension points worth knowing. The config file is the main lever (mode, score, keys, badge visibility). If you need behaviour the rule does not cover — custom logging, per-route thresholds, a different failure message — bind your own rule or wrap the facade rather than editing vendor code, and do it in a single class so the eventual migration touches one file.

Badge visibility. Hiding the v3 badge is possible but Google's terms expect attribution somewhere in the UI. If you hide it, add the required text manually; otherwise you are shipping a compliance problem alongside your bot protection.

Debugging order when a submission fails. (1) Is a token actually present in the payload? (2) Is it being submitted twice? (3) Is the config cached and stale? (4) Is the site/secret pair correct for this environment? (5) Does the action/score match what the form was configured for? That order resolves nearly every report.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource