PHPackages                             smalk/laravel-ads - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. smalk/laravel-ads

ActiveLibrary[API Development](/categories/api)

smalk/laravel-ads
=================

Server-side Smalk native-ad injection + AI-agent tracking for Laravel publishers.

v0.1.0(1mo ago)00MITPHPPHP ^8.1

Since Jun 10Pushed 1mo agoCompare

[ Source](https://github.com/smalk-ai/laravel_plugin)[ Packagist](https://packagist.org/packages/smalk/laravel-ads)[ RSS](/packages/smalk-laravel-ads/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (4)Versions (2)Used By (0)

smalk/laravel-ads
=================

[](#smalklaravel-ads)

Server-side Smalk native-ad injection and AI-agent tracking for Laravel publishers.

**Laravel 10 / 11 / 12 · PHP 8.1+**

---

How it works
------------

[](#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 `` 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
-------

[](#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](#configuration) below).

---

Placing an ad
-------------

[](#placing-an-ad)

Add **exactly one** ad slot per page. Two options:

### Option A — div placeholder (recommended)

[](#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:

```

```

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

[](#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:

```

```

Omit `path` to let the component fall back to the current request URL.

> **One slot per page maximum.** Multiple `smalk-ads` divs on the same page are not supported.

---

Configuration
-------------

[](#configuration)

After publishing, the config lives at `config/smalk.php`. Every value is driven by an environment variable.

### Credentials

[](#credentials)

Env varDefaultEffect`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

[](#js-tracker)

Env varDefaultEffect`SMALK_JS_TRACKER_ENABLED``true`When `true`, the middleware appends `` before `` 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

[](#ai-agent-tracking)

Env varDefaultEffect`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](#gdpr).### Ad Injection

[](#ad-injection)

Env varDefaultEffect`SMALK_ADS_ENABLED``true`When `true`, the middleware fetches and injects server-side ad HTML into the `` 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

[](#json-ld)

Env varDefaultEffect`SMALK_JSONLD_REWRITE``true`When `true`, the middleware rewrites `dateModified` only within `` structured-data blocks to surface the ad content to AI engines via structured data, after a successful ad injection.### Freshness &amp; Cache

[](#freshness--cache)

Env varDefaultEffect`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 &amp; cache](#freshness--cache) below.---

Freshness &amp; cache
---------------------

[](#freshness--cache-1)

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-smalkfreshness-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:

1. Fetches your active-ad URLs from `GET /api/v1/projects/{project_key}/ads/inventory/active-ad-urls/`.
2. Stores the path list in the application cache so the middleware can set `Last-Modified` and `Cache-Control` headers on those responses.
3. Calls your configured `CachePurger` to 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

[](#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](https://github.com/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:
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
----------------

[](#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 `` 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
------------------------------

[](#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_contains` fast-paths and config checks), so duplicate registration is harmless — but you can open an issue if your setup requires explicit opt-out.

---

Verify
------

[](#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 `` replaced with Smalk ad HTML. If you see the empty `` instead, no active booking exists for that URL yet — the integration is working correctly.

---

GDPR
----

[](#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 .

---

License
-------

[](#license)

MIT

###  Health Score

33

—

LowBetter than 72% of packages

Maintenance90

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity32

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

45d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1295125?v=4)[Antonin Lacombe](/maintainers/iXioN)[@iXioN](https://github.com/iXioN)

---

Top Contributors

[![iXioN](https://avatars.githubusercontent.com/u/1295125?v=4)](https://github.com/iXioN "iXioN (3 commits)")

---

Tags

laraveladsaigeosmalk

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/smalk-laravel-ads/health.svg)

```
[![Health](https://phpackages.com/badges/smalk-laravel-ads/health.svg)](https://phpackages.com/packages/smalk-laravel-ads)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

813336.8k3](/packages/defstudio-telegraph)[api-platform/laravel

API Platform support for Laravel

58174.6k17](/packages/api-platform-laravel)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5022.6k](/packages/simplestats-io-laravel-client)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
