smalk/laravel-ads
最新稳定版本:v0.1.0
Composer 安装命令:
composer require smalk/laravel-ads
包简介
Server-side Smalk native-ad injection + AI-agent tracking for Laravel publishers.
README 文档
README
Server-side Smalk native-ad injection and AI-agent tracking for Laravel publishers.
Laravel 10 / 11 / 12 · PHP 8.1+
How it works
AI crawlers (ChatGPT, Perplexity, Claude, Gemini) do not execute JavaScript, so ads must already be present in the HTML your server returns — client-side injection is invisible to them. This package registers a middleware on the web group that intercepts each outgoing HTML response, calls the Smalk Ad Server to retrieve the active ad, and replaces the <div class="smalk-ads"></div> placeholder before the response leaves your server. A second stage fires an after-response tracking call so plain-HTTP AI agents — which also skip the JS tracker — are recorded in your Smalk dashboard.
Install
Step 1 — require the package
composer require smalk/laravel-ads
Step 2 — publish the config
php artisan vendor:publish --tag=smalk-config
Step 3 — set credentials in .env
SMALK_PROJECT_KEY=your-project-key SMALK_API_KEY=your-api-key
Those two variables are the only mandatory ones. Everything else has a sensible default (see Configuration below).
Placing an ad
Add exactly one ad slot per page. Two options:
Option A — div placeholder (recommended)
Drop this once in your Blade layout (e.g. resources/views/layouts/app.blade.php), in the body at the point where the ad should appear:
<div class="smalk-ads"></div>
The middleware detects the div, fetches the active ad HTML from the Smalk Ad Server, and replaces it before the response is sent. If no ad is live for that URL, the div is left intact — do not remove it: Smalk uses its presence to verify the placement is installed.
Option B — Blade component
Use the component when you want to resolve the ad at render time, or when your layout is composed dynamically per-route:
<x-smalk-ad path="/{{ $currentPath }}" />
Omit path to let the component fall back to the current request URL.
One slot per page maximum. Multiple
smalk-adsdivs on the same page are not supported.
Configuration
After publishing, the config lives at config/smalk.php. Every value is driven by an environment variable.
Credentials
| Env var | Default | Effect |
|---|---|---|
SMALK_PROJECT_KEY |
— | Required. Workspace project key — sent with every ad request and used by smalk:freshness to hit /projects/{key}/ads/inventory/active-ad-urls/. |
SMALK_API_KEY |
— | Required. Sent as Authorization: Api-Key … on all server-side calls. |
SMALK_API_BASE |
https://api.smalk.ai/api/v1 |
Base URL for the Smalk API. Only change this for staging. |
JS Tracker
| Env var | Default | Effect |
|---|---|---|
SMALK_JS_TRACKER_ENABLED |
true |
When true, the middleware appends <script src="…/tracker.js?PROJECT_KEY=…"> before </head> on every HTML response. |
SMALK_TRACKER_CDN |
https://cdn.smalk.ai/tracker.js |
CDN URL for tracker.js. Not versioned by SRI — the script is a dynamic versioned asset matching the WordPress, Drupal, and Node plugins. |
AI Agent Tracking
| Env var | Default | Effect |
|---|---|---|
SMALK_TRACKING_ENABLED |
true |
When true, the middleware fires an after-response POST /api/v1/tracking/visit/ for every request on the web middleware group. Never blocks the response. |
SMALK_TRACKING_FORWARD_IP |
false |
When true, the visitor's IP (X-Real-IP / X-Forwarded-For) is forwarded to Smalk alongside User-Agent and Referer. Off by default — see GDPR note. |
Ad Injection
| Env var | Default | Effect |
|---|---|---|
SMALK_ADS_ENABLED |
true |
When true, the middleware fetches and injects server-side ad HTML into the <div class="smalk-ads"> placeholder. |
SMALK_ADS_CACHE_TTL |
21600 |
max-age value (seconds) used in the Cache-Control header on ad-bearing paths. Default is 6 hours. |
JSON-LD
| Env var | Default | Effect |
|---|---|---|
SMALK_JSONLD_REWRITE |
true |
When true, the middleware rewrites dateModified only within <script type="application/ld+json"> structured-data blocks to surface the ad content to AI engines via structured data, after a successful ad injection. |
Freshness & Cache
| Env var | Default | Effect |
|---|---|---|
SMALK_FRESHNESS_ENABLED |
true |
When true, the smalk:freshness command is auto-scheduled to run daily. |
SMALK_CACHE_PURGER |
Smalk\Ads\Cache\NullCachePurger |
Fully-qualified class name of your CachePurger implementation. See Freshness & cache below. |
Freshness & cache
Ad creatives rotate. To ensure visitors and crawlers always receive the latest ad, the package manages cache freshness through three complementary layers.
The smalk:freshness command
The package auto-schedules smalk:freshness to run once a day using Laravel's built-in scheduler (registered via callAfterResolving, so no manual $schedule->command(…) is needed). This command:
- Fetches your active-ad URLs from
GET /api/v1/projects/{project_key}/ads/inventory/active-ad-urls/. - Stores the path list in the application cache so the middleware can set
Last-ModifiedandCache-Controlheaders on those responses. - Calls your configured
CachePurgerto clear full-page caches for those URLs.
Requirement: your server must run the Laravel task scheduler. Add this to your system crontab if it isn't already:
* * * * * cd /var/www/your-app && php artisan schedule:run >> /dev/null 2>&1
You can also run it manually at any time:
php artisan smalk:freshness
Three cache-clear layers
Layer A — Smalk-managed CDN purge (recommended, zero code)
Register your CDN credentials in the Smalk dashboard and Smalk will purge active-ad URLs nightly. No code changes on your side.
Supported providers: Cloudflare, CloudFront, Fastly, Akamai, KeyCDN.
Register credentials at: https://app.smalk.ai/workspaces/{workspace-id}/ads/brand-safety/cdn
Layer B — Application-level cache purge via CachePurger
If you use spatie/laravel-responsecache, point SMALK_CACHE_PURGER at the built-in adapter:
SMALK_CACHE_PURGER=Smalk\Ads\Cache\ResponseCachePurger
For any other full-page caching layer, implement the Smalk\Ads\Cache\CachePurger interface:
namespace App\Cache; use Smalk\Ads\Cache\CachePurger; class VarnishCachePurger implements CachePurger { /** @param string[] $urls */ public function purge(array $urls): void { foreach ($urls as $url) { // send a PURGE request to your Varnish node, call an SDK, etc. } } }
Then wire it in .env:
SMALK_CACHE_PURGER=App\Cache\VarnishCachePurger
Layer C — Automatic Last-Modified + Cache-Control headers (always on)
After a successful freshness sweep, the middleware automatically sets:
Last-Modified: <UTC day boundary>
Cache-Control: public, max-age=21600
on every response for a URL in the active-ad list. This ensures downstream CDNs and browsers respect the 6-hour TTL cap and revalidate when the ad changes. No configuration needed.
Disabling pieces
All three concerns are independently toggleable. Only want the JS tracker?
SMALK_ADS_ENABLED=false SMALK_TRACKING_ENABLED=false
Only want server-side ads and tracking, without the JS tracker (e.g. you add the <script> tag by hand in your layout)?
SMALK_JS_TRACKER_ENABLED=false
Shut everything off:
SMALK_JS_TRACKER_ENABLED=false SMALK_ADS_ENABLED=false SMALK_TRACKING_ENABLED=false
Manual middleware registration
The package appends SmalkMiddleware to the web group automatically on boot (using pushMiddlewareToGroup, which is stable across Laravel 10–12). This covers the vast majority of setups.
If you need to control the exact position of the middleware in the stack, you can also add it explicitly. In Laravel 11 / 12, in bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) { $middleware->web(append: [\Smalk\Ads\Http\Middleware\SmalkMiddleware::class]); })
In Laravel 10, in app/Http/Kernel.php, append it to the web group:
protected $middlewareGroups = [ 'web' => [ // ... existing middleware ... \Smalk\Ads\Http\Middleware\SmalkMiddleware::class, ], ];
Note: there is currently no config flag to prevent auto-registration. If you add the middleware manually in a position that matters, bear in mind it will be registered twice. The middleware is idempotent (the ad fetch and tracking dispatch are both guarded by
str_containsfast-paths and config checks), so duplicate registration is harmless — but you can open an issue if your setup requires explicit opt-out.
Verify
After deploying, confirm the ad is present in the server-rendered HTML by simulating a ChatGPT crawler:
curl -A "Mozilla/5.0 (compatible; ChatGPT-User/1.0)" https://your.site/article | grep -A2 smalk-ads
You should see the <div class="smalk-ads"> replaced with Smalk ad HTML. If you see the empty <div> instead, no active booking exists for that URL yet — the integration is working correctly.
GDPR
The JS tracker is bot-focused. It does not track human visitors, build profiles, set cookies, or store PII. Smalk has no human-analytics product.
The server-side tracking call forwards User-Agent and Referer only. IP forwarding (SMALK_TRACKING_FORWARD_IP) is off by default. Enabling it constitutes server-side processing of personal data; a Data Processing Agreement (DPA) is available — contact privacy@smalk.ai.
License
MIT
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-10