smking / laravel
Laravel package for smking AEO — auto-inject JSON-LD, FAQ, and AI summary into Laravel responses so AI crawlers (ChatGPT, Perplexity, Google AI) can cite your pages.
Requires
- php: ^8.1
- illuminate/contracts: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
README
AI-native SEO (AEO) for Laravel. Auto-inject JSON-LD, FAQ, and AI summaries into your pages so ChatGPT, Perplexity, and Google AI can cite them.
Install
composer require smking/laravel
Publish the config:
php artisan vendor:publish --tag=smking-config
Configure your .env:
SMKING_API_KEY=pk_... SMKING_BASE_URL=https://your-smking-instance.example
Both values are required. SMKING_BASE_URL must point at your smking deployment — the package ships with no default so it never silently talks to the wrong host.
That's it — the middleware auto-registers. Every HTML GET response now picks up:
- AEO — JSON-LD, FAQ/summary blocks (for ChatGPT, Perplexity, Google AI)
- SEO —
<title>,og:*,twitter:*,<link rel="canonical">(for Google snippet + social shares)
The middleware never overrides tags your layout already writes — it only fills gaps. So Yoast / your existing meta-writing tooling stays the source of truth.
Install verification
After composer require + vendor:publish + .env setup, run:
php artisan smking:doctor
If everything is green, the install is complete. The doctor command runs six checks: config publish status (informational — defaults are merged automatically, publishing is only needed when you want to override only/except/inject.*), API key (must be set and start with pk_), base URL (must be set and a valid URL), middleware is in the HTTP kernel (reflection check), API reachable (POSTs an empty body to {base_url}/api/v1/public/aeo and expects 400/401/422 — confirms the endpoint exists rather than just any live host), and AEO status for a probe path (informational — defaults to a synthetic __smking-doctor so doctor runs don't pollute the audit queue with real URLs).
For HTTP-level verification, hit any HTML page and look at the response headers:
curl -I http://your-app.test/
You should see two headers — these confirm the middleware ran, regardless of whether the smking backend has audited your URL yet:
X-Smking-Status: ready | pending | not_found | disabled
X-Smking-Path: /<your-path>
The data-smking-injected="1" HTML attribute also appears on every page where middleware ran (HTML 200 GET, not in except patterns). Content injection (JSON-LD, FAQ, SEO meta) only appears once status reaches ready — which requires the URL to be reachable from the public internet so the backend can crawl it.
Local dev with
.test/.localTLDs: the backend can't reach your machine, so status stays atnot_founduntil you deploy. The middleware mark and theX-Smking-*headers still verify the install —php artisan smking:doctoris the authoritative install signal. Inlocal/testing/developmentenvironments you'll also see an HTML comment near</body>explaining why content wasn't injected.
Manual usage
Disable auto-injection and render where you want:
// config/smking.php 'auto_inject' => false,
{{-- 1. Body content (JSON-LD + FAQ + summary) --}} <x-smking-aeo path="/products/{{ $product->slug }}" /> {{-- 2. SEO meta inside <head> with fallback to your own page data --}} <head> <x-smking-meta :path="request()->path()" :fallback-title="$product->name" :fallback-og-description="$product->short_description" /> </head> {{-- 3. Facade for full control --}} @php($aeo = \Smking::forPath('/products/'.$product->slug)) @if ($aeo->isReady()) <script type="application/ld+json">{!! json_encode($aeo->jsonLd) !!}</script> <title>{{ $aeo->seo?->title ?? $product->name }}</title> @endif
The <x-smking-meta /> component mirrors getSmkingMetadata() from @smking/next — call it inside <head> and it emits exactly the SEO tags the API has values for, falling back to the fallback-* props otherwise. Use it when you want SEO meta in your Blade layout but body injection from the middleware.
Config (config/smking.php)
| Key | Default | Notes |
|---|---|---|
api_key |
env('SMKING_API_KEY') |
Publishable key from the dashboard |
base_url |
(required, no default) | Set SMKING_BASE_URL to your smking deployment origin |
auto_inject |
true |
Register middleware globally |
only / except |
see file | Path filters (Laravel wildcard) |
inject.* |
all true |
Toggle json_ld / meta_description / faq / summary / seo_title / og_title / og_description / og_image / canonical |
cache.ttl |
3600 |
Seconds; 0 disables |
timeout |
3 |
HTTP timeout in seconds |
How it works
- Middleware runs after your response is built.
- For each HTML
GET200, it callsPOST /api/v1/public/aeowith the request path. - If smking has ready content, structured data + SEO meta go into
<head>; FAQ + summary go before</body>. - Conflict detection: every SEO tag (
<title>,og:*,canonical,meta description) is only written when the host page hasn't already written it — so Yoast-equivalent tooling, custom Blade layouts, or hand-written meta tags stay untouched. - Unknown paths are registered for background crawling — next request will serve content.
- Responses are cached per path in Laravel's cache. Pending/error states fail open.
Requirements
- PHP 8.1+
- Laravel 10 / 11 / 12
License
MIT