Call Us NowRequest a Quote
Back to Blog
Google Ads VBB
October 27, 2023
15 min read

Architecting a Data-Driven B2B Google Ads VBB Engine with Kotlin Multiplatform & Next.js 15 (2026)

Induji Technical Team

Induji Technical Team

Content Strategy

Architecting a Data-Driven B2B Google Ads VBB Engine with Kotlin Multiplatform & Next.js 15 (2026)

Key Takeaways

  • The Problem: Standard B2B Google Ads campaigns fail because low lead volume starves AI-driven bid strategies like Target CPA. The initial "lead" conversion is a poor indicator of actual revenue due to long sales cycles.
  • The Solution: Architect a system for Value-Based Bidding (VBB) by feeding deep-funnel data (deal stages, contract values) from your CRM/ERP back to Google Ads as offline conversions. This teaches the algorithm to bid for high-value prospects, not just any lead.
  • The Unified Stack: We propose a modern, type-safe, and performant stack. Next.js 15 serves as the high-speed front-end for lead capture and server-side event tracking. Kotlin Multiplatform acts as the robust backend core for processing business logic, calculating conversion values, and orchestrating API calls.
  • Core Components: The architecture relies on securely capturing the Google Click ID (GCLID) with Next.js Server Actions, storing it in a staging database (PostgreSQL), using a Kotlin service to enrich this data with CRM/ERP insights, and finally pushing it to the Google Ads API.
  • Strategic Shift: This architecture enables a fundamental shift from "Maximize Conversions" to "Maximize Conversion Value" or "Target ROAS (tROAS)", aligning ad spend directly with business revenue and customer lifetime value (LTV).

The Core Challenge: Why Standard Conversion Tracking Fails for High-Value B2B

For years, B2B marketers have been trying to fit a square peg into a round hole. We run sophisticated Google Ads campaigns targeting niche, high-value enterprise clients, yet we measure success with a metric designed for e-commerce: the cost per lead (CPL) or cost per acquisition (CPA). This model is fundamentally broken for B2B for three critical reasons:

1. The Data Lag & Value Disconnect

A B2B "conversion" is not a sale; it's the start of a conversation. The journey from a form submission to a signed contract can take months and involve multiple stakeholders. A lead from a small business inquiring about a basic service and a lead from a Fortune 500 company for a multi-year contract are tracked as identical "conversions" in Google Ads. This lack of value differentiation means Google's AI optimizes for the cheapest, easiest-to-acquire leads, which are often the lowest quality.

2. The Conversion Volume Problem

Google's Smart Bidding AI thrives on data. The official recommendation is at least 30-50 conversions per month for strategies like Target CPA to work effectively. Most high-ticket B2B campaigns generate far fewer leads, sometimes less than 15 a month. This data scarcity starves the algorithm, leaving it unable to find meaningful patterns and effectively optimize bids. The result is volatile performance and wasted ad spend.

3. Disconnected Data Silos

The most valuable data—deal stages, pipeline value, customer LTV, and final revenue—lives in your CRM (Salesforce, HubSpot) or ERP (ERPNext, SAP). Your ad platform data lives in Google Ads. These systems don't talk to each other out of the box. Without a bridge, Google's bidding algorithm is flying blind, completely unaware of which keywords, ads, and audiences are actually driving revenue.

To solve this, we must re-architect our data flow. We need to create a closed-loop system that feeds business outcomes back to the ad platform, enabling true Value-Based Bidding.

Blueprint for a Unified VBB Data Engine: The Kotlin + Next.js Stack

We propose a modern, resilient, and scalable architecture designed specifically to solve this problem. This blueprint leverages the performance of Next.js 15 on the edge and the robust, type-safe power of Kotlin on the JVM for core data processing.

A detailed architectural diagram showing the data flow from a user clicking a Google Ad, landing on a Next.js 15 page, submitting a form via Server Action, the data flowing to a Kotlin backend, which then queries a CRM/ERP and finally pushes a valued conversion to the Google Ads API.

