A zero-modification Laravel package that provides complete data isolation for live product demos, SaaS playgrounds, interactive trial sessions, and testing environmentsโwithout altering a single line of your existing models, migrations, or database tables.
When offering live demos or trial sessions for your SaaS or web application, visitors often want to create, edit, or delete data (e.g., creating blog posts, adding products, modifying settings).
Traditionally, developers had to choose between:
- Resetting the database periodically: Interrupts active users and causes data collisions across simultaneous visitors.
- Modifying application logic & models: Polluting codebase with tenant checks, session filters, or custom traits.
- Spinning up isolated containers per user: Expensive, slow, and hard to manage at scale.
Sandboxer intercepts Eloquent CRUD operations per user session transparently. Any data created, updated, or deleted by a demo visitor exists only in their isolated sandbox session.
- Master Database is 100% untouched: Production data remains safe and pristine.
- Zero Model Modifications: Works out-of-the-box without adding traits or modifying your Eloquent models or migrations.
- Multi-Visitor Isolation: Visitor A sees their sandboxed changes; Visitor B sees theirsโneither affects the master database or each other.
- Automatic Expiration & Cleanup: Sessions and sandboxed data expire automatically after a configured TTL.
Install Sandboxer via Composer.
If you are deploying Sandboxer to provide live demo environments, interactive product tours, or sandbox mode in your production or staging SaaS application, install it as a main dependency:
composer require cyclechain/sandboxerIf you are using Sandboxer strictly for local development isolation, testing, or preview environments, install it as a dev dependency:
composer require cyclechain/sandboxer --devPublish the configuration file:
php artisan vendor:publish --tag=sandboxer.configRun the package database migrations (creates sandbox_sessions and sandbox_storage tables):
php artisan migrateEnable sandbox mode in your .env file:
SANDBOXER_ENABLED=true
SANDBOXER_TTL=3600
SANDBOXER_DEMO_EMAIL=[email protected]
SANDBOXER_DEMO_PASSWORD=adminThat's it! Sandboxer automatically intercepts database operations whenever sandbox mode is activated.
Sandboxer can automatically detect and activate sandbox mode for incoming HTTP requests based on:
- Subdomains:
demo.yourdomain.com,sandbox.yourdomain.com,try.yourdomain.com - URL Paths:
/demo,/sandbox,/try - Query Parameters:
?sandbox=1,?demo=true - Active Session Cookie:
sandbox_sessioncookie
Configure auto-detection in config/sandboxer.php:
'auto_detection' => [
'domains' => 'demo.*.com,sandbox.*.com,try.*.com',
'paths' => '/demo,/sandbox,/try',
'parameters' => ['sandbox' => '1', 'demo' => 'true'],
],For applications requiring demo user login, update your login controller (or custom auth handler) using SandboxAuthHelper:
use Cyclechain\Sandboxer\Helpers\SandboxAuthHelper;
use Illuminate\Http\Request;
public function login(Request $request)
{
// Handle demo/sandbox login credentials transparently
$sandboxResponse = SandboxAuthHelper::handleSandboxLogin($request, '/dashboard');
if ($sandboxResponse) {
return $sandboxResponse;
}
// Normal application login flow
return parent::login($request);
}Use the Sandboxer Facade to check or control sandbox state manually:
use Cyclechain\Sandboxer\Facades\Sandboxer;
// Check if sandbox mode is active for current request
if (Sandboxer::isActive()) {
// Current request is sandboxed
}
// Get the current sandbox session UUID
$sandboxId = Sandboxer::currentId();
// Manually destroy current sandbox session and clear storage
app(\Cyclechain\Sandboxer\SandboxManager::class)->destroy();Sandbox sessions expire automatically based on the SANDBOXER_TTL setting (default: 3600 seconds / 1 hour).
To clean up expired sessions, schedule the SandboxCleanupJob in your app/Console/Kernel.php or routes/console.php:
use Illuminate\Support\Facades\Schedule;
use Cyclechain\Sandboxer\Jobs\SandboxCleanupJob;
Schedule::job(new SandboxCleanupJob())->hourly();Or dispatch manually:
php artisan queue:workIncoming Request
โ
Sandbox Middleware (detects subdomain, path, query, or cookie)
โ
ModelEventInterceptor & Pretend Mode (captures creating, updating, deleting without touching DB)
โ
StorageManager (stores operations in sandbox_storage table)
โ
SandboxScope & Eloquent Builder (merges master DB data with sandboxed CRUD mutations on reads)
โ
Response (displays isolated data to the visitor)
- Write Interception: When a model is created, updated, or deleted,
ModelEventInterceptorcaptures the attributes, places the database connection in pretend mode (preventing actual SQL writes), and persists the mutation intosandbox_storage. - Read Interception: When Eloquent queries execute (
all(),where(),find()),SandboxScopeoverlays sandboxed insertions, updates, and deletions onto the retrieved master data.
Edit config/sandboxer.php:
return [
'enabled' => env('SANDBOXER_ENABLED', false),
'ttl' => env('SANDBOXER_TTL', 3600),
'demo_credentials' => [
'email' => env('SANDBOXER_DEMO_EMAIL', '[email protected]'),
'password' => env('SANDBOXER_DEMO_PASSWORD', 'admin'),
],
// Tables excluded from sandboxing (e.g. system/auth tables)
'excluded_tables' => ['users', 'sessions', 'password_reset_tokens', 'migrations', 'sandbox_sessions', 'sandbox_storage'],
'cache' => [
'enabled' => env('SANDBOXER_CACHE_ENABLED', true),
'prefix' => env('SANDBOXER_CACHE_PREFIX', 'sandbox'),
'ttl' => env('SANDBOXER_CACHE_TTL', 3600),
],
'auto_detection' => [
'domains' => env('SANDBOXER_AUTO_DOMAINS', 'demo.*.com,sandbox.*.com,try.*.com'),
'paths' => env('SANDBOXER_AUTO_PATHS', '/demo,/sandbox,/try'),
'parameters' => ['sandbox' => '1', 'demo' => 'true'],
],
'cleanup' => [
'enabled' => env('SANDBOXER_CLEANUP_ENABLED', true),
'interval' => env('SANDBOXER_CLEANUP_INTERVAL', 3600),
],
];Run the PHPUnit test suite:
composer testOr via Docker:
docker run --rm -v $(pwd):/app -w /app laravelsail/php84-composer:latest ./vendor/bin/phpunit --bootstrap vendor/autoload.php packages/cyclechain/sandboxer/testsThe MIT License (MIT). Please see License File for more information.
Developed and maintained by Fatih Mert Doฤancan & CycleChain.