GEMINI LABJP
NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20
Articles/API / SDK
API / SDK/2026-03-23Advanced

Running a Gemini + LINE Bot in Production — Reply Token Expiry, Duplicate Replies, and Cold-Start Latency

The first walls you hit putting Gemini behind a LINE Bot are the 30-second reply-token expiry, duplicate replies from webhook redelivery, and Cloud Run cold starts. This guide solves them with loading animations, push-message fallback, idempotency, and Firestore-backed history — with working code and measured numbers.

gemini102gemini-api277line-botpython104cloud-run6production140

Premium Article

As an indie developer at Dolice, I put Gemini behind a LINE Bot and everything worked perfectly through ngrok on my machine. The morning after I shipped it to Cloud Run, the reports started: "it replies twice" and "sometimes it just goes silent."

Neither was a bug in my code. The LINE Messaging API, a generative model that takes a few seconds, and serverless cold starts simply weren't aligned on the same clock.

This is the record of how I re-aligned them — with working code and the numbers I measured. It still works as a tutorial you can follow from first setup, but most of the space goes to the traps that only show up in production.

If the Gemini API itself is new to you, the Gemini API Quickstart is a gentler starting point.


Get a Minimal Version Running First

Before the traps, let's stand up the smallest version that works. Without this foundation, the later discussion has nothing to stand on.

What You'll Need

  • Python 3.11+
  • A Google AI Studio API key (free at Google AI Studio)
  • A LINE Developers account (free at LINE Developers)
  • ngrok (HTTPS tunnel for local testing) or Google Cloud Run (production)

Creating a LINE Channel

  1. Sign in to the LINE Developers Console
  2. Create a Provider (e.g., My AI Bot)
  3. Create a Messaging API channel
  4. From the channel settings, note two values:
    • Channel secret (Basic settings tab)
    • Channel access token (Messaging API tab → "Issue")
  5. You'll set the Webhook URL later

Installing Packages

mkdir gemini-line-bot && cd gemini-line-bot
python -m venv venv
source venv/bin/activate
pip install google-genai flask line-bot-sdk gunicorn google-cloud-firestore

Keep secrets in a .env file.

# .env
GEMINI_API_KEY=your_gemini_api_key_here
LINE_CHANNEL_SECRET=your_channel_secret_here
LINE_CHANNEL_ACCESS_TOKEN=your_channel_access_token_here

Smoke Test

Confirm Gemini works on its own first.

# test_gemini.py
from google import genai
 
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
response = client.models.generate_content(
    model="gemini-3-flash",
    contents="Hello! Please introduce yourself briefly.",
)
print(response.text)

For a chatbot backend I recommend gemini-3-flash — the balance of speed and price is hard to beat. I switch to gemini-3-pro only for the moments that genuinely need deeper reasoning, which keeps both cost and latency reasonable.


Why a Naive reply_message Breaks in Production

Most samples call Gemini the moment the webhook arrives and return the text via reply_message. Locally, this is fine.

In production, two properties of the LINE reply token start to bite.

First, the reply token expires roughly 30 seconds after it's issued. Second, each reply token can only be used once.

Gemini Flash is fast, but a longer prompt or a busy moment can take several seconds. Stack a Cloud Run cold start on top and you occasionally creep toward that 30-second edge. Reply to an expired token and LINE returns 400 Invalid reply token — the user just gets silence.

Redelivery makes it worse. If your webhook doesn't return 200 quickly enough, LINE resends the same event. Call Gemini and reply on every resend, and the user receives the same answer two or three times. That was the "it replies twice" I hit on day one.

The rest of this guide takes both problems — token expiry and redelivery — head on.


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
A concrete way to work around the ~30-second, single-use reply token using a loading animation plus push-message fallback
How to stop duplicate replies caused by webhook redelivery by making each event idempotent with its event ID
Measured ~4s cold-start penalty on Cloud Run with min-instances 0, and why conversation history belongs in Firestore
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 $10 for lifetime access
View Membership →

Related Articles

API / SDK2026-07-15
Sample what you already accepted — an audit budget that catches silent quality drift
A confidence gate only ever looks at output the model hesitated on. Silent drift sinks into the batch that sailed through. Working from a fixed 30-minutes-a-day review budget, this walks through deriving detection time from the binomial, reallocating the same budget across risk strata, and catching slow decay with a cumulative monitor.
API / SDK2026-07-14
When Gemini's executed result and its prose disagree on a number — a gate that trusts only code_execution_result
Gemini Code Execution returns the value it actually computed and the sentence describing it as separate parts. Trust the prose and you can inherit a hallucinated number. Here is a verification gate, in working code, that extracts the executed result as the single source of truth and rejects prose that disagrees.
API / SDK2026-07-13
When responseSchema Can't Do $ref: Handling Recursive Schemas in Production with responseJsonSchema
Gemini's responseSchema is an OpenAPI subset with no $ref or $defs, so it can't express shared definitions or recursion. Here's how I moved to responseJsonSchema to reuse localized fields and handle a recursive category tree in production.
📚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 →