This architecture consists of three primary layers:

The Front-End Layer: Next.js 15 for Performance and Data Capture

The front-end is the first and most critical point of data capture. Its role is to deliver a lightning-fast user experience to maximize Quality Score and reliably capture user and attribution data.

Key Responsibilities:

  • High-Performance Landing Pages: Using Next.js 15's Partial Prerendering (PPR), we can serve statically generated shells of our landing pages for near-instant load times, while dynamic content is streamed in. This is crucial for achieving high ad Quality Scores and reducing bounce rates.
  • Secure Data Ingestion: We leverage Next.js Server Actions to handle form submissions. This is a game-changer for security and reliability. The form data, including hidden fields containing the GCLID, is sent directly to a server-side function, bypassing the client-side JavaScript environment entirely. This prevents client-side manipulation and ensures the GCLID is captured reliably.
  • Server-Side Tagging (SST): To further enhance data integrity, we run a server-side Google Tag Manager (GTM) container. The Next.js application sends events to this server-side endpoint. This approach mitigates issues with ad blockers, ITP/ETP tracking preventions, and provides a single, controlled gateway for all marketing tags.

The Core Logic Layer: Kotlin Multiplatform for Unified Business Rules

This is the brain of the operation. The Kotlin service is responsible for ingesting raw lead data, enriching it with business value, and orchestrating its delivery to the Google Ads API.

Why Kotlin Multiplatform? While we are primarily using Kotlin/JVM for this backend service, architecting with Kotlin Multiplatform from the start provides future-proofing.

  • Type Safety & JVM Power: Kotlin's strong type system eliminates a whole class of data-related bugs. Running on the JVM gives us access to a mature ecosystem of libraries for database access (Exposed, jOOQ), API clients, and message queues, along with world-class performance and concurrency features (Coroutines).
  • Unified Business Models: The core data model for a "conversion event" or "customer value" can be defined once in a Kotlin Multiplatform common module. If you later decide to build an iOS/Android admin dashboard to monitor this pipeline, you can reuse the exact same data classes and validation logic.
  • Clean Separation of Concerns: The Kotlin service is completely decoupled from the front-end. It focuses solely on business logic: "What is this lead worth at this stage in our sales pipeline?"

The Data Persistence & Integration Layer

This layer connects our VBB engine to the rest of the business.

  • Staging Database (PostgreSQL): A simple but powerful PostgreSQL database acts as the intermediary. When a lead is submitted via the Next.js app, a record is created here containing the lead_id, gclid, submission_timestamp, and other initial data.
  • Event-Driven Integration (Kafka/RabbitMQ): For maximum scalability and decoupling, we use an event-driven approach. Your CRM/ERP should be configured to publish an event (e.g., deal.stage.changed) to a message queue like Kafka whenever a deal's status is updated. Our Kotlin service subscribes to this topic. This is far more efficient than constantly polling the CRM API for changes.
  • Direct API Connectors: For systems that don't support webhooks or messaging, the Kotlin service can run scheduled jobs (e.g., every hour) to poll the CRM/ERP API for updated deal information.

Implementing the End-to-End Data Flow for Offline Conversion Imports

Let's walk through the technical implementation steps to bring this architecture to life.

Step 1: Capturing the GCLID Reliably with Next.js

When a user clicks a Google Ad, they are redirected to your landing page with a gclid parameter in the URL. We must capture and store this.

In your Next.js 15 page component (app/page.tsx):

export default function LandingPage({ searchParams }: { searchParams: { gclid?: string } }) {
  const gclid = searchParams.gclid || '';

  return (
    <form action={submitLead}>
      <input type="hidden" name="gclid" value={gclid} />
      {/* Other form fields: name, email, etc. */}
      <button type="submit">Submit</button>
    </form>
  );
}

The Server Action (app/actions.ts):

'use server';
import { db } from './lib/db'; // Your database client

