All Articles
Trimming Gemini Embeddings from 3072 to 768 Dimensions: A Matryoshka Approach to Cutting Vector DB Cost and Latency
gemini-embedding-001 returns 3072-dimensional vectors, but thanks to Matryoshka representation you can keep only the leading dimensions with almost no quality loss. This is a design for trimming to 768 to cut vector DB storage and latency, including the re-normalization pitfall and coarse-to-fine search code.
Why Gemini API Throws 'Unsupported MIME type' and How to Fix It
The 'Unsupported MIME type' error from the Gemini API has three distinct causes: a misspelled MIME string, an octet-stream upload, and a genuinely unsupported format. Here is how to tell them apart with code that actually works.
Bulk Processing Without the 429s: Adaptive Concurrency for the Gemini API
Pushing tens of thousands of requests through the Gemini API with a fixed concurrency almost always produces 429s and dropped items. Here is an AIMD design that auto-tunes concurrency from the 429 feedback, with a bounded worker pool, a dead-letter queue, and resumable checkpoints.
Localizing App Store Keyword Fields with Gemini 2.5 Flash — A Month of Notes Across 40 Apps
Operational notes from a month of using Gemini 2.5 Flash to draft the 100-character App Store keyword field across 40 wallpaper apps and several locales — CJK character counting, deduping against the title, prohibited terms, per-locale quirks, and what actually moved the needle.
The Day You Switch Gemini Embedding Models: Designing a Zero-Downtime Reindex
Upgrade your embedding model and every vector you ever stored becomes incompatible. Here is a dual-index design for re-embedding hundreds of thousands of vectors without downtime, complete with a resumable reindex job and a query-side abstraction layer.
Preserving Gemini 3 Thought Signatures So Multi-Turn Function Calling Doesn't Degrade
When you build function calling on Gemini 3 thinking models, reasoning quality often drops from the second turn onward. The cause is usually a dropped thought signature. Here is how to keep it and verify the effect.
Why Gemini 2.5 Pro Rejects thinkingBudget: 0 (and How to Fix It)
Setting thinkingBudget to 0 on Gemini 2.5 Pro returns a 400 INVALID_ARGUMENT error. Here is why the per-model thinking budget ranges differ, how to minimize thinking on Pro the right way, and when to switch to Flash, with Python and JavaScript examples.
Two Months of Turning App Store Connect Daily Sales into a Slack Digest with Gemini 2.5 Flash
Notes from two months of running App Store Connect Sales/Trends data through Gemini 2.5 Flash and posting a short morning digest to Slack. Why Flash beat Pro for this job, how AdMob and store revenue stopped colliding, and what a single 'normal/check' label changed.
Propagating a Time Budget Through a Multi-Stage Gemini Pipeline
A field memo on killing DEADLINE_EXCEEDED errors in an in-app help search by carrying a single request-wide deadline through the embed, search, and generate stages — sizing maxOutputTokens from the remaining budget and reserving a fallback budget so a breach returns a partial answer instead of an error.
Designing a Semantic Clustering Pipeline for App Reviews with Gemini Embeddings
How I cluster 10,000+ app reviews from my indie apps using Gemini Embeddings to compute improvement priorities. The three-layer pipeline and cost design that emerged from a year of running it.
Treating a 0.5B Local LLM as a 'Front-Line Router' — Gemini Nano Next to Qwen 0.5B
Qwen2.5 0.5B reads as 'too weak for daily chat' when you give it the wrong task. As a mobile-app developer with 50M cumulative downloads behind me, I find it useful to put Gemini Nano next to Qwen 0.5B and think about the routing layer instead.
Why HTTP Referrer Restrictions on Your Gemini API Key Cause 403 Errors in Production
Walks through why a Gemini API key with HTTP referrer restrictions can suddenly return 403 PERMISSION_DENIED in production. Covers the exact referrer string format, SDK behavior differences, how to safely route around the limitation with a tiny edge proxy, and how it differs from the CORS error you hit when calling straight from the browser.