Textstem has 13 features that are off until a site turns them on. Most need one .env switch, and some also need extra packages, a queue worker or a host-app change.
At a glance
| Feature | Switch | Main requirement |
|---|---|---|
| Form Data | FORMS_ENABLED=true |
Migration; Livewire and Tailwind on public pages |
| Live page screenshots | TEXTSTEM_PAGE_SCREENSHOTS=true |
spatie/browsershot, Puppeteer, headless Chrome, queue worker |
| React rendering | TEXTSTEM_REACT_RENDERING=true |
Inertia and React frontend; textstem:install-react |
| MCP server | MCP_ENABLED=true |
None (endpoints are public) |
| Page cache | WRANGLER_CACHE_ENABLE=true |
A working cache store |
| External search (Scout) | searchable in config/pages.php, SCOUT_DRIVER |
A Scout engine such as Meilisearch or Algolia |
| Real-time updates | BROADCAST_DRIVER |
Pusher, Reverb or Soketi, and Laravel Echo in the host app |
| Scheduled security audit | Tools → Security Audit in the admin | Scheduler cron |
| AI description button | openai.generate_description in config |
An AI provider key |
| AI image comparison | images.comparison_driver = openai |
OpenAI key |
| Analyse on save | ACCESSIBILITY_CHECK_ON_SAVE, SEO_CHECK_ON_SAVE |
Queue worker recommended |
| Admin dark mode | DARK_MODE=true |
None |
| Redis | TEXTSTEM_USE_REDIS=true |
A Redis server and PHP Redis client |
AI features are on by default but do nothing until a provider key is set. That setup is covered under AI features below.
Form Data
Editors build forms in the admin, with steps, show-if rules and file uploads, then place them on pages with the Active Form block. Answers are kept in the admin, and can be emailed to staff, exported as CSV or posted to a webhook. While it's off, none of its tables, routes, menus, blocks or schedules load.
Needs
- Livewire scripts loaded on public pages
- The package's form views in Tailwind's
content, plus the@tailwindcss/formsplugin - A mailer and a queue worker, for staff emails and sender copies
- A private writable disk for uploads (
FORMS_UPLOAD_DISK, defaultlocal) - Optional: Cloudflare Turnstile keys (
TURNSTILE_SITE_KEY,TURNSTILE_SECRET_KEY) for the robot check - Optional:
FORMS_VISITOR_GUARDandFORMS_VISITOR_LOGIN_ROUTEfor forms limited to signed-in visitors
Turn it on
FORMS_ENABLED=true
php artisan migrate
php artisan config:cache # only if config is cached
The migration adds the textstem_forms* tables, four Form Data permissions and a forms-manager role. Old answers are pruned daily at 03:45 by forms:prune-submissions.
Live page screenshots
The Pages admin's Cards and Columns views show a picture of each page, refreshed in the background a few seconds after each save. With screenshots off, each card shows the page's SEO image, else its first image, else an icon.
Needs
spatie/browsershot(Composer) andpuppeteer(npm) in the host app- Node.js 18+ and
chrome-headless-shell, installed as the queue worker's user - Chrome's system libraries and fonts on Linux
- A running queue worker; captures don't run with
QUEUE_CONNECTION=sync - About 150 to 300 MB of memory per capture
Turn it on
composer require spatie/browsershot
npm install puppeteer
npx puppeteer browsers install chrome-headless-shell
TEXTSTEM_PAGE_SCREENSHOTS=true
php artisan textstem:page-screenshots --check
php artisan textstem:page-screenshots --all
php artisan queue:restart
Set TEXTSTEM_SCREENSHOT_NODE, TEXTSTEM_SCREENSHOT_NPM or TEXTSTEM_SCREENSHOT_CHROME when those aren't on the worker's PATH. On Herd, also set TEXTSTEM_SCREENSHOT_IGNORE_HTTPS_ERRORS=true.
React rendering
Public pages render with Inertia and React instead of Blade. The admin panel stays Blade and Livewire. The post-login redirect becomes role-aware, and the admin bar keeps up with client-side navigation.
Needs
- An Inertia and React frontend: Laravel's React starter kit, or
@inertiajs/react,react,react-dom,@vitejs/plugin-reactandinertiajs/inertia-laraveladded by hand - Jetstream's Inertia option won't work, because it's Vue
- No team management unless you build it
- A React component for each custom Wrangler component
Turn it on
composer require inertiajs/inertia-laravel # if not already installed
php artisan textstem:install-react
The command publishes the React source to resources/js/ and can add TEXTSTEM_REACT_RENDERING=true to .env. Then route textstem/* pages to PublicLayout in resources/js/app.tsx, add textstem: TextstemSharedProps to sharedPageProps in resources/js/types/global.d.ts, and run npm run build.
MCP server
The site's content is exposed to AI assistants such as Claude Desktop and Cursor over the Model Context Protocol. Built-in resources cover site info, published public pages and published posts. You can add your own tools and resources.
Needs
- Nothing to install
- Care with what you expose: the
/mcpendpoints need no login, so expose only public content
Turn it on
MCP_ENABLED=true
MCP_PATH=mcp # default
MCP_RATE_LIMIT=60 # requests per minute per IP
MCP_SITE_DESCRIPTION="A short description of the site"
This registers GET /mcp and POST /mcp. To add your own, run php artisan textstem:make:mcp-tool {name} or php artisan textstem:make:mcp-resource {name}.
Page cache
Rendered public pages are cached, so repeat visits skip rendering.
Needs
- A working cache store (Redis recommended in production)
Turn it on
WRANGLER_CACHE_ENABLE=true
WRANGLER_CACHE_TTL=3600 # seconds
WRANGLER_CACHE_MODE=private # Cache-Control: public or private
WRANGLER_CACHE_WITHQUERY=false # true caches each query string separately
Clear it with php artisan cache:manage clear.
External search (Scout)
Pages and posts are indexed in an external engine for public site search. A page's index entry includes the text of its enabled blocks. The admin's own search at /textstem/search uses the database and doesn't need this.
Needs
- A Scout engine, such as Meilisearch, Algolia or Typesense, with its client package
- A front-end search page in the host app
Turn it on
Create config/pages.php in the host app. The page model reads pages.searchable:
return [
'searchable' => 1,
];
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://localhost:7700
MEILISEARCH_KEY=your-key
php artisan scout:import "Medialight\Textstem\Models\WranglerPage"
php artisan scout:import "Medialight\Textstem\Models\Post"
Only enabled, public, listed pages are indexed.
Real-time updates
The admin updates live over WebSockets when models change or AI jobs finish, instead of polling.
Needs
- A broadcast server: Pusher, Laravel Reverb or Soketi
- Laravel Echo set up in the host app's JavaScript
- A queue worker
Turn it on
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=...
PUSHER_APP_KEY=...
PUSHER_APP_SECRET=...
PUSHER_APP_CLUSTER=mt1
Then set up Echo in resources/js/bootstrap.js and rebuild. The package registers its own private textstem.* channels.
Scheduled security audit
textstem:security-audit runs on a schedule and can email a report.
Needs
- The scheduler cron (
php artisan schedule:runevery minute) - A mailer, for notifications
Turn it on
In the admin, open Tools → Security Audit and turn on the schedule. Choose daily or weekly (Wednesdays), a time (default 02:00), and whether to email always or only on alerts, and to which addresses.
AI features
All AI calls go through one service, which handles content generation, SEO analysis, accessibility checks, image comparison and the chat assistant. AI is on by default (OPENAI_ENABLED=true) but does nothing until a provider key is set.
Needs
- An OpenAI or Anthropic API key
- A queue worker, since AI jobs are queued by default (
OPENAI_USE_QUEUE=true)
Turn it on
# OpenAI
TEXTSTEM_AI_PROVIDER=openai
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o-mini
# or Anthropic
TEXTSTEM_AI_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_MODEL=claude-haiku-4-5-20251001
TEXTSTEM_AI_MODEL overrides the model for every feature.
Three AI extras are each off until you set them:
| Extra | Turn it on | Needs |
|---|---|---|
| Generate description button in editors | 'generate_description' => true under openai in config/textstemapp.php |
Provider key |
| AI image comparison | 'comparison_driver' => 'openai' under images in config/textstemapp.php (default fingerprint, no AI) |
OpenAI key |
| Image descriptions with Google Cloud Vision | GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json |
A Google Cloud service account with Vision enabled |
Analyse on save
Accessibility and SEO analysis normally run on demand. With these on, each save starts an analysis.
Needs
- A queue worker, so saves don't wait (
ACCESSIBILITY_USE_QUEUEandSEO_USE_QUEUEdefault totrue) - A provider key if
SEO_USE_AI=true
Turn it on
ACCESSIBILITY_CHECK_ON_SAVE=true
SEO_CHECK_ON_SAVE=true
Admin dark mode
Admin users can choose light, dark or their system setting.
Needs: nothing.
Turn it on: DARK_MODE=true
Redis
The package uses Redis for caching and queues.
Needs
- A Redis server
- The
phpredisextension or thepredis/predispackage, andREDIS_*connection settings
Turn it on: TEXTSTEM_USE_REDIS=true
Sources
config/textstem.php,src/TextstemServiceProvider.phpandsrc/Providers/TextstemFormsServiceProvider.phpinmedialight/textstem-laraveldocs/installation.md,docs/mcp.md,docs/search.md,docs/broadcasting.mdanddocs/ai-provider.mdin the same repository