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

Iconcaptcha Laravel Package

fabianwennink/iconcaptcha

IconCaptcha is a lightweight, self-hosted PHP captcha that replaces reCAPTCHA with a privacy-friendly icon-based challenge. No external services, no tracking, fully customizable, and easy to integrate—ideal for GDPR-conscious sites.

View on GitHub
Deep Wiki
Context7

Getting Started

IconCaptcha is a framework-agnostic PHP + JavaScript package. In Laravel you install the PHP backend via Composer and the front-end bundle separately, then wire the two together yourself — there is no first-party Laravel service provider to lean on. Budget an hour for the initial integration.

  1. composer require fabianwennink/iconcaptcha
  2. Install the JS bundle (npm install iconcaptcha or use the CDN build). Confirm the major version matches the PHP package.
  3. Put the icon set somewhere public, e.g. public/vendor/iconcaptcha/icons, and record both the filesystem path and the public URL.
  4. Create config/iconcaptcha.php and a small service provider that configures the library once at boot.
  5. Add a route/controller for the widget's AJAX endpoint. Put it in the web middleware group so sessions work.
  6. Render the container in a Blade component and initialise the JS with the endpoint URL.
  7. Validate the submitted token in a FormRequest or a custom validation rule.

Where to look first: the README's "Basic usage" section, the examples/ directory in the repo, the JS package docs for front-end options, and src/IconCaptcha.php for the public methods (handleRequest(), getPayload(), validate() in v4). Start with a single contact form: render the widget, point it at your endpoint, add the validation rule, and test a correct selection, a wrong selection, and an expired challenge.

Implementation Patterns

Keep one dedicated endpoint controller. Make it invokable and minimal. If the library returns a response, return it; if it writes/echoes directly, capture with output buffering and wrap in JsonResponse. Don't let Laravel's exception handler convert errors into HTML redirects — the JS expects JSON.

Configure once in a service provider. Use env-backed config (ICONCAPTCHA_ICON_PATH, ICONCAPTCHA_ICON_URL, ICONCAPTCHA_STORAGE) and call the library's configuration method in boot(). Avoid scattering options across controllers.

Render through a Blade component. A <x-iconcaptcha /> component that outputs the container, includes the JS once via @once/@push('scripts'), and initialises with route('iconcaptcha.endpoint') keeps forms clean and consistent.

Wrap validation in a custom rule. Implement ValidationRule and call the library's validate(). Attach it to the FormRequests for login, registration, and contact forms so it composes with Laravel's normal error handling and old-input flow.

Use session storage by default, but plan for scale. The session driver is the path of least resistance on a single server. On load-balanced or multi-server deployments, implement or configure a shared storage driver (Redis/DB) through the library's storage interface, or ensure sticky sessions.

Add middleware deliberately. Apply throttle to the endpoint yourself — the package does not ship rate limiting. Decide how to handle CSRF: either configure the JS to send X-CSRF-TOKEN from a meta tag, or exclude the endpoint and accept the trade-off.

Handle Livewire and Inertia. For Livewire, wrap the widget in wire:ignore so DOM morphing doesn't destroy it. For Inertia, load the script once in the root layout and re-initialise on page visits; otherwise the widget works only on the first load.

Disable it in tests. Add an ICONCAPTCHA_ENABLED flag and bypass validation in the test environment, or bind a fake validator in the container. Otherwise every form test needs a real challenge.

Theme with CSS variables or overrides. Keep the icon set and colour scheme consistent with your brand; the widget is designed to be customised rather than used stock.

Gotchas and Tips

  • Version coupling. The PHP and JS packages must share a major version. v3 and v4 differ in config keys and DOM expectations. Pin both in composer.json and package.json.
  • Path vs URL. The filesystem icon path and the public icon URL are separate settings and both must be correct. A bad path gives broken images; a bad URL gives 404s in the network tab.
  • Session lifetime. If the session expires between challenge load and form submit, validation fails without a useful error. Check config/session.php and your driver.
  • JSON contamination. A PHP notice, a stray dump(), or a dd() before the response breaks the widget. Use logs, not debug output, in the endpoint.
  • Middleware mismatch. api routes have no session by default; web routes have CSRF. Pick deliberately and test the actual request from the browser.
  • One-time tokens. A failed submission usually consumes the challenge. Re-render the widget after a validation error and don't cache the form fragment.
  • Caching. Never cache the endpoint or the rendered widget HTML — challenge payloads are per-session and per-request.
  • Multiple forms/tabs. Challenges are keyed by session, so several open forms can collide. Use a form identifier if the version supports it, or be aware of the limitation.
  • Accessibility. Icon selection is inherently visual. Provide an alternative path (audio, email confirmation, manual moderation) and test keyboard navigation.
  • Localisation. Check which strings are translatable and whether the JS carries its own copy; pass the locale explicitly.
  • Debugging "spinner forever." Open the network tab, inspect the endpoint response, confirm the session cookie is sent, and verify the response is application/json. This catches most integration mistakes.
  • Upgrade path. Small package, small community (184 stars), fewer Stack Overflow answers. Read the changelog before bumping and keep one integration test that submits a form with a valid challenge.
  • Self-hosted assets. Serve icons with correct MIME types and cache headers; add cache busting when the icon set changes. If you use a CDN, make sure the icon path is reachable.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin