GEMINI LABJP
FLASH35 — Gemini 3.5 Flash is now GA, built for sustained frontier performance on agentic and coding tasks (Jun)AGENTS — Managed Agents launch in public preview, running in Google-hosted isolated Linux sandboxes (Jun)SCHEMA — The Interactions API legacy schema is removed on June 8; migrate from outputs to steps now (Jun)SEARCH — Gemini 3.5 Flash rolls out globally across Search AI Mode and the Gemini app for everyone (Jun)FILESEARCH — File Search goes multimodal, embedding and searching images natively via gemini-embedding-2 (Jun)DEPRECATE — gemini-3.1-flash-image-preview and gemini-3-pro-image-preview shut down on June 25 (Jun)FLASH35 — Gemini 3.5 Flash is now GA, built for sustained frontier performance on agentic and coding tasks (Jun)AGENTS — Managed Agents launch in public preview, running in Google-hosted isolated Linux sandboxes (Jun)SCHEMA — The Interactions API legacy schema is removed on June 8; migrate from outputs to steps now (Jun)SEARCH — Gemini 3.5 Flash rolls out globally across Search AI Mode and the Gemini app for everyone (Jun)FILESEARCH — File Search goes multimodal, embedding and searching images natively via gemini-embedding-2 (Jun)DEPRECATE — gemini-3.1-flash-image-preview and gemini-3-pro-image-preview shut down on June 25 (Jun)
Articles/API / SDK
API / SDK/2026-06-04Advanced

Don't make Gemini judge your AdMob report — confine structured output to extraction

When deciding AdMob floors (eCPM thresholds), letting Gemini make the decision itself is dangerous. Confine structured output to 'extracting a messy report into typed data,' and keep the threshold judgment in deterministic code — here is the reasoning and implementation, with the actual decision rules from running 42 groups.

Gemini API203Structured Output7AdMob10App MonetizationDesign3

Premium Article

When automating the job of setting AdMob floors (eCPM thresholds) from a report, the first idea most people reach for is "hand the whole report to Gemini and have it answer the new floor for each group." I started down that path too, and stopped almost immediately. Letting an LLM do the threshold arithmetic and judgment makes that judgment unauditable. Setting a floor is an irreversible operation tied directly to revenue, and any mechanism where you cannot later reproduce "why this value" must not be put into operation.

I have run a solo app business since 2014 — 50 million cumulative downloads — and AdMob is a revenue source peaking around one million yen a month. Running that scale alone, alongside an art practice with 17 international awards, I review the floors of 42 mediation groups every month. What that experience tells me is that Gemini's structured output is strong not at "judging" but at "extracting." This article shows the design that confines structured output to the extraction step and separates the judgment into code, together with the actual decision rules.

Why you must not let the LLM do the judging

The floor decision rules themselves are, in fact, fully deterministic. The rules I use are these. On iOS, the floor is based on actual eCPM × 55%; if the ratio of current floor / eCPM exceeds 65%, lower it; if the ratio is under 40% and the match rate exceeds 95%, raise it; the middle (40–65%) holds. The minimum unit is $0.50. Android is a flat $0.50, not a ratio of actuals.

These rules complete with arithmetic and threshold comparisons alone. That is, there is no room for an LLM to "decide." And yet, passing the whole ruleset to an LLM via prompt produces three problems. First, output wavers at the threshold edges (e.g., when the ratio is exactly 65.0%). Second, even on the same input it may return subtly different values per run, breaking reproducibility. Third, and biggest: you cannot verify, from the output, the basis for a judgment like "hold because ratio is 64%." With code, anyone can trace the single line ratio = floor / ecpm; an LLM's internal reasoning cannot be traced.

A mis-set floor causes no-fill if too high (fill rate drops) and collapses eCPM if too low. In fact, I once had Android INT floors set excessively high relative to actuals, which capped the match rate in the low 70% range. To verify and fix this kind of "too strong / too weak" afterward, the judgment must be deterministic.

So what do you let Gemini do — only "extraction"

On the other hand, when you receive an AdMob report as CSV or pasted text, the data is astonishingly messy. Inconsistent group-name notation, currency symbols present or absent, a match rate written as "47.53%" one time and "0.4753" another, column order shifting with export settings. Tidying this messy input into uniformly typed rows is exactly where Gemini's structured output is overwhelmingly strong.

The trick here is to include no "decision result" whatsoever in the output schema. Define only the raw observations in the schema (group name, group ID, actual eCPM, match rate, current floor), and never put the new floor or a "raise/lower" judgment into it. You confine the LLM's responsibility to "messy input → typed observations."

import os
from google import genai
from pydantic import BaseModel
 
class GroupRow(BaseModel):
    group_name: str
    group_id: str
    ecpm_usd: float        # actual eCPM (observation only)
    match_rate: float      # normalized to 0.0-1.0
    current_floor_usd: float
 
class ExtractedReport(BaseModel):
    rows: list[GroupRow]
 
client = genai.Client(api_key=os.environ["YOUR_GEMINI_API_KEY"])
 
raw_report = open("admob_mediation_report.txt", encoding="utf-8").read()
 
resp = client.models.generate_content(
    model="gemini-2.5-pro",
    contents=(
        "Extract the following AdMob mediation report, normalized to one row per group. "
        "Convert match_rate to 0.0-1.0. Do NOT output any judgment or recommended value. "
        "Observations only.\n\n" + raw_report
    ),
    config={
        "response_mime_type": "application/json",
        "response_schema": ExtractedReport,
    },
)
 
report: ExtractedReport = resp.parsed

The key is stating in the prompt, too, "Do NOT output any judgment or recommended value." Bound by the schema and limited in natural language as well, Gemini works stably as an "extractor."

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Why and how to split: confine Gemini structured output to 'extraction' and keep threshold judgment in code
A deterministic implementation of the real 42-group floor decision rules (eCPM×55%, ratio thresholds)
How letting an LLM compute thresholds becomes unauditable, and the typed-schema design that avoids it
Secure payment via Stripe · Cancel anytime
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

API / SDK2026-05-27
Letting Gemini Flash Decide continue / pause / rollback for Staged Rollouts: An Indie Developer's Three-Signal Engine
How I built a Gemini Flash decision engine that reads Firebase Crashlytics, App Store / Google Play reviews, and AdMob revenue together, and outputs continue / pause / rollback for each staged rollout across six indie apps. Numbers from two months of production use included.
API / SDK2026-05-25
Automating App Localization QA with the Gemini API: A Structured-Output Pipeline That Catches Translation Drift Early
Lessons from running 14-language localization across a 50M-download personal app portfolio, distilled into a production-ready Gemini 2.5 Pro structured-output evaluation pipeline that catches translation drift before users do.
API / SDK2026-05-22
A Gemini API Control Plane for Indie Developers Running an App Portfolio
When you run several apps (wallpaper, healing, manifestation) on Gemini API, keys scatter and per-app cost attribution disappears. This is the three-layer control-plane architecture I have used for twelve months, with the traps that only show up over time.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →