Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Admob Ssv Laravel Package

casperlaitw/laravel-admob-ssv

Laravel AdMob SSV adds server-side verification for Google AdMob rewarded ad callbacks. It validates SSV signatures and callback parameters so you can securely confirm ad views and award user rewards. Includes simple configuration, key management, and robust validation for production reward flows.

View on GitHub
Deep Wiki
Context7

Getting Started

This package handles Google AdMob Server-Side Verification (SSV) callbacks: AdMob calls a URL on your app after a user earns a reward, and the package verifies Google's signature before letting you act on it. v1.5.0 is a compatibility-only release (adds Laravel 12 and 13 support), so the day-to-day workflow is unchanged — it just means you can now composer update this package on modern Laravel skeletons.

  1. Install and publish config:
    composer require casperlai/laravel-admob-ssv
    php artisan vendor:publish --tag=admob-ssv-config
    
  2. Open config/admob-ssv.php first — this is where the callback route, middleware group, and any key/URL settings live. Decide whether the package registers its own route or whether you point it at a route you own.
  3. Grab the resulting URL (/admob-ssv/callback by default) and paste it into AdMob → Ad unit → Server-side verification (or the account-level SSV URL) in the AdMob console.
  4. First use case: listen for the package's verification event and credit the reward to your user. Register a listener in EventServiceProvider (or use Event::listen), and inside it read custom_data to identify the user, reward_amount/reward_item to know what to grant, and transaction_id as the idempotency key.

If you just need the signature check, you're done at step 3 — the package rejects bad signatures for you.

Implementation Patterns

Event-listener as the integration point. The idiomatic pattern is: package verifies → package dispatches event → your listener does domain work. Keep the listener thin and push the actual grant into a queued job or an action class so a slow DB doesn't time out Google's callback (Google expects a fast 200).

Event::listen(AdMobSsvVerified::class, function ($event) {
    RewardGrant::dispatch($event->transactionId, $event->customData, $event->rewardAmount);
});

Identify the user via custom_data, not user_id. user_id is whatever you set in the AdMob SDK and can be absent or spoofable-looking; custom_data is the field you control per-request. Common pattern: put an opaque, signed token (or the user's ULID + a HMAC) in custom_data from the app, then look the user up server-side. Never trust a bare user ID from the query string to authorise a grant.

Idempotency is mandatory. AdMob retries callbacks. Wrap the grant in a unique index on transaction_id (or a reward_transactions table with firstOrCreate) so a retry doesn't double-credit. This is the single most important pattern with this package — the signature check proves authenticity, not uniqueness.

Environment-parity config. Keep the SSV URL per environment: a staging app in AdMob pointing at staging.example.com and production pointing at example.com. Because the URL lives in the AdMob console (not your repo), document it in your README so nobody's surprised when staging callbacks land in prod after a config copy.

Testing locally. Expose your dev server (ngrok http 80, valet share, or expose) and temporarily point a test ad unit's SSV URL at the tunnel. Note you can't easily forge a valid signature — so for unit tests, either fake the event (Event::fake()) or bypass verification in a test-only config flag rather than trying to mint Google signatures.

Multi-app / multi-ad-unit setups. If you run several apps through one Laravel install, use the ad_unit (and ad_network) fields in the payload to route to the right reward table or tenant. Combine with a rewarded_videos/reward_ledger table keyed by (ad_unit, transaction_id).

Pair with your own audit log. Persist the raw callback payload (minus signature) alongside the grant. When a user claims "I watched the ad and got nothing," this table is your only evidence, since you can't query AdMob for individual SSV callbacks.

Gotchas and Tips

  • Signature covers the raw query string. If you put a middleware in front of the callback route that re-encodes or reorders query parameters, verification breaks. Leave the route's middleware group as bare as possible (no TrimStrings/ConvertEmptyStringsToNull weirdness on that route) and don't add request-mutating middleware.
  • The callback must be public HTTPS — no auth middleware, no CSRF, and Google won't follow redirects to a login page. If you see 302s in your access log instead of 200s, this is why.
  • Google's verifier keys are fetched from gstatic.com. In locked-down networks (or CI), outbound HTTPS to www.gstatic.com must be allowed, and the package may cache keys — clear cache if you ever see valid callbacks rejected after a key rotation.
  • Replay protection is on you. Signatures are valid indefinitely. Use the timestamp field plus your transaction_id uniqueness constraint to reject stale replays; don't rely on the package to do it.
  • Respond fast, then work. Do the minimum synchronously (lookup + idempotent insert) and push the rest to a queue. Google treats non-2xx as a failure and retries, which amplifies any bug into duplicate grants if you're not idempotent.
  • custom_data has length limits and URL-encoding quirks. Keep it short and URL-safe; long JSON blobs may be truncated or mangled. If you need richer payloads, store the context server-side keyed by a short token.
  • Don't log the signature naively — not a secret per se, but there's no value in it, and full-URL logging tends to leak custom_data tokens into logs. Redact.
  • Upgrading to v1.5.0: purely additive Laravel 12/13 constraint support alongside the existing 10/11 support. No config or API changes, so this is a safe minor bump — but check your composer.json laravel/framework constraint resolves and re-run the SSV test flow once, since Laravel 13 may change how route middleware groups are resolved.
  • Extension point: if the built-in signature validation doesn't fit (e.g. you need to fan out to multiple reward backends or add custom logging on failure), the cleanest hook is to disable the package route and implement a thin controller that still uses the package's verifier, so you keep its battle-tested signature logic without fighting the default wiring.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox