Build a Claude Chatbot with Gradio in Python

Use the Claude API with Gradio in Python 2026. Build a streaming chatbot, image analysis app, and multi-modal demo with gr.ChatInterface and gr.Blocks. Working code.

💥 50p impulse-buy: Power Prompts PDF (first 10 buyers) 30 battle-tested Claude Code prompts · 8-page PDF · paste into CLAUDE.md and never re-type a prompt again · 50p impulse-buy, no commitment

Gradio is the fastest way to build a shareable ML demo UI in Python. Combined with the Claude API, you can have a streaming chatbot or multi-modal app running in under 30 lines. This guide covers the minimal chatbot, streaming, image analysis, and deployment to Hugging Face Spaces.

Installation

pip install anthropic gradio

Minimal streaming chatbot

import anthropic
import gradio as gr

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from env

def chat(message: str, history: list[dict]) -> str:
    """Non-streaming version — simpler but less responsive."""
    messages = history + [{"role": "user", "content": message}]
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=messages,
    )
    return response.content[0].text

demo = gr.ChatInterface(fn=chat, type="messages", title="Claude Chatbot")
demo.launch()

Streaming version (token-by-token)

import anthropic
import gradio as gr
from typing import Generator

client = anthropic.Anthropic()

def chat_stream(message: str, history: list[dict]) -> Generator[str, None, None]:
    messages = history + [{"role": "user", "content": message}]
    full_response = ""
    with client.messages.stream(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=messages,
    ) as stream:
        for text in stream.text_stream:
            full_response += text
            yield full_response  # Gradio re-renders on each yield

demo = gr.ChatInterface(
    fn=chat_stream,
    type="messages",
    title="Claude Streaming Chatbot",
    description="Powered by Claude Sonnet 4.6",
)
demo.launch()

With system prompt and model selector

import anthropic
import gradio as gr

client = anthropic.Anthropic()

MODELS = [
    "claude-sonnet-4-6",
    "claude-haiku-4-5-20251001",
    "claude-opus-4-7",
]

def chat_stream(message, history, system_prompt, model):
    messages = history + [{"role": "user", "content": message}]
    full_response = ""
    with client.messages.stream(
        model=model,
        max_tokens=1024,
        system=system_prompt,
        messages=messages,
    ) as stream:
        for text in stream.text_stream:
            full_response += text
            yield full_response

with gr.Blocks(title="Claude Demo") as demo:
    gr.Markdown("## Claude API Demo")
    with gr.Row():
        model_dd = gr.Dropdown(MODELS, value="claude-sonnet-4-6", label="Model")
        system_box = gr.Textbox(
            value="You are a helpful assistant. Be concise.",
            label="System prompt",
            lines=2,
        )
    chatbot = gr.ChatInterface(
        fn=chat_stream,
        additional_inputs=[system_box, model_dd],
        type="messages",
    )

demo.launch()

Image analysis with Claude Vision

import anthropic
import gradio as gr
import base64
from PIL import Image
import io

client = anthropic.Anthropic()

def analyze_image(image: Image.Image, question: str) -> str:
    # Convert PIL image to base64 JPEG
    buffer = io.BytesIO()
    image.convert("RGB").save(buffer, format="JPEG")
    img_b64 = base64.standard_b64encode(buffer.getvalue()).decode("utf-8")

    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/jpeg",
                        "data": img_b64,
                    },
                },
                {"type": "text", "text": question or "Describe this image in detail."},
            ],
        }],
    )
    return response.content[0].text

demo = gr.Interface(
    fn=analyze_image,
    inputs=[
        gr.Image(type="pil", label="Upload image"),
        gr.Textbox(label="Question", placeholder="What's in this image?"),
    ],
    outputs=gr.Textbox(label="Claude's analysis", lines=8),
    title="Claude Vision Demo",
)
demo.launch()

Gradio vs Streamlit for Claude apps

AspectGradioStreamlit
Setup for chat1 function + gr.ChatInterface()Session state + st.chat_message() loop
Multi-modal inputsBuilt-in: Image, Audio, Video, FileRequires st.file_uploader + manual processing
StreamingGenerator function + yieldst.write_stream()
Free hostingHugging Face Spaces (always-on)Streamlit Community Cloud (always-on)
Custom stylingLimited (theme param)More flexible (st.markdown + CSS)
Best forML demos, image/audio/video apps, quick prototypesData dashboards, analysis tools, business apps

Deploy to Hugging Face Spaces (free)

# requirements.txt
anthropic
gradio

# app.py (your main file — HF Spaces auto-detects it)
# Set ANTHROPIC_API_KEY in Space Settings → Variables and secrets

# Local dev:
python app.py
# Opens at http://localhost:7860

# HF Spaces deploy:
# 1. Push to GitHub / HF repo
# 2. Create Space at huggingface.co/spaces → Gradio SDK
# 3. Add ANTHROPIC_API_KEY as a secret
# 4. Space auto-builds from requirements.txt

To estimate Claude API costs for your Gradio demo, use the Claude API Cost Calculator. For a Streamlit alternative, see the Claude API Streamlit guide. For production WebSocket-based streaming (bidirectional, cancel-capable), see the Claude API WebSocket guide.

Frequently asked questions

How do I use the Claude API with Gradio in Python?
Install anthropic and gradio. Create a chat function that takes message and history, calls client.messages.create(), and yields text chunks for streaming. Pass the function to gr.ChatInterface(). Gradio handles the UI, and Claude handles the generation.
How do I stream Claude responses in Gradio?
Use gr.ChatInterface with a generator function. Inside the function, call client.messages.stream() as a context manager, then yield accumulated text in a loop: for text in stream.text_stream: full_response += text; yield full_response. Gradio displays each yielded value as an incremental update.
What is the difference between Gradio and Streamlit for Claude apps?
Gradio is purpose-built for ML demos with built-in ChatInterface, image, audio, and video components — minimal code for a polished demo. Streamlit is more general-purpose (dashboards, data apps) and requires more wiring for chat history and streaming. Gradio deploys for free on Hugging Face Spaces; Streamlit deploys on Streamlit Community Cloud.
How do I add image analysis to a Gradio Claude app?
Use gr.Image(type='pil') or gr.Image(type='filepath') as an input. Convert the image to base64, then pass it as a content block: {'type': 'image', 'source': {'type': 'base64', 'media_type': 'image/jpeg', 'data': base64_data}}. Claude's vision API supports JPEG, PNG, GIF, and WebP.
How do I deploy a Gradio Claude app for free?
Push your app.py to a public GitHub/Hugging Face repo, create a new Space at huggingface.co/spaces (select Gradio SDK), and add ANTHROPIC_API_KEY as a secret in Space Settings → Repository secrets. The Space runs free with 2 CPU cores on Hugging Face's infrastructure.

Free tools

Cost Calculator → API Cookbook → Diff Summarizer → Skills Browser →

More examples

Claude API Python QuickstartClaude API Node.js / TypeScript QuickstartClaude API Streaming in PythonClaude API Streaming in Node.js / TypeScriptClaude API Tool Use in PythonClaude API Tool Use in Node.js / TypeScript