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.
Architecture fit
IconCaptcha-PHP is a framework-agnostic PHP library, not a Laravel package. There is no service provider, facade, config file, publishable migration, or Blade directive — so integration is a wrapping exercise we own, not a composer require and go. The product is also two artifacts: this server-side PHP component (challenge generation, session-backed validation) and a separate IconCaptcha-JS client widget. Both must be versioned and kept in lockstep, and neither ships a Laravel-native contract.
Conceptually it fits cleanly as a validation layer alongside any existing captcha abstraction: one route to mint a challenge, one to validate a response, plus a custom validation rule. The genuine architectural friction is session coupling — challenge state lives in session, and Laravel owns and abstracts the session. If the library only supports native $_SESSION, it conflicts with Laravel's StartSession middleware and becomes a real blocker rather than a wiring task. Confirm early whether it exposes a storage/session interface we can implement against Illuminate\Session\Store.
The 184 stars / 0 Packagist dependents / 2.75 score reads as ecosystem immaturity, not code quality. Treat it as a small, credible, single-maintainer library — attractive for privacy-sensitive, self-hosted, no-third-party-call requirements — and price in the ownership accordingly.
Integration feasibility
A first working cut is realistically 1–2 engineer-weeks: composer install, a service provider, config, two routes (challenge + validate), a Blade/Vite-wrapped widget component, and a ValidatesIconCaptcha rule. The AJAX endpoints will need CSRF handling (token pass-through or exclusion) and the assets need a Vite pipeline entry.
Technical risk, ranked
Key questions to answer in the spike
$_SESSION?Stack fit
PHP 8.x on Laravel 10–12; no database requirement, no schema changes. Front-end agnostic — the widget drops into Blade + Vite, Livewire, or an Inertia/Vue/React surface with equal effort. The standout fit is no outbound network calls: it works air-gapped, on-prem, and in GDPR/DPA-sensitive flows where shipping user data to Google is a non-starter.
Migration path
Do not rip out the incumbent captcha. Introduce IconCaptcha behind a per-form config flag and run it in parallel.
app/Captcha/IconCaptcha or a private Composer package exposing a stable Laravel API: service provider, config, routes, validation rule, Blade component, Vite assets. Other teams should never touch the vendor library directly.Compatibility notes
file, redis, database are all fine once bridged. The cookie driver is a problem — payload size and server-side mutation semantics.script-src/style-src/img-src.Sequencing rationale
Solve the session bridge first in isolation. If it fails, the whole evaluation collapses to a cheap "no" and you've spent a week, not a quarter. Everything after that gate is standard Laravel plumbing with predictable effort.
Maintenance
We own the wrapper and, effectively, the upgrade path. Budget 1–2 engineer-days per quarter for dependency bumps, plus incident time. Pin exact versions of both the PHP and JS artifacts and bump them together. The codebase is small enough that a fork is a realistic contingency if upstream goes quiet — MIT makes that clean.
Support
No vendor, no SLA; GitHub issues only. That means an internal runbook is mandatory: how to disable the captcha, how to flip back to the incumbent provider, and who owns the session-bridge code. Captcha failures surface to users as "I can't log in" — treat this as a highest-severity, user-facing failure class in on-call routing.
Scaling
Compute cost is negligible — icon selection, no proof-of-work, no ML scoring. State lives in session, so scaling is entirely a function of your existing shared session store; no new datastore. The challenge endpoint is hit roughly once per form impression, so capacity tracks form traffic, and the static assets are edge-cacheable.
Failure modes
Ramp-up
Engineers reach productivity in ~2–3 days once the session bridge exists; the surface is small. The risk is concentrated knowledge — one engineer will understand the bridge, and that is the piece most likely to break on a Laravel upgrade. Document it explicitly and add a test that exercises the full round trip. Product/design needs two decisions up front: the accessibility fallback and whether the icon set is customized for brand. Total team ramp is low; ongoing ownership cost is the real line item.
How can I help you explore Laravel packages today?