unbotable/unbotable-laravel
Composer 安装命令:
composer require unbotable/unbotable-laravel
包简介
Laravel integration for Unbotable — privacy-respecting bot and spam protection
关键字:
README 文档
README
Privacy-respecting bot and spam protection for Laravel forms and logins — no CAPTCHAs for real visitors, no tracking, no third-party data harvesting.
This package is the Laravel client for Unbotable. It talks to the Unbotable service over HTTP, attaches a short-lived signed token to your forms, and verifies it with middleware. There is no account and no API key — you point it at the service and protect a route.
⚠️ Alpha — coming soon
Unbotable is in early testing. The protection works, but it's young: tuning is ongoing, the API may shift before 1.0, and it will not yet catch every bot. It's built to fail open — if anything goes wrong, your forms keep working and real users are never blocked by our bug. Pin an exact version and treat it as defence-in-depth, not a guarantee, until we cut a stable release.
How it works
@unbotableJsloads a tiny script that, in the background, measures device and behaviour signals and asks the Unbotable service for a verdict.- The service returns a signed, 5-minute token (and, for borderline sessions, an invisible proof-of-work the browser solves silently).
- The
unbotablemiddleware verifies the token's signature locally against the service's public key and enforces the verdict.
Raw signals are used for a split second to reach a decision and then thrown away. What little the service stores is one-way and anonymous — you could publish the whole database and not find a single person in it. That's the point.
A local honeypot and timing floor run independently of the service, so even if Unbotable is unreachable you keep a baseline of protection.
Requirements
- PHP 8.2+
- Laravel 12 or 13
Installation
composer require unbotable/unbotable-laravel
The service provider, the unbotable middleware alias, and the Blade directives
register automatically via Laravel package discovery.
Point the package at the service (defaults to the public service):
UNBOTABLE_URL=https://unbotable.com
Optionally publish the config to tune behaviour:
php artisan vendor:publish --tag=unbotable-config
Quick start
Protect a route
use Illuminate\Support\Facades\Route; Route::post('/login', [LoginController::class, 'store'])->middleware('unbotable'); // During rollout, observe without enforcing: Route::post('/register', [RegisterController::class, 'store'])->middleware('unbotable:log_only');
Blade forms
Add the script once in your root layout, then drop the honeypot into the form:
{{-- layout <head> or before </body> --}} @unbotableJs <form method="POST" action="/login"> @csrf @unbotableHoneypot {{-- hidden trap field --}} @unbotableTimestamp {{-- JS-free timing floor --}} {{-- ...your fields... --}} </form>
For a plain Blade form with no framework, auto-wire it — the token is attached on submit:
@unbotableWire('#login-form')
Inertia / Vue
Add @unbotableJs to your root Blade layout, then use the composable. The cleanest
way to import it is a Vite alias to the installed package (no copied files to
drift):
// vite.config.js import { fileURLToPath } from 'node:url' export default defineConfig({ resolve: { alias: { '@unbotable': fileURLToPath( new URL('./vendor/unbotable/unbotable-laravel/resources/js', import.meta.url) ), }, }, })
<script setup> import { useForm } from '@inertiajs/vue3' import { useUnbotable } from '@unbotable/useUnbotable' const unbotable = useUnbotable() const form = useForm({ email: '', password: '', _unbotable_hp: '' }) const submit = async () => { await unbotable.settled() // let the background assess finish unbotable.protect(form).post(route('login')) // attaches the token + PoW } </script> <template> <form @submit.prevent="submit"> <!-- ...your fields... --> <!-- off-screen honeypot --> <input type="text" name="_unbotable_hp" v-model="form._unbotable_hp" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px" /> </form> </template>
Configuration
All settings have sensible defaults; override via env or the published config.
| Key (env) | Default | What it does |
|---|---|---|
UNBOTABLE_URL |
https://unbotable.com |
The Unbotable service to verify against |
UNBOTABLE_ON_BLOCK |
fake_success |
On a block verdict: fake_success (redirect back with a flag), abort (422), or log_only |
UNBOTABLE_ON_UNREACHABLE |
open |
If the service is unreachable: open (allow + log, rely on honeypot/timing) or closed (block) |
UNBOTABLE_MIN_SUBMIT_SECONDS |
2 |
Submissions faster than this are treated as bots (JS-free) |
UNBOTABLE_REPLAY_MAX_USES |
3 |
How many times one token may be reused before rejection |
UNBOTABLE_FAKE_SUCCESS_REDIRECT |
null |
Where fake_success redirects (null = back) |
fake_success sets the session key _unbotable_ok so your view can show a
plausible success message to a bot while quietly dropping the submission.
Fail-open by design
If the service times out, errors, or the script never runs, the package sends a
unreachable status and the middleware applies on_unreachable (default:
allow). A genuine block verdict always blocks; only outages fail open. We'd
rather let a borderline request through than block a real person over our own
downtime.
Privacy
No cookies, no third parties, no tracking — not even an analytics beacon. Nothing stored is tied to a person: the service keeps only one-way, anonymous hashes that expire on their own within weeks. See the live data at unbotable.com.
License
MIT — see LICENSE.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-14