Search by

botect / botect-php

develupers

Botect server SDK for plain PHP with optional Laravel integration.

Package info

github.com/botect/botect-php

pkg:composer/botect/botect-php

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-09-10 00:44 UTC

This package is auto-updated.

Last update: 2026-09-10 00:54:37 UTC


README

The official PHP SDK for Botect, a bot-detection platform that scores visitor sessions and helps your application decide how to handle automated traffic.

Use the same package in plain PHP or Laravel. The core works without a framework; Laravel adds automatic service discovery, a facade, Blade integration, middleware, configuration publishing, and queue support.

Documentation · Changelog · Quickstart · Authentication · Report an issue

Choose a delivery mode

Start with deferred (the default). It needs no queue worker, cron job, or delivery files. Choose spool or queue when you want persistent delivery with retries.

These are the exact supported configuration values:

Value Plain PHP Laravel How it sends Required setup Retries
deferred — default Yes Yes Buffers in memory and sends after the response on PHP-FPM None; PHP-FPM recommended No; one attempt
spool Yes Yes Saves deliveries to files for a background process to send Private writable directory and a cron job or flush worker Yes; bounded retries
queue No built-in driver Yes Dispatches deliveries to Laravel's asynchronous queue Configured queue connection and running queue worker Yes; bounded retries

Where to set it:

Environment Configuration location Example
Plain PHP delivery argument of Botect::create() Botect::create($configuration, delivery: 'deferred')
Laravel BOTECT_DELIVERY in .env, mapped to botect.delivery BOTECT_DELIVERY=deferred

For plain PHP spool mode, also pass storageDirectory. In Laravel, BOTECT_DELIVERY=queue inherits the application's default connection and that connection's default queue from config/queue.php. Leave BOTECT_QUEUE_CONNECTION and BOTECT_QUEUE unset unless you want to override them. The synchronous sync connection is not supported.

On hosts without PHP-FPM's fastcgi_finish_request(), deferred falls back to shutdown processing and may delay the browser response. Even on PHP-FPM, sending still occupies a PHP worker briefly. Buffered deliveries are not persisted in this mode.

This setting controls server deliveries and cached-verdict refreshes. Browser events sent directly to Botect bypass it; lookupVerdict() always makes an immediate request and waits for a response.

Setup guides: Plain PHP · Laravel · Configuration reference

What the SDK does

  • Renders the Botect browser collector with your project's site key.
  • Reads cached session verdicts and schedules background refreshes.
  • Queues assertions that a visitor has authenticated in your application.
  • Supports optional server page tracking and forwarding browser events through your application.
  • Sends server requests after the browser response by default, with optional file-spool and Laravel queue delivery.
  • Allows requests when verdict evidence is unavailable. Enforcement is opt-in.

The browser collector gathers signals; Botect's API computes scores. This package integrates those capabilities into your PHP application. It does not implement the scoring engine or wrap every Botect management API.

Requirements

Environment Requirements
Plain PHP PHP 8.3+, JSON, and cURL for the default HTTP transport
Laravel Laravel 12 with PHP 8.3+, or Laravel 13 with PHP 8.4+

Enable scoring for a project in Botect to obtain its site key (pk_…) and private key (sk_…). The site key can appear in browser markup. Keep the private key on your server; it is required for verdicts, logged-in assertions, and server ingest. An account API token is a different credential—see Authentication.

Installation

The package is currently available from GitHub as a development version. Until it is published to Packagist, add the repository to your application's Composer configuration:

composer config repositories.botect vcs https://github.com/botect/botect-php.git
composer require botect/botect-php:dev-main

Commit your application's composer.lock to keep deployments on the same revision. Laravel support is included in this package; no separate Laravel package is needed.

Plain PHP quickstart

1. Configure the client

Create botect.php in your application root, outside the public directory:

<?php

declare(strict_types=1);

require __DIR__.'/vendor/autoload.php';

use Botect\Botect;
use Botect\Configuration;

return Botect::create(
    new Configuration(
        siteKey: (string) getenv('BOTECT_SITE_KEY'),
        privateKey: getenv('BOTECT_PRIVATE_KEY') ?: null,
    ),
);

