clikgate / clikgate-laravel
Laravel integration for the Clikgate server SDK: auto-discovered provider, Clikgate facade, click-ID middleware and queued goal sending.
Requires
- php: >=8.2
- clikgate/clikgate-php: ^2.0
- illuminate/contracts: ^12.0 || ^13.0
- illuminate/http: ^12.0 || ^13.0
- illuminate/queue: ^12.0 || ^13.0
- illuminate/support: ^12.0 || ^13.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- orchestra/testbench: ^10.0 || ^11.0
- phpstan/phpstan: ^2.3
- phpunit/phpunit: ^10.5 || ^11.5 || ^12.4 || ^13.4
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Laravel integration for clikgate/clikgate-php: an auto-discovered service provider, the Clikgate facade, the clikgate middleware, $request->clikgateClickId(), and queued goal sending. Laravel 12 and 13.
composer require clikgate/clikgate-laravel
Set CLIKGATE_API_KEY=cg_live_… (or cg_test_…) in .env. To change other settings, publish the config with php artisan vendor:publish --tag=clikgate-config.
use Clikgate\Laravel\Facades\Clikgate; Clikgate::goal('account_opened', ['clickId' => $application->click_id, 'reference' => $application->reference, 'value' => '2000000']);
Keep the click ID
// bootstrap/app.php ->withMiddleware(function (Middleware $middleware) { $middleware->web(append: ['clikgate']); }) // a controller: save it with your own record Application::create(['reference' => 'APP-55231', 'click_id' => $request->clikgateClickId()]);
- The middleware keeps a
?cgid=…in the first-party_cg_cgidcookie, which the web script also reads. - The provider excludes that cookie from
EncryptCookies, so the web script can read it.
Keep the click ID longer (Safari)
Safari, and every browser on iPhone, keeps a click ID saved by a script for up to 7 days (sometimes less). When your server saves it, it lasts as long as you choose, up to the browser's limit.
- Persist it from the query: the
clikgatemiddleware above does it on every page of thewebgroup, with the_cg_kept=smarker (goals then reportkept_by: server_cookie). - The
/cg/keeproute, for pages Laravel doesn't render (a static or cached landing page): register it, and adddata-server-endpoint="/cg/keep"to the web script.
// routes/web.php Route::clikgateKeep('/cg/keep');
<script src="https://sdk.clikgate.com/v1/static/clikgate.js" data-web-key="cgw_test_…" data-server-endpoint="/cg/keep" async></script>
- Same server only. The route must be served by the same host as the website (same scheme, host and port), because the cookie is first-party.
- CSRF: the macro removes Laravel's CSRF middleware (
ValidateCsrfToken) from this one route, because the web script has no CSRF token. The route checks the origin itself (Sec-Fetch-Site: same-origin, else anOriginequal to the host), accepts only a JSON body of at most 1 KB with the same valid click ID inclick_idandpage_click_id, and changes nothing but these two cookies. Every answer is empty withCache-Control: no-store, private; it never redirects and never echoes or logs what it receives. - Settings:
cookie.days(1 to 400, default 30) andcookie.domaininconfig/clikgate.php.Secureis always on unlesscookie.keep_secureis false. The cookie name comes fromclick_id_param(elsecgid), never from the request. - The cookie is readable by the page on purpose (not
HttpOnly, and excluded fromEncryptCookies): the web script needs to read it. It only holds the click ID. - Visitor context for goals:
Clikgate::clickIds()->context($request)returnsclickId,keptBy,browserEngineandplatform, worked out in the SDK from the cookie and theUser-Agent(the User-Agent itself is never sent):Clikgate::goal('account_opened', ['reference' => $application->reference, ...Clikgate::clickIds()->context($request)]). Allowed in private mode. - Hashed email and phone for ad networks: when the business has turned on matching by hashed email or phone for a destination, add
\Clikgate\HashForAds::hash($email, $phone)to a goal's options (hashedEmail,hashedPhoneE164,hashedPhoneDigits; see theclikgate/clikgate-phpREADME). In private mode, hash on your own server: Clikgate never hashes for you there.
Identify your users
Full guide: https://clikgate.com/docs/identify-users. Path A (default): set CLIKGATE_IDENTITY_SECRET (Apps › your app › Identity secret) on the server only, and add one field to your sign-in and "current user" responses; the app passes it to the mobile SDK's identifyUser(). For several apps, CLIKGATE_IDENTITY_SECRETS is a JSON object of app IDs to secrets.
return response()->json(['user' => $user, 'clikgateIdentityToken' => Clikgate::createIdentityToken((string) $user->id)]); Clikgate::createIdentityToken((string) $user->id, ['appId' => 'app_…']); // several apps
Path B (no secret or token): the app sends getInstallationId() with its sign-in request, and you call Clikgate::identifyUser() after sign-in and at every signed-in app open (skip it when there's no installation ID):
if ($request->filled('installation_id')) { Clikgate::identifyUser(['appId' => 'app_…', 'installationId' => $request->string('installation_id')->toString(), 'customerId' => (string) $user->id]); }
Queued sending (recommended)
Set CLIKGATE_QUEUE=redis (any queue connection) and, optionally, CLIKGATE_QUEUE_NAME.
Clikgate::goal()then dispatches aClikgate\Laravel\Jobs\SendGoaljob, and the queue retries it on network errors, timeouts and HTTP 429, 500, 502, 503 and 504.- Each send uses a random
Idempotency-Key(reused across the HTTP retries inside one attempt), and the API ignores a second event with the same goal and reference, so a queue retry never counts twice. - Without a queue,
goal()usesCLIKGATE_SEND_MODE:sync(the default),after_responseorbackground.
Everything else
Clikgate::payments()->fromPaystack($verifyResponse)(andfromFlutterwave,fromMonnify,fromStripe,confirm([...])): confirm a payment right after your own verification with the gateway, never with data from the browser or the app (see the PHP SDK's Payments section).Clikgate::goal('order_paid', ['reference' => 'T123456', 'provider' => Provider::Paystack])reports a payment on a Payment goal; results carrystatus(GoalStatus:counted,waiting,received,refused). See the PHP SDK's Payment goals section.Clikgate::goals()->send(…),Clikgate::links(),Clikgate::clickIds()andClikgate::api().Clikgate::verifyWebhook($request->getContent(), $request->header('Clikgate-Signature'), $secret).app(\Clikgate\Clikgate::class)gives the client itself.
See clikgate/clikgate-php. The full example is in examples/routes/web.php.
Licence: MIT. Security: see SECURITY.md.