NestJS backend service that verifies Google Play Integrity tokens before mobile attribution SDKs fire install events. Closes the gap between attribution-reported installs and real Play Store installs.
Mobile attribution SDKs often over-count installs relative to Play Store actuals — especially on incentive-heavy ad networks. The gap signals fraud: SDK spoofing, emulators, rooted devices, click injection. Each fraudulent install inflates marketing-spend attribution and wastes budget.
Gate Adjust SDK install events with Google Play Integrity verdicts, reducing fraud volume and aligning Adjust install count closer to Play Store reality.
Two-step flow: client requests a server-signed HMAC nonce, requests Google for an integrity token bound to that nonce, then sends both back. Backend verifies HMAC server-side first (cheap) before calling Google.
Static secret in X-API-Key header. SHA-256 hashed both sides → crypto.timingSafeEqual (constant-time, resists timing attacks).
| Header | Example | Notes |
|---|---|---|
| X-Bundle-Id | com.iecgames.lbp | Should match server PLAY_INTEGRITY_PACKAGE_NAME |
| X-Platform | android / ios | Phase 1: Android only |
| X-Version-Name | 1.4.2 | Semantic app version |
| X-Version-Code | 142 | Android versionCode / iOS build number |
| X-Os-Version | Android 14 | Free-form |
| X-Device-Model | Pixel 8 Pro | Build.MODEL on Android |
| X-Device-Locale | vi-VN | BCP-47 locale tag |
jsonPayload.client.x-platform="android" AND jsonPayload.client.x-version-name="1.4.2"
| Component | Choice | Why |
|---|---|---|
| Framework | NestJS 10 + TypeScript | Team expertise, DI, Swagger auto-gen |
| Deployment | Cloud Run (us-central1) | SEA user base, ~150ms RTT savings vs us-central1 |
| Auth | Workload Identity + ADC | No secret rotation, no JSON key leak risk |
| Cache | Stateless HMAC (no Redis) | YAGNI — saves $80/mo + 1 IO hop |
| Logging | pino + Cloud Logging | JSON structured logs, native GCP integration |
| Static landing | @nestjs/serve-static | Internal docs at / (env toggle) |
Nonce re-use within 5-min TTL window is acceptable for fraud-gating — attacker still needs a valid one-shot integrity token from Google. Saves Memorystore + VPC connector overhead.
| Metric | Baseline | Target (30d) |
|---|---|---|
| Adjust vs Play Console gap | ~70% | ≤ 15% |
| /verify P99 latency | — | < 800ms |
| Legit pass rate | — | ≥ 95% |
| Fail-open events (BE down) | — | < 0.5% |
| MTG cost-per-install | inflated | reflects fraud removal |