Provide the environment variables through your application's environment or existing configuration loader. The SDK does not load .env files itself. The default delivery mode does not require a storage directory or background worker.

2. Add the browser collector

In your page template, render the collector once, before </head> or </body>:

<?php $botect = require dirname(__DIR__).'/botect.php'; ?>
<!doctype html>
<html>
<head>
    <title>My application</title>
    <?= $botect->collector() ?>
</head>
<body>
    <!-- Your page content -->
</body>
</html>

By default, the collector loads from https://cdn.botect.ai/v1/sdk.js and sends browser events directly to https://api.botect.ai/v1/events.

For a Content Security Policy nonce, use $botect->collector(cspNonce: $nonce). Your policy must also permit the collector's script source and event destination.

3. Let the SDK send after the response

This quickstart uses deferred. No additional worker setup is needed. When you call loggedIn(), recordPage(), or forwardEvents(), the SDK buffers the delivery in memory. At the end of the request, it releases an active PHP session lock and calls fastcgi_finish_request() when available, then attempts each buffered delivery once.

On PHP-FPM, the browser receives the completed response before delivery starts. The PHP worker remains occupied briefly while sending. Failed deliveries are discarded: this mode does not persist or retry them, and a killed process can lose pending deliveries.

On hosts without fastcgi_finish_request(), the fallback runs during PHP shutdown and may delay the browser response. In long-running plain PHP processes, call $botect->sendPending() at the end of each request or unit of work, after your host has sent its response. PHP shutdown happens only when the process exits.

The buffer accepts up to 10 distinct deliveries and 1 MiB of serialized data per drain. A 1,000 ms budget is checked between attempts; an attempt already in progress can run until its configured HTTP timeout. Remaining deliveries are discarded when the budget is exhausted. Calls return false if a delivery cannot fit in the buffer.

Optional: file-spool delivery

For persistence and retries, opt into the existing file-spool mode:

$botect = Botect::create(
    new Configuration(
        siteKey: (string) getenv('BOTECT_SITE_KEY'),
        privateKey: getenv('BOTECT_PRIVATE_KEY') ?: null,
    ),
    storageDirectory: __DIR__.'/var/botect',
    delivery: 'spool',
);

Keep that directory outside the public web root. The web application and worker must use the same configuration and storage directory. Run $botect->flush(limit: 100) from a CLI worker or cron; see the worker example. Never flush the file spool during a visitor's request. Browser events sent directly to Botect do not use either delivery buffer.

Laravel quickstart

1. Publish configuration

Laravel discovers the service provider automatically:

php artisan vendor:publish --tag=botect-config

Set your project's keys in .env:

BOTECT_SITE_KEY=pk_your_site_key
BOTECT_PRIVATE_KEY=sk_your_private_key

The complete configuration is in config/botect.php. Tracking and enforcement are disabled by default.

2. Add the collector to Blade

Place the directive once in your layout:

<head>
    @botect
</head>

For a CSP nonce, use @botect($nonce).

The client is also available through the container as Botect\Botect and through the Botect\Laravel\Facades\Botect facade.

3. Set up your chosen delivery mode

Use the delivery-mode table to choose a value for BOTECT_DELIVERY. The setup for each mode follows.

Deferred (default): nothing else to configure. Laravel drains the in-memory delivery buffer through its application-termination hook after the response is sent. No Laravel queue connection or worker is required. The same best-effort limits and non-FPM caveat described above apply.

BOTECT_DELIVERY=deferred

File spool: set BOTECT_DELIVERY=spool, add this to routes/console.php, and run your application's Laravel scheduler:

use Illuminate\Support\Facades\Schedule;

Schedule::command('botect:flush --limit=100')
    ->everyMinute()
    ->withoutOverlapping()
    ->runInBackground();

Spool files are stored under storage/app/private/botect, separated by project and API URL. Each local spool needs a worker that can access it. Schedule more frequent flushing if you need prompt verdict refreshes.

Asynchronous queue: use your application's existing Laravel queue setup by setting just:

BOTECT_DELIVERY=queue

