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/Dev Tools
Dev Tools/2026-05-24Advanced

Running Streamlit + Gemini as a Production BI Dashboard — Auth, Cost, Caching, Rate Limits, Observability

A design memo for promoting a Streamlit + Gemini data analysis app into a real multi-user internal BI dashboard — authentication, cost optimization, result caching, per-user rate limits, and observability, all from production experience.

Streamlit2Gemini API192Data Analysis3BIAuthenticationProduction32

Premium Article

I have been shipping personal apps since 2014, and as the indie developer behind 50 million cumulative downloads across a handful of mobile apps, I find myself reaching for Streamlit + Gemini more and more whenever I need a small internal dashboard — even though the "team" is just me. Watching AdMob revenue across six wallpaper apps, scanning App Store and Google Play reviews, eyeballing publishing throughput across two blogs (Lacrima and Mystery) — the first Streamlit version of that BI broke in roughly three weeks.

What broke: no login meant anyone with the URL could see the data; the Gemini bill quietly climbed past ¥4,000 a month on queries no one even read; the same CSV uploaded twice burned the API twice; and when something errored, I learned about it a week later. A Streamlit script you write for a personal experiment and a Streamlit BI you actually rely on share maybe 30–40% of the code. This article is the design memo for the rewritten side, based on the stack I actually run.

Why personal-experiment Streamlit and production BI are different beasts

Five layers that exist in the latter and not the former:

  1. Auth layer — who can access. A bare Streamlit app has none.
  2. Cost layer — something to break the linear relationship between user clicks and Gemini billing.
  3. Cache layer — never pay twice for the same question.
  4. Rate-limit layer — Gemini's project quota is one thing, per-user throttling is another.
  5. Observability layer — being able to ask later "who ran what, how many tokens did it burn, did we hit cache".

Personal experiments survive without any of the five. The moment a teammate or even a second device of yours starts hitting the URL daily, all five become non-negotiable.

The auth layer: streamlit-authenticator vs Auth0 vs Cloudflare Access

For the kind of indie BI I build, the team is 1–5 people. At that scale the realistic options collapse to three.

streamlit-authenticator (under 5 users, same-day deploy)

A Python package where you point a YAML file at hashed passwords and you get a login screen. This is what I started with. No additional infra, deployable to Streamlit Community Cloud in minutes.

# auth.py
import streamlit_authenticator as stauth
import yaml
from yaml.loader import SafeLoader
import streamlit as st
 
def get_authenticator():
    config = yaml.load(st.secrets["AUTH_CONFIG"], Loader=SafeLoader)
    return stauth.Authenticate(
        config["credentials"],
        config["cookie"]["name"],
        config["cookie"]["key"],
        config["cookie"]["expiry_days"],
    )
 
def login_gate():
    auth = get_authenticator()
    auth.login(location="main")
    if st.session_state.get("authentication_status") is not True:
        st.warning("Login required")
        st.stop()
    return st.session_state["username"]

Three gotchas you'll hit. First, expiry_days=30 gives long-lived cookie sessions with no real revocation; I keep mine at 7 and rotate hashes weekly via cron. Second, if that YAML ever lands in a public repo, you're done — keep it in Streamlit Secrets or an external KV. Third, the package does not provide MFA, so it's a poor fit for sensitive data.

Auth0 (10–30 users, MFA required)

When the headcount climbs and you need to revoke access cleanly, Auth0 is the next step up. The free tier covers 25,000 MAU, so an indie BI runs at zero cost. About 30 lines with Authlib:

# auth_oidc.py
from authlib.integrations.requests_client import OAuth2Session
import streamlit as st
 
AUTH0_DOMAIN = st.secrets["AUTH0_DOMAIN"]
CLIENT_ID = st.secrets["AUTH0_CLIENT_ID"]
CLIENT_SECRET = st.secrets["AUTH0_CLIENT_SECRET"]
REDIRECT_URI = st.secrets["AUTH0_REDIRECT_URI"]
 
def login_gate():
    if "user" in st.session_state:
        return st.session_state["user"]
 
    code = st.query_params.get("code")
    if code is None:
        sess = OAuth2Session(CLIENT_ID, CLIENT_SECRET, redirect_uri=REDIRECT_URI)
        url, _ = sess.create_authorization_url(
            f"https://{AUTH0_DOMAIN}/authorize", scope="openid profile email"
        )
        st.markdown(f"[Sign in]({url})")
        st.stop()
 
    sess = OAuth2Session(CLIENT_ID, CLIENT_SECRET, redirect_uri=REDIRECT_URI)
    token = sess.fetch_token(f"https://{AUTH0_DOMAIN}/oauth/token", code=code)
    user = sess.get(f"https://{AUTH0_DOMAIN}/userinfo").json()
    st.session_state["user"] = user
    st.query_params.clear()
    return user

If you go this route, always set up a Rule to restrict allowed email domains. Forget it and Auth0 will happily accept open signups from anywhere.

Cloudflare Access (my current default for indie BI)

The pattern I have settled on. Cloudflare Access does authentication at the edge, so the Streamlit code stays almost auth-free. You publish Streamlit via Cloud Run or a Cloudflare Tunnel, register the host as a Zero Trust Application, and Cloudflare authenticates with Google one-time PIN or GitHub before any request reaches your origin.

Three reasons I prefer it. First, auth lives outside Streamlit, so Streamlit upgrades cannot break login. Second, the free tier covers 50 users — generously beyond indie scale. Third, every request carries a Cf-Access-Authenticated-User-Email header, which makes user identification trivial.

# auth_cf.py
import streamlit as st
 
def login_gate():
    headers = st.context.headers if hasattr(st, "context") else {}
    email = headers.get("Cf-Access-Authenticated-User-Email")
    if not email:
        st.error("Missing auth header — access via Cloudflare Access")
        st.stop()
    return email

I recommend streamlit-authenticator for under-5-person internal BI, Cloudflare Access for everything else. Auth0 fits when you must onboard external collaborators with IdPs beyond Google/GitHub.

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
Five layers that change between a personal experiment and a real internal BI — each with concrete code you can lift into your own app
Token pricing and cache hit rates measured on a working Gemini 2.5 Flash vs 2.5 Pro vs 3.x Pro stack, in JPY/USD
When to pick streamlit-authenticator vs Auth0 vs Cloudflare Access, with team-size thresholds and concrete gotchas
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

Dev Tools2026-07-09
Closing the Failures That Never Throw: Normalizing Gemini API Responses into a Discriminated Union
An HTTP 200 with an empty body will never reach your catch block. Here is how I normalize finishReason and blockReason into a discriminated union, and let a never check turn missed cases into compile errors.
Dev Tools2026-05-03
Build a CSV Insight App with Gemini API and Streamlit — A Production-Ready Dashboard with Auto-Insights and Visualization
A production-grade implementation guide for a Streamlit + Gemini API data analysis app. Upload a CSV, get auto-insights and visualizations in seconds. Covers schema inference, structured output, and real-world rate-limit handling.
Dev Tools2026-03-30
Firebase Genkit × Gemini API in Production — Field Notes from an Indie Developer Running 50M-Download Apps
Production field notes from running Firebase Genkit and Gemini API on the back end of indie wallpaper and mindfulness apps that cumulatively passed 50M downloads. Covers Flow and Tool design, RAG, deployment, real cost and latency numbers, plus seven undocumented gotchas you only find after a month 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 →