◉GEMINI LABJP
●API — Gemini 3.8 Flash TTS and Flash-Lite TTS are generally available (Sep 22). The Voices endpoint lets you query over 150 voices●10/22 — 16 days until the three Veo 3.1 models shut down. The place to move is gemini-omni-1.1-flash●TMP — An issue reports Gemini CLI creating temporary scripts in unexpected places. Where to put them is the real question●NEW — To prepare for the year-end price switch, I built a Gemini call ledger in Sheets and estimated the monthly cost●CLAUDE — Handing Claude Code's Japanese-text work to Gemini 3.8 is a pairing getting read on Zenn. The real question is which jobs to hand over and which to keep●2.5 — Skip the Gemini 2.5 family for new projects (Sep 18). The API still serves it, but access is limited to past users●API — Gemini 3.8 Flash TTS and Flash-Lite TTS are generally available (Sep 22). The Voices endpoint lets you query over 150 voices●10/22 — 16 days until the three Veo 3.1 models shut down. The place to move is gemini-omni-1.1-flash●TMP — An issue reports Gemini CLI creating temporary scripts in unexpected places. Where to put them is the real question●NEW — To prepare for the year-end price switch, I built a Gemini call ledger in Sheets and estimated the monthly cost●CLAUDE — Handing Claude Code's Japanese-text work to Gemini 3.8 is a pairing getting read on Zenn. The real question is which jobs to hand over and which to keep●2.5 — Skip the Gemini 2.5 family for new projects (Sep 18). The API still serves it, but access is limited to past users
Articles/API / SDK
◈ API / SDK/2026-08-22Intermediate

Once You Pass Twenty Mediation Groups, How Do You Find the Setting That Went Missing?

As ad mediation groups multiply, missing sources and type drift accumulate quietly. Here is the split I settled on: normalize the settings into one matrix, let code confirm the gaps, and send Gemini only the cells that need judgment.

gemini116gemini-api284admob5structured-output28indie-dev47

✦ Premium Article

When I extended mediation on the iOS side and added Liftoff, InMobi, and Unity Ads, the change covered four apps and more than twenty groups. I opened them one at a time in the console, checking that every network appeared in the same shape. Around the tenth group I lost track of where I had already been.

A week later I found that one group was missing a single network. Revenue for that group was slightly lower, but nothing that would register as an anomaly. Missing configuration tends to show up in exactly that quiet way.

So I rebuilt the check. The short version: finding the gaps is a job for code, and what Gemini receives is only the question of whether each gap is deliberate.

"Tell Me What Looks Wrong" Will Not Surface an Absence

My first attempt was the obvious one. I dumped all twenty-odd groups into text and asked Gemini to point out inconsistencies.

What came back were cells where the eCPM was clearly off by an order of magnitude, and group names that broke the naming convention. Both were correct observations. But the one thing I most wanted — a network missing from a single group — never appeared.

Once I thought about why, it made sense. An anomaly in something that exists leaves traces in the text. An absence exists only as nothing written in a particular place. To notice that row 19 lacks an element every other row has, you first collect the union of elements across all rows, then diff each row against it. That is set arithmetic, not reading comprehension.

Rather than push a language model into work it is poorly shaped for, I changed the shape of what I handed it.

Step One: Normalize the Settings Into a Single Matrix

A console export works, and so does hand-written JSON transcribed from screenshots. What matters is getting to a form you can pivot into a group-by-network matrix.

# groups: transcribed from the console. In production, read the export instead.
groups = [
    {"group": "RWD-iOS-Wallpaper-JP", "app": "wallpaper", "sources": [
        {"network": "admob_bidding", "type": "bidding"},
        {"network": "applovin",      "type": "bidding"},
        {"network": "liftoff",       "type": "bidding"},
        {"network": "inmobi",        "type": "bidding"},
        {"network": "unity",         "type": "waterfall", "ecpm": 4.2}]},
    {"group": "RWD-iOS-Wallpaper-US", "app": "wallpaper", "sources": [
        {"network": "admob_bidding", "type": "bidding"},
        {"network": "applovin",      "type": "bidding"},
        {"network": "liftoff",       "type": "bidding"},
        {"network": "unity",         "type": "waterfall", "ecpm": 4.2}]},
    {"group": "RWD-iOS-Ukiyoe-JP", "app": "ukiyoe", "sources": [
        {"network": "admob_bidding", "type": "bidding"},
        {"network": "applovin",      "type": "bidding"},
        {"network": "liftoff",       "type": "bidding"},
        {"network": "inmobi",        "type": "bidding"},
        {"network": "unity",         "type": "waterfall", "ecpm": 0.42}]},
    {"group": "RWD-iOS-Healing-JP", "app": "healing", "sources": [
        {"network": "admob_bidding", "type": "bidding"},
        {"network": "applovin",      "type": "waterfall", "ecpm": 3.9},
        {"network": "liftoff",       "type": "bidding"},
        {"network": "inmobi",        "type": "bidding"},
        {"network": "unity",         "type": "waterfall", "ecpm": 4.2}]},
]
 
 
def build_matrix(groups):
    """Build a group x network table.
    Unset cells become None, and those are the candidates for 'missing'."""
    networks = sorted({s["network"] for g in groups for s in g["sources"]})
    matrix = {}
    for g in groups:
        by_net = {s["network"]: s for s in g["sources"]}
        matrix[g["group"]] = {n: by_net.get(n) for n in networks}
    return networks, matrix
 
 
networks, matrix = build_matrix(groups)
for name, row in matrix.items():
    print(name, {n: (row[n]["type"] if row[n] else "-") for n in networks})

Running it locally gives you this:

RWD-iOS-Wallpaper-JP {'admob_bidding': 'bidding', 'applovin': 'bidding', 'inmobi': 'bidding', 'liftoff': 'bidding', 'unity': 'waterfall'}
RWD-iOS-Wallpaper-US {'admob_bidding': 'bidding', 'applovin': 'bidding', 'inmobi': '-', 'liftoff': 'bidding', 'unity': 'waterfall'}
RWD-iOS-Ukiyoe-JP    {'admob_bidding': 'bidding', 'applovin': 'bidding', 'inmobi': 'bidding', 'liftoff': 'bidding', 'unity': 'waterfall'}
RWD-iOS-Healing-JP   {'admob_bidding': 'bidding', 'applovin': 'waterfall', 'inmobi': 'bidding', 'liftoff': 'bidding', 'unity': 'waterfall'}

One dash. The thing I lost track of at group ten is now sitting in plain view. It is only a reshaping, but the nature of the check changes at this point.

✦

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
✦You will be able to split data that contains absences into the part code should settle and the part a language model should judge
✦You will catch a missing ad network during a few minutes of pre-flight checking instead of noticing it weeks later in the revenue numbers
✦You will be able to lift the responseSchema-to-report implementation straight into your own project
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
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 $15 for lifetime access
View Membership →

Related Articles

◈ API / SDK2026-08-23
Moving app AI work from runtime calls to a pre-ship batch pass
Where you put a Gemini call decides whether your request count scales with users or with assets. Here is the decision rule I used to move classification into a pre-ship batch pass, plus a resumable implementation.
◈ API / SDK2026-05-24
Two Weeks of Classifying Half a Year of App Store Reviews with Gemini File API
I ran half a year of App Store Connect reviews through the Gemini File API for two weeks straight, asking it to classify and summarize them. Here is what worked, where Batch Mode fit better, and which sharp edges took me a few days to round off.
◈ API / SDK2026-05-18
Building Automatic Wallpaper Category Classification with Gemini Vision
An indie developer shares how they implemented automatic wallpaper image classification with the Gemini Vision API — including accuracy results, real pitfalls, structured-output tips, and a cost comparison with GPT-4o Vision.
📚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