Auction-as-a-Service: Using AdQuery to Run Ads Against Your Own Candidate Sets

Overview

Auction-as-a-Service is a pattern for using Kevel's Decision API where you determine which products or listings are eligible to be shown, and Kevel runs the auction, pacing, budgeting, frequency capping, and tracking against that set. It's powered by a feature called AdQuery — a set of filter operators you include in your ad decision requests that let you query ads by custom properties defined on their creative templates.

This approach is particularly valuable for sponsored listings in e-commerce and marketplace environments, where you already have a search engine, recommendation system, or inventory service that knows which products are relevant to a given user and context.

When combined with Kevel Catalog, Auction-as-a-Service becomes especially powerful. Catalog synchronizes your product inventory with Kevel's platform, automatically creating and updating ads from your product feed. This means product data — SKUs, prices, images, availability — stays in sync without manual ad ops work, and AdQuery at request time filters the auction down to only the products your search engine considers relevant.

Why Use Auction-as-a-Service?

The problem with traditional ad targeting for sponsored listings

Standard ad servers use key-value targeting: an ad is configured to target a keyword like "2021 Honda Accord", and when a request contains that keyword, the ad is eligible. This works for display advertising but breaks down for sponsored listings because:

  1. Search permutations are effectively infinite. You can't pre-configure every possible search term, misspelling, or filter combination as a targeting rule. Attempting to do so bloats ad configuration and slows down response times.

  2. Duplicating search logic is fragile. If both your search engine and your ad server independently decide which products to show, they will inevitably disagree. The result is irrelevant sponsored listings or wasted impressions.

  3. Dynamic inventory creates operational overhead. Products go in and out of stock, promotions launch and expire, and prices change. Managing campaign state in lockstep with your catalog is expensive and error-prone.

How Auction-as-a-Service solves this

Instead of asking Kevel to replicate your product selection logic, you separate the concerns:

Your system handlesKevel handles
Search relevance and rankingProduct catalog sync and ad creation (Kevel Catalog)
User personalizationAuction mechanics (who wins a placement)
Category and attribute filteringPrioritization rules and flight weighting
PaginationPacing and budget management
Frequency capping
Inventory availability (via Catalog sync)
Impression, click, and conversion tracking

The workflow is:

  1. Catalog sync (ongoing): Your product feed is synced to Kevel Catalog, which keeps product data — SKUs, prices, images, availability — up to date. When products go in or out of stock, Catalog reflects that automatically. Ads are created from products through Catalog, so the AdQuery-enabled product ID field is populated automatically.
  2. At request time: A user performs a search or browses a page on your platform.
  3. Your search/recommendation engine returns a set of eligible product IDs (e.g., SKUs).
  4. You pass those IDs to Kevel's Decision API via AdQuery.
  5. Kevel filters the ad candidate set down to only ads matching those IDs, then runs its full auction logic — priority, bids, pacing, budgets, frequency caps, and so on.
  6. Kevel returns the winning ad(s) along with impression and click tracking URLs.

Key benefits

  • Dramatically faster launch. No need to recreate your search logic inside Kevel. Sync your product feed via Kevel Catalog to automatically create ads with the right product identifiers, then pass eligible IDs at request time via AdQuery.
  • Faster ad response times. Instead of evaluating millions of candidates, Kevel evaluates only the relevant subset — reducing latency by up to 80%.
  • Guaranteed relevance. Sponsored listings are always a subset of your organic results, so users never see promoted products that don't belong.
  • Automatic inventory management. Kevel Catalog keeps product data in sync with your feed — when products go out of stock, their availability is reflected automatically. No manual campaign pausing required.
  • No duplicate data entry. With the Create Ads from Products flow, ad ops don't need to manually copy product information into ad creatives. Catalog maps product attributes directly to creative template fields.
  • Supports pagination. Pass only the product IDs for the current page. Each page can show unique ads without repetition.

How to Set Up Auction-as-a-Service

Step 1: Create a custom creative template

Ads in Kevel are created against creative templates — these define the fields (properties) each ad can have. To use AdQuery, you need at least one template property that is marked as queryable.

  1. In Studio (or via the Management API), create or edit a template.
  2. Add a field for the product identifier your system uses. This could be:
    • A string field (e.g., sku) for alphanumeric product codes
    • A number field (e.g., productId) for integer-based IDs
  3. Check the "AdQuery" option on the field. This tells Kevel to index that property so it can be filtered at request time.
  4. In most cases, mark the field as required so every ad using this template has an identifier.
  5. Publish the template.

You can add additional AdQuery-enabled fields beyond just the product ID — for example, price, category, or brand — to support richer filtering at request time.

Step 2: Sync your product feed and create ads via Kevel Catalog

The recommended approach for managing product ads at scale is Kevel Catalog. Catalog syncs your product inventory with Kevel, maps product attributes to creative template fields, and lets you create ads directly from products — so AdQuery-enabled fields like ctProductId are populated automatically and stay up to date as your inventory changes.

You can also create ads manually or via the Management API for smaller inventories, but Catalog is the path that scales.

Step 3: Make Decision API requests with AdQuery

When a user performs a search or browses your platform, your backend:

  1. Calls your own search/recommendation engine to get the list of eligible product IDs.
  2. Pass those IDs to Kevel's Decision API inside the adQuery field of the placement.

Here's an example request:

{
  "placements": [
    {
      "divName": "sponsored-results",
      "networkId": 12345,
      "siteId": 67890,
      "adTypes": [10],
      "adQuery": {
        "ctSku": {
          "in": ["sku4001a", "sku4003b", "sku500a", "sku12245"]
        }
      },
      "count": 4
    }
  ]
}

In this example:

  • ctSku is the name of the AdQuery-enabled field on your creative template (prefixed with ct by convention).
  • The in operator tells Kevel: "only consider ads whose ctSku value matches one of these".
  • count: 4 means "return up to 4 winning ads".

Kevel will look at the full set of active ads, filter down to only those with matching SKUs, then run its auction. The response includes the winning ads and their tracking URLs.

You can safely include IDs that don't exist as ads in Kevel. The engine will simply ignore them and return only ads that match.

The in Operator: Filtering by Product IDs

The core of Auction-as-a-Service is the in operator. It tells Kevel: "only consider ads whose property value matches one of the values in this list." This is how you pass eligible product IDs from your search engine to Kevel's auction.

"adQuery": {
  "ctSku": {
    "in": ["sku-001", "sku-002", "sku-003", "sku-004"]
  }
}

An ad is eligible if its ctSku value matches any of the provided values (OR logic within the list).

If you include multiple AdQuery variables in a single request, they are AND'd together — an ad must match all of them:

"adQuery": {
  "ctSku": {
    "in": ["sku-001", "sku-002", "sku-003"]
  },
  "ctCategory": {
    "eq": "electronics"
  }
}

Here an ad must have a matching SKU and be in the "electronics" category.

AdQuery supports additional operators beyond in — including eq (exact match), not (negation), min/max (numeric ranges), nullValuesMatch, and phraseMatch (fuzzy text search). For the full operator reference, see the AdQuery documentation.

Influencing Results with Relevancy Scores

Once you have a set of eligible ads via AdQuery, you can further influence which ad wins the auction by using relevancy scores.

Relevancy scores let you bias the auction in favor of ads that your system considers more relevant, higher quality, or better performing — even if they have a lower bid. This is particularly useful for self-serve advertising platforms where bidders compete in an auction but you want to balance revenue with user experience.

Practical Example: Sponsored Listings Flow

Here's a complete end-to-end example:

Scenario: An e-commerce marketplace with 100,000 products. Advertisers can sponsor their products to appear at the top of search results.

Setup (one-time):

  1. Create a template with an AdQuery-enabled ctProductId field (number).
  2. Create a Catalog and sync your product feed.
  3. Create ads from products — Catalog automatically populates ctProductId from your product data and keeps it in sync as your inventory changes.

At request time:

  1. User searches for "wireless headphones".
  2. Your search engine returns 200 matching products: [101, 205, 312, 419, ...].
  3. Your backend sends a Decision API request:
{
  "placements": [
    {
      "divName": "sponsored-slot-1",
      "networkId": 12345,
      "siteId": 67890,
      "adTypes": [10],
      "adQuery": {
        "ctProductId": {
          "in": [101, 205, 312, 419, 502, 610, 718, 825, 933, 1047]
        }
      },
      "count": 2
    }
  ]
}
  1. Kevel checks: of those 10 product IDs, suppose products 205, 419, and 825 have active sponsored ads. Kevel runs the auction among those 3, applying priority rules, bid amounts, budgets, pacing, and frequency caps.
  2. The response returns the 2 winning ads (say products 419 and 205) with impression and click tracking URLs.
  3. Your frontend renders those products with a "Sponsored" label and fires the impression URLs.

Important Notes

  • Other flight configurations still apply. AdQuery narrows the candidate set, but ads must still satisfy other active targeting rules on the flight (e.g., keyword targeting, geo-targeting, dayparting) unless you explicitly use skipFilters to bypass them.
  • IDs don't need to exist in Kevel. You can pass product IDs that have no corresponding ad — Kevel simply ignores them. This means you don't need to filter your candidate list before sending it.
  • AdQuery is placement-scoped. Each placement in a multi-placement request can have its own independent adQuery and skipFilters.