The SDK uses queue.default (normally configured by Laravel's QUEUE_CONNECTION) and the default queue configured for that connection in config/queue.php. Your existing workers process Botect jobs alongside application jobs; no separate Botect queue or worker is required. Those workers must consume the selected connection's default queue.

The sync driver is not supported for queue delivery; use deferred when you do not have an asynchronous queue worker. With queue delivery, use your existing worker instead of botect:flush.

Optional queue customization

Set these only if you deliberately want different routing for Botect jobs:

Optional environment variable Purpose When unset
BOTECT_QUEUE_CONNECTION Select a different configured Laravel connection Uses queue.default
BOTECT_QUEUE Select a different queue on that connection Uses the connection's configured default queue

For example, to use an existing Redis connection with a dedicated queue:

BOTECT_QUEUE_CONNECTION=redis
BOTECT_QUEUE=botect

Both overrides are independent. If you set either, make sure a worker consumes the selected connection and queue.

Laravel verdicts use your configured cache store. Web processes and queue workers must share that cache for background refreshes to be useful; set BOTECT_CACHE_STORE when needed.

Reading verdicts

A verdict needs a response from Botect, so the SDK provides two explicit choices.

Immediate lookup

Use lookupVerdict() when you need evidence for the current request:

$verdict = $botect->lookupVerdict($sessionToken, ['path' => '/checkout']);

if ($verdict->available()) {
    $score = $verdict->score;
    $action = $verdict->action;
    $reason = $verdict->reason;
}

In Laravel:

use Botect\Laravel\Facades\Botect;

$verdict = Botect::lookupVerdict($sessionToken);

This method makes one immediate HTTP request and waits up to the configured timeout. It does not retry or buffer a refresh. Invalid input, a missing private key, network failures, and unavailable evidence return an allow verdict.

Cached lookup

$botect->verdict($sessionToken) reads cached evidence without making an inline HTTP request. On a miss, it schedules a refresh through your chosen delivery driver and returns action: allow, verdict: not_computed, and score: 0. Cached verdicts expire after 10 seconds by default.

The default plain PHP cache exists only for the current request. A refresh after the response cannot benefit the next request unless you configure a persistent cache. Use lookupVerdict() for the simplest plain PHP integration. For cached lookups, pass a private storageDirectory to Botect::create() to enable the file verdict cache without changing the delivery mode, or supply your own VerdictCache implementation through the cache argument. For the optional file verdict cache, periodically call $botect->pruneVerdictCache() from CLI to remove expired files; spool flush() already does this. No cache maintenance is needed for the default request-local cache. Laravel uses its configured cache store automatically.

Both lookup methods accept the context keys path, ip, country, and ua; values must be strings. Cached lookups use separate entries for different contexts.

In direct browser mode, the collector's session token lives in browser local storage. Your application must explicitly pass that token to its server when using verdicts or logged-in assertions; the SDK does not discover it from a PHP session. With server tracking enabled, use the signed session cookie described below.

See Verdict API and Score bands for response fields and scoring behavior.

Marking a visitor as logged in

After your application has authenticated a visitor, schedule an assertion for their Botect session:

$queued = $botect->loggedIn($sessionToken);

Or with the Laravel facade:

use Botect\Laravel\Facades\Botect;

$queued = Botect::loggedIn($sessionToken);

A true result means the configured dispatcher accepted the assertion, not that Botect has accepted it yet. The default mode sends it after the response; spool and queue modes use their workers. The SDK invalidates the local verdict cache for that session and sends no application user ID or email address with the assertion.

See Logged-in visitors for how assertions interact with your rules.

Optional server tracking

Server tracking records page observations and routes browser events through an endpoint on your application. Enable it only when your Botect backend supports and has enabled the server-ingest endpoints. It is disabled by default.

For Laravel, set:

BOTECT_SERVER_INGEST_ENABLED=true

Then change the existing tracking settings in config/botect.php:

'tracking' => [
    'enabled' => true,
    'inject_collector' => true,
    'except' => ['admin/*'],
],

When enabled, the provider adds tracking to the web middleware group and registers POST /_botect/events. Eligible successful HTML GET responses receive a signed HttpOnly session cookie and a collector configured to use that local endpoint. Browser forwarding and page observations use the configured delivery mode.

Tracking injects the collector automatically. If you render @botect yourself, set tracking.inject_collector to false. For automatic injection under a nonce-based CSP, supply a csp_nonce request attribute.

Tracked HTML contains visitor-specific tokens and is marked private, no-store. Bypass full-page and CDN HTML caching for tracked pages. Rebuild Laravel's configuration and route caches after changing the server-ingest setting or ingest path.

Resolve a session token from the signed cookie in Laravel:

use Botect\Laravel\Facades\Botect;

$sessionToken = Botect::sessionToken(
    (string) request()->cookie(config('botect.cookie_name'), ''),
);

An absent or invalid cookie returns null; check for a token before calling loggedIn() or verdict().

Plain PHP applications can build the same integration using page(), sessionCookie(), recordPage(), collector($page), and forwardEvents(). Set serverIngestEnabled: true in Configuration, and implement the local POST handler at ingestPath to pass the signed page token and decoded collector body to forwardEvents(). The plain PHP core does not register routes or set cookies for you.

Optional Laravel enforcement

Enable enforcement.enabled in config/botect.php, then apply the middleware to the routes you want to protect:

use Illuminate\Support\Facades\Route;

Route::get('/checkout', CheckoutController::class)
    ->middleware('botect.enforce');

Use your application's controller. The middleware uses cached verdict() reads, so choose a persistent Laravel cache store for evidence to survive between requests. It needs a valid Botect server session cookie or a botect.session_token request attribute supplied by your integration; adding it alone does not connect a direct browser session to Laravel.

The default handler returns HTTP 403 for block and HTTP 429 with Retry-After: 5 for delay. It allows allow, log, challenge, and unavailable evidence. To implement an actual challenge flow or different responses, provide a class implementing Botect\Laravel\Contracts\VerdictHandler and configure enforcement.handler to use it.

Configuration reference

Setting Plain PHP constructor argument Laravel configuration Default
API base URL apiUrl botect.api_url / BOTECT_API_URL https://api.botect.ai/v1
Collector URL collectorUrl botect.collector_url / BOTECT_COLLECTOR_URL https://cdn.botect.ai/v1/sdk.js
Server ingest serverIngestEnabled botect.server_ingest_enabled / BOTECT_SERVER_INGEST_ENABLED false
Local ingest path ingestPath botect.ingest_path / BOTECT_INGEST_PATH /_botect/events
Connection timeout connectTimeoutMs botect.connect_timeout_ms 200 ms
Request timeout timeoutMs botect.timeout_ms 1,000 ms
Verdict cache lifetime verdictTtl botect.verdict_ttl 10 seconds
Signed page token lifetime pageTokenTtl botect.page_token_ttl 900 seconds
Maximum forwarded body size maxBodyBytes botect.max_body_bytes 262,144 bytes

API and collector URLs must be absolute HTTPS URLs. See Configuration for validation limits and config/botect.php for Laravel delivery, cache, cookie, and tracking settings.

Delivery values, defaults, and configuration locations are listed in Choose a delivery mode. Supplying a storage directory alone enables file verdict caching; it does not select spool delivery.

For custom infrastructure, the core accepts implementations of Dispatcher, VerdictCache, and HttpTransport. Laravel applications can bind those contracts in their own service provider.

Documentation and examples

Development

composer install
composer check

composer check runs the test suite and a standalone integration check that rejects any Laravel or Symfony class loading in the plain PHP core. The CI matrix covers PHP 8.3–8.5 and Laravel 12–13, excluding Laravel 13 on PHP 8.3.

Run php tests/fpm.php for an isolated PHP-FPM smoke test that verifies response completion before delivery. Set PHP_FPM_BINARY if the binary is not at the default system path.

Report SDK bugs and feature requests in GitHub Issues. Include your PHP/Laravel versions and a minimal reproduction, with credentials removed.

Contributing

See contributing.md for setup, testing, and the pull request workflow.

License

This package is available under the MIT license.