export async function submitLead(formData: FormData) {
  const leadData = {
    name: formData.get('name') as string,
    email: formData.get('email') as string,
    gclid: formData.get('gclid') as string,
  };

  if (leadData.gclid) {
    // 1. Send data to your CRM/ERP to create a new lead
    const crmResponse = await crm.createLead(leadData);

    // 2. Store the GCLID and lead ID in your staging database
    await db.query(
      'INSERT INTO gclid_mapping (lead_id, gclid, submission_time) VALUES ($1, $2, NOW())',
      [crmResponse.id, leadData.gclid]
    );
  }
  // ... handle redirect or success message
}

Step 2: The Kotlin Value Calculation Service

This service is triggered when a deal stage changes. It fetches the relevant data, calculates a value, and prepares a payload for Google.

Your Kotlin data class might look like this:

data class GoogleAdsConversionPayload(
    val gclid: String,
    val conversionActionId: String,
    val conversionDateTime: String, // ISO 8601 format
    val conversionValue: Double,
    val currencyCode: String = "USD"
)

The core logic function:

suspend fun processDealUpdate(dealId: String) {
    // 1. Fetch updated deal info from CRM
    val deal = crmApiClient.getDealById(dealId)

    // 2. Fetch GCLID from your staging DB using the lead/deal ID
    val gclid = gclidRepository.findGclidByDealId(dealId) ?: return // No GCLID, no upload

    // 3. Calculate the value based on business logic
    val value = when (deal.stage) {
        "Meeting Scheduled" -> 100.0 // A static value for an early-stage milestone
        "Proposal Sent" -> 500.0 // Higher value for a more committed stage
        "Closed Won" -> deal.annualContractValue * 0.75 // Use a fraction of ACV to represent LTV
        "Closed Lost" -> 0.0
        else -> 0.0
    }

    if (value > 0) {
        // 4. Prepare and send the payload
        val payload = GoogleAdsConversionPayload(
            gclid = gclid,
            conversionActionId = "YOUR_CONVERSION_ACTION_ID",
            conversionDateTime = ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
            conversionValue = value
        )
        googleAdsApiClient.uploadOfflineConversion(payload)
    }
}

A code snippet showing the Kotlin data class for GoogleAdsConversionPayload and the processDealUpdate function, highlighting the business logic in the when statement.

Step 3: Pushing Data to the Google Ads API

Using the Google Ads API client library for Java, the uploadOfflineConversion function would handle the authentication (OAuth2) and the construction of the UploadClickConversionsRequest. This is a gRPC call that sends the click conversion data securely to your Google Ads account.

Configuring Google Ads for Value-Based Bidding

The architecture is only half the battle. You must configure your Google Ads account correctly to leverage this new data stream.

  1. Create Offline Conversion Actions: In Google Ads, go to Goals > Conversions > Summary and create a new conversion action. Select "Import" and then "Other data sources or CRMs." Give it a name like "CRM: Deal Stage Update."
  2. Assign Value: Crucially, set this action to "Use different values for each conversion" and provide a default value (e.g., $1) which will be overridden by your API calls.
  3. Choose the Right Bid Strategy: Once you have a consistent flow of valued conversions (aim for at least 20-30 per month), you can switch your campaign's bid strategy from "Target CPA" to "Maximize Conversion Value". If you have a specific return you need to hit, you can use "Target ROAS (tROAS)".
  4. Manage Your Goals: Ensure this new offline conversion action is set as a "Primary" action for optimization, while your old "Website Lead" form submission action is demoted to "Secondary." This tells Google to optimize for the valuable offline events, not the initial, low-value form fills.

DevOps & Scalability Considerations

A production-grade system requires robust DevOps practices.

  • Containerization: Both the Next.js app and the Kotlin microservice should be containerized using Docker for consistent, portable deployments.
  • Orchestration: Deploy these containers on a managed Kubernetes service like AWS EKS or Google GKE. This provides auto-scaling, self-healing, and simplified management.
  • CI/CD Pipeline: Implement a full CI/CD pipeline (e.g., using GitHub Actions). When code is merged to the main branch, the pipeline should automatically build the Docker images, run unit and integration tests, push the images to a container registry (ECR/GCR), and deploy the new version to Kubernetes.
  • Monitoring & Alerting: Use a combination of Prometheus for metrics collection and Grafana for dashboarding. Set up alerts (e.g., via PagerDuty or Slack) for critical failures, such as a high rate of failed API calls to the Google Ads API or a stalled message queue consumer.
  • DPDP & Security: Ensure all data handling is compliant with regulations like the DPDP Act. Store API keys and database credentials securely using a secrets manager like AWS Secrets Manager or HashiCorp Vault. Enforce encryption in transit (TLS) and at rest.

A CI/CD pipeline diagram illustrating the parallel deployment paths for the Next.js front-end and the Kotlin backend service, from Git commit through build, test, containerize, and deploy to a Kubernetes cluster.

Frequently Asked Questions (FAQ)

Q1: How much historical conversion data do I need before switching to a tROAS strategy? A: Ideally, you should have at least 30 valued conversions within the last 30 days before making the switch. Start with "Maximize Conversion Value" first, as it's less restrictive. Run it for a month to establish a baseline ROAS, then switch to tROAS using that baseline as your initial target.

Q2: Can this architecture work with other ad platforms like Meta Ads? A: Absolutely. The core logic is platform-agnostic. The Kotlin service can be extended with a new module to format and send data to Meta's Conversions API (CAPI). The front-end would need to capture Meta's click identifier (fbclid) alongside the gclid. The fundamental principle of feeding offline value back to the platform remains the same.

Q3: What's the advantage of Kotlin Multiplatform if I'm only building a backend service? A: The primary immediate benefits are those of Kotlin/JVM: type safety, coroutines for efficient I/O, and the vast Java ecosystem. The "Multiplatform" aspect is strategic. It establishes a codebase where your core business logic (data models, validation) is defined in a platform-agnostic way. This makes future expansion—like building a native mobile app for your sales team to monitor lead quality—exponentially faster, as you can share the entire logic layer.

Q4: How do I handle currency conversion if my B2B clients are global? A: Your Kotlin value-calculation service should be designed to handle this. When fetching the deal from your CRM, it should also get the deal's currency. Before sending the payload to the Google Ads API, you can use a real-time currency conversion API (like Open Exchange Rates) to convert the deal value into the primary currency of your Google Ads account. This ensures all values sent to Google are normalized.


Unlock the True ROI of Your B2B Ad Spend

Moving beyond CPL is no longer a luxury; it's a necessity for B2B enterprises that want to achieve scalable and profitable growth through paid media. By architecting a closed-loop, data-driven engine, you transform Google Ads from a simple lead generation channel into a sophisticated revenue-driving machine that gets smarter with every deal you close.

This architecture is complex, requiring deep expertise across front-end development, backend engineering, cloud infrastructure, and marketing technology.

Ready to build a VBB engine that aligns your ad spend directly with revenue? Contact Induji Technologies today for a strategic consultation. Our expert engineers will design and implement a custom, end-to-end solution tailored to your unique business needs.

Related Articles

SEO vs. GEO | The Future of Search
Industry Trends
March 8, 2026
15 min read

SEO vs. GEO | The Future of Search

Discover why GEO (Generative Engine Optimization) is replacing traditional SEO. Learn how to rank for AI citations with Induji Technologies - Request a Quote today!

Induji Technical Team

Induji Technical Team

Ready to Transform Your Business?

Partner with Induji Technologies to leverage cutting-edge solutions tailored to your unique challenges. Let's build something extraordinary together.

Architecting a Data-Driven B2B Google Ads VBB Engine with Kotlin Multiplatform & Next.js 15 (2026) | Induji Technologies Blog