Gradio is an open-source Python library for building and sharing web apps for machine learning models, APIs, or any Python function — no JavaScript, CSS, or web-hosting experience required. You write a Python function, wrap it in a Gradio component layout, and call .launch(); Gradio renders a complete web UI, runs a server, and (optionally) creates a public share link in seconds.
This guide covers everything you need to build, customize, run, and share Gradio apps with the gradio Python package (version 6.x). It is organized by what you want to do — start with the Quick Start, then jump to the task that matches your goal.
Note
Gradio ships three high-level building blocks:
gr.Interface(the fastest way to wrap a single function),gr.Blocks(full control over layout and data flow), andgr.ChatInterface(purpose-built for chatbots). All three are entirely Python.
1. Quick Start
1.1 Your first app
Create a file named app.py:
import gradio as gr
def greet(name, intensity):
return "Hello, " + name + "!" * int(intensity)
demo = gr.Interface(
fn=greet,
inputs=["text", "slider"],
outputs=["text"],
)
demo.launch()
Run it:
python app.py
Expected output:
* Running on local URL: http://127.0.0.1:7860
To create a public link, set `share=True` in `launch()`.
Open http://127.0.0.1:7860 in your browser. Type a name, drag the slider, and click Submit — your greeting appears on the right.
Tip
By convention, Gradio is imported as
gr(import gradio as gr) for readability. Every example in this guide follows that convention.
1.2 The three core arguments of gr.Interface
| Argument | Meaning |
|---|---|
fn |
The Python function to wrap a UI around. Can be any callable — a model's predict, a generator, an async function. |
inputs |
One component (or list) for the function's argument(s). The number of inputs must match the number of fn parameters. |
outputs |
One component (or list) for the function's return value(s). The number of outputs must match the number of return values. |
You can pass components either as string shortcuts ("text", "slider", "image") or as instantiated objects (gr.Textbox(), gr.Slider(), gr.Image()). Use the object form when you need to configure the component (labels, ranges, defaults).
demo = gr.Interface(
fn=greet,
inputs=[gr.Textbox(label="Your name"), gr.Slider(1, 10, value=3, label="Intensity")],
outputs=[gr.Textbox(label="Greeting")],
)
1.3 Share it with the world
Set share=True to get a temporary public URL (valid ~72 hours), tunneled from your machine — no deployment needed:
demo.launch(share=True)
* Running on local URL: http://127.0.0.1:7860
* Running on public URL: https://a23dsf231adb.gradio.live
This share link expires in 72 hours.
Important
With a share link, the UI is publicly reachable but all computation still runs on your machine. Do not share links to apps that expose sensitive data or that you have not secured with authentication.
2. Installation
Prerequisite: Gradio requires Python 3.10 or higher (3.10–3.13 are supported).
pip (recommended)
pip install --upgrade gradio
With OAuth support
pip install --upgrade "gradio[oauth]"
With MCP server support
pip install --upgrade "gradio[mcp]"
uv
uv add gradio
Verify the install:
python -c "import gradio; print(gradio.__version__)"
6.17.0
Tip
Always install Gradio inside a virtual environment to avoid dependency conflicts:
python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install gradio
The base install pulls in FastAPI, Starlette, Uvicorn, Pydantic, huggingface_hub, gradio_client, pandas, numpy, and pillow. The [oauth] and [mcp] extras add the dependencies needed for sign-in and MCP-server features respectively.
3. Choosing Your Building Block
Gradio gives you three ways to build, in increasing order of control:
| Building block | Use when you want to… | Lines of code |
|---|---|---|
gr.Interface |
Wrap a single function with fixed inputs → outputs (the classic "demo a model" case) | Fewest |
gr.ChatInterface |
Build a chatbot UI around a message-handling function | Few |
gr.Blocks |
Design custom layouts, multiple interacting functions, dynamic UIs, dashboards | Most flexible |
Note
gr.Interfaceandgr.ChatInterfaceare both built on top ofgr.Blocks. Anything you can do with them, you can also do (more verbosely) with Blocks. Start high-level and drop to Blocks only when you need the control.
4. Building with gr.Interface
gr.Interface is the quickest path from a function to a demo. Beyond the three core arguments, it accepts many parameters to control appearance and behavior.
4.1 Multiple inputs and outputs
Pass lists. Each input maps to a function argument (in order); each output maps to a return value (in order):
import gradio as gr
def calculate(num1, operation, num2):
if operation == "add":
return num1 + num2, "Added!"
elif operation == "multiply":
return num1 * num2, "Multiplied!"
demo = gr.Interface(
fn=calculate,
inputs=[gr.Number(), gr.Radio(["add", "multiply"]), gr.Number()],
outputs=[gr.Number(label="Result"), gr.Textbox(label="Status")],
)
demo.launch()
4.2 The four kinds of Interfaces
The shape of an Interface is inferred automatically from inputs/outputs:
| Kind | Condition | Behavior |
|---|---|---|
| Standard | Both inputs and outputs provided |
Input column → Submit → output column |
| Input-only | outputs=None |
Collects input, no output panel |
| Output-only | inputs=None |
"Generate" button produces output |
| Unified | inputs and outputs are the same component objects |
One panel acting as both (e.g. an image editor) |
4.3 Live interfaces
Set live=True to re-run automatically whenever any input changes — no Submit button:
gr.Interface(fn=greet, inputs="text", outputs="text", live=True).launch()
4.4 Examples
Provide sample inputs that users can click to populate the UI. Pass a nested list (one inner list per example, in input order):
gr.Interface(
fn=calculate,
inputs=[gr.Number(), gr.Radio(["add", "multiply"]), gr.Number()],
outputs=[gr.Number(), gr.Textbox()],
examples=[[3, "add", 4], [5, "multiply", 6]],
)
See Examples & Caching for caching and performance.
4.5 Titles, descriptions, and articles
gr.Interface(
fn=greet,
inputs="text",
outputs="text",
title="Greeting Generator",
description="Enter your name to receive a friendly greeting. Supports **Markdown**.",
article="A longer explanation that appears *below* the interface.",
)
description and article accept Markdown and HTML. If article is an HTTP(S) link to a file, its contents are downloaded and displayed.
4.6 Selected gr.Interface parameters
| Parameter | Default | Purpose |
|---|---|---|
live |
False |
Re-run automatically on input change |
examples |
None |
Clickable sample inputs (nested list or directory path) |
cache_examples |
None |
Pre-compute example outputs for instant display |
title / description / article |
None |
Header/footer text (Markdown + HTML) |
flagging_mode |
"manual" |
"never", "auto", or "manual" — show a Flag button to log inputs/outputs |
flagging_dir |
.gradio/flagged |
Where flagged data (CSV) is stored |
submit_btn / clear_btn / stop_btn |
text/Button | Customize the action buttons (string label or gr.Button) |
additional_inputs |
None |
Extra inputs rendered in a collapsible accordion |
concurrency_limit |
"default" |
Max simultaneous runs of this event |
batch / max_batch_size |
False / 4 |
Process inputs in batches (function must accept/return lists) |
show_progress |
"full" |
"full", "minimal", or "hidden" progress animation |
api_name / api_visibility |
None / "public" |
Control how this appears in the REST API |
Tip
additional_inputsis the clean way to add optional knobs (temperature, max-tokens, etc.) without cluttering the main UI — they appear in a collapsed accordion below the primary inputs.
4.7 From a Hugging Face pipeline
If you have a transformers or diffusers pipeline, Gradio infers the inputs and outputs for you:
import gradio as gr
from transformers import pipeline
pipe = pipeline("image-classification")
gr.Interface.from_pipeline(pipe).launch()
4.8 Tabbed interfaces
Combine several Interfaces (or Blocks) into one tabbed app:
gr.TabbedInterface(
[demo1, demo2],
tab_names=["Classifier", "Generator"],
).launch()
5. Building with gr.Blocks
gr.Blocks is Gradio's low-level API. You create a Blocks object, enter it as a context manager (with), declare components and layouts inside, and wire up events. You still write only Python.
5.1 The basic pattern
import gradio as gr
def update(name):
return f"Welcome to Gradio, {name}!"
with gr.Blocks() as demo:
gr.Markdown("Start typing below and then click **Run**.")
with gr.Row():
inp = gr.Textbox(placeholder="What is your name?")
out = gr.Textbox()
btn = gr.Button("Run")
btn.click(fn=update, inputs=inp, outputs=out)
demo.launch()
Three things happen here:
- Components (
gr.Markdown,gr.Textbox,gr.Button) are declared in the order they should appear. - Layout blocks (
gr.Row) control arrangement. - Event listeners (
btn.click(...)) connect a user action to a function.
5.2 Layout components
Nest these as context managers to arrange your UI:
| Layout | Effect |
|---|---|
gr.Row() |
Place children side by side horizontally |
gr.Column() |
Stack children vertically (use scale= for relative width) |
gr.Tabs() / gr.Tab() |
Tabbed sections |
gr.Accordion(label, open=False) |
Collapsible section |
gr.Group() |
Visually group components with no padding between them |
gr.Sidebar() |
A collapsible side panel |
gr.Walkthrough() / gr.Step() |
Multi-step guided flow |
gr.Draggable() |
Drag-to-reorder container |
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=2):
inp = gr.Textbox(label="Input")
with gr.Column(scale=1):
out = gr.Label(label="Output")
with gr.Accordion("Advanced settings", open=False):
temp = gr.Slider(0, 1, label="Temperature")
5.3 Outputs feeding inputs
Unlike Interface, Blocks lets any output drive any other function — build chains and graphs of computation:
with gr.Blocks() as demo:
text = gr.Textbox()
upper = gr.Textbox()
reversed_ = gr.Textbox()
text.change(lambda s: s.upper(), text, upper)
upper.change(lambda s: s[::-1], upper, reversed_)
5.4 Updating component properties
Return a re-instantiated component (or gr.update(...)) to change properties — value, visibility, label, interactivity — at runtime:
def toggle(show):
return gr.Textbox(visible=show)
with gr.Blocks() as demo:
check = gr.Checkbox(label="Show box")
box = gr.Textbox(visible=False)
check.change(toggle, check, box)
Tip
gr.update(value=..., visible=..., interactive=...)is a lightweight alternative when you only want to change a few properties without re-creating the component.
5.5 Multi-page apps
Use demo.route("Page Name", "/path") to add additional pages to a single Blocks app, and gr.Navbar to navigate between them.
6. The Component Library
Gradio includes 40+ built-in components. Each works as an input, an output, or both, and each has rich, type-aware preprocessing/postprocessing so your Python function receives convenient native types (a str, a numpy array, a PIL.Image, a pandas.DataFrame, …).
6.1 Text & number components
| Component | String shortcut | Python type |
|---|---|---|
gr.Textbox |
"text" / "textbox" |
str |
gr.TextArea |
"textarea" |
str (multi-line) |
gr.Number |
"number" |
float / int |
gr.Slider |
"slider" |
float |
gr.Checkbox |
"checkbox" |
bool |
gr.CheckboxGroup |
"checkboxgroup" |
list[str] |
gr.Radio |
"radio" |
str |
gr.Dropdown |
"dropdown" |
str / list |
gr.ColorPicker |
"colorpicker" |
str (hex) |
gr.DateTime |
— | str / timestamp |
gr.Code |
"code" |
str (syntax-highlighted) |
6.2 Media components
| Component | Python type | Notes |
|---|---|---|
gr.Image |
numpy.ndarray / PIL.Image / filepath |
type= controls the format |
gr.ImageEditor |
dict of layers | Draw, crop, mask, inpaint |
gr.ImageSlider |
tuple of two images | Before/after comparison |
gr.Audio |
(sample_rate, numpy) / filepath |
Recording + playback |
gr.Video |
filepath | Upload, record, playback |
gr.Gallery |
list of images | Grid of images |
gr.Model3D |
filepath | 3D model viewer |
gr.File / gr.FileExplorer |
filepath(s) | Upload / browse files |
6.3 Structured-data & plotting components
| Component | Python type | Notes |
|---|---|---|
gr.Dataframe |
pandas.DataFrame |
Editable table |
gr.JSON |
dict / list |
Pretty-printed JSON |
gr.Label |
dict[str, float] |
Classification scores |
gr.HighlightedText |
list of (text, label) | Token/NER highlighting |
gr.BarPlot / gr.LinePlot / gr.ScatterPlot |
pandas.DataFrame |
Native charts |
gr.Plot |
matplotlib/plotly/bokeh figure | Embed any plotting library |
6.4 Chat, display & control components
| Component | Purpose |
|---|---|
gr.Chatbot |
Renders a conversation (used by ChatInterface) |
gr.MultimodalTextbox |
Text input + file attachments |
gr.Dialogue |
Multi-speaker dialogue editor |
gr.Markdown / gr.HTML |
Static rich text / raw HTML |
gr.Button |
Trigger an event |
gr.UploadButton / gr.DownloadButton |
File upload / download buttons |
gr.ClearButton / gr.DuplicateButton / gr.LoginButton / gr.DeepLinkButton |
Specialized action buttons |
gr.State / gr.BrowserState |
Hidden session state (server / browser-persisted) |
gr.Timer |
Fire an event on an interval |
gr.Navbar |
Page navigation bar |
gr.WorkflowCanvas |
Visual node-based workflow editor |
Note
Session state:
gr.State()holds a per-session Python object that persists across interactions but is not displayed.gr.BrowserState()persists data in the user's browser local storage across page reloads. Use them to keep conversation history, counters, or user-specific data.
6.5 Common component parameters
Most components share these constructor arguments:
| Parameter | Purpose |
|---|---|
value |
Initial value (or a function to compute it) |
label |
Text label shown above the component |
info |
Extra helper text below the label |
visible |
Show or hide the component |
interactive |
Whether users can edit it (inputs are interactive, outputs are not, by default) |
elem_id / elem_classes |
DOM id/classes for custom CSS targeting |
scale / min_width |
Relative sizing within a Row/Column |
render |
If False, defer rendering (declare now, place later) |
7. Event Listeners
In Blocks, components expose event listener methods. Calling one wires a user action to a function. The signature is consistent:
component.event(fn, inputs, outputs, **kwargs)
7.1 The event catalog
| Event | Fires when… |
|---|---|
.click() |
A button/component is clicked |
.change() |
A value changes (by user or function) |
.input() |
A value changes by the user only |
.submit() |
Enter is pressed in a textbox |
.select() |
An item/region is selected |
.upload() |
A file is uploaded |
.clear() |
A component is cleared |
.stream() |
Streaming input (webcam/mic) produces a chunk |
.key_up() |
A key is released (live search) |
.focus() / .blur() |
Component gains/loses focus |
.play() / .pause() / .stop() / .end() |
Media playback events |
.start_recording() / .stop_recording() |
Audio/video recording events |
.like() / .retry() / .undo() / .edit() |
Chatbot interactions |
.delete() / .download() / .copy() |
File/clipboard actions |
.expand() / .collapse() |
Accordion toggled |
.tick() |
A gr.Timer interval elapses |
.load() |
The app (or a component value) first loads |
7.2 Chaining events with .then() and .success()
Every event listener returns a dependency you can chain:
click_event = btn.click(step_one, inp, mid)
click_event.then(step_two, mid, out) # runs after, regardless of success
click_event.success(step_three, mid, log) # runs only if step_one succeeded
7.3 Triggering on multiple events with gr.on
gr.on(
triggers=[textbox.submit, button.click],
fn=respond,
inputs=textbox,
outputs=output,
)
7.4 Streaming and progress
Make fn a generator (yield) to stream partial results to the UI. Add a gr.Progress() argument to report progress bars:
def generate(prompt, progress=gr.Progress()):
for i in progress.tqdm(range(10)):
...
yield partial_result
Important
Generator functions (those that
yield) require the queue to be enabled. The queue is on by default, so this usually works automatically — but if you call.queue(...)you must do so before.launch().
8. Building Chatbots with gr.ChatInterface
gr.ChatInterface builds a complete chatbot UI from a single message-handling function. Only fn is required.
8.1 The chat function contract
Your function receives message (the user's latest input as a str) and history (a list of OpenAI-style {"role": ..., "content": ...} dicts). It returns or yields the assistant's reply:
import gradio as gr
def echo(message, history):
return f"You said: {message}"
gr.ChatInterface(fn=echo, title="Echo Bot").launch()
8.2 Streaming responses
Yield progressively to stream tokens as they are produced:
def slow_echo(message, history):
response = ""
for char in message:
response += char
yield response
gr.ChatInterface(fn=slow_echo).launch()
8.3 Connecting a real LLM
from openai import OpenAI
client = OpenAI()
def chat(message, history):
messages = history + [{"role": "user", "content": message}]
stream = client.chat.completions.create(
model="gpt-4o-mini", messages=messages, stream=True
)
response = ""
for chunk in stream:
response += chunk.choices[0].delta.content or ""
yield response
gr.ChatInterface(fn=chat, type="messages").launch()
8.4 Multimodal & advanced chat features
| Parameter | Effect |
|---|---|
multimodal=True |
Use a MultimodalTextbox so users can attach files; message becomes {"text": ..., "files": [...]} |
editable=True |
Users can edit past messages and regenerate |
save_history=True |
Persist conversations to the browser and show a history side panel |
examples=[...] |
Clickable starter prompts (strings, or dicts with text/files) |
additional_inputs=[...] |
Extra controls (system prompt, temperature) passed after history |
additional_outputs=[...] |
Update other components (e.g. an artifact panel) from the chat function |
flagging_mode="manual" |
Show 👍/👎 feedback on assistant messages (flagging_options=("Like","Dislike")) |
Tip
Set
type="messages"to use the modern OpenAI-style dictionary history format. This is the recommended format for new chatbots.
9. Launching & Sharing Your App
.launch() starts the web server. It returns (app, local_url, share_url).
9.1 Common launch options
| Parameter | Default | Purpose |
|---|---|---|
share |
False |
Create a temporary public *.gradio.live link |
server_name |
"127.0.0.1" |
Set to "0.0.0.0" to expose on your local network |
server_port |
7860 (auto-search) |
Port to bind |
auth |
None |
Require login (see Authentication) |
inbrowser |
False |
Auto-open a browser tab |
debug |
False |
Block the main thread and print errors (needed in Colab) |
show_error |
False |
Show full errors in the UI and browser console |
favicon_path |
None |
Custom favicon (.png/.gif/.ico) |
max_file_size |
None |
Cap uploads, e.g. "5mb" |
pwa |
None |
Make the app installable as a Progressive Web App |
ssr_mode |
False |
Server-side rendering (needs Node 20+) for performance/SEO |
9.2 Styling at launch
Important
Changed in Gradio 6.0:
theme,css,css_paths,js,head, andhead_pathsmoved from thegr.Blocks(...)constructor to.launch(...). Passing them to the constructor now emits a warning. Update older code accordingly.
demo.launch(
theme="soft",
css=".gradio-container {background: #f0f0f0}",
)
See Themes & Styling.
9.3 Custom HTTPS
demo.launch(
ssl_keyfile="key.pem",
ssl_certfile="cert.pem",
)
9.4 Mounting inside an existing FastAPI app
from fastapi import FastAPI
import gradio as gr
app = FastAPI()
@app.get("/")
def root():
return {"message": "Hello"}
app = gr.mount_gradio_app(app, demo, path="/gradio")
10. The Queue & Concurrency
The queue manages how many function calls run at once and gives users their position while waiting. It is enabled by default.
demo.queue(
max_size=20, # max events held; new ones rejected when full
default_concurrency_limit=2, # default simultaneous runs per event
)
demo.launch()
queue() parameter |
Default | Purpose |
|---|---|---|
max_size |
None (unlimited) |
Maximum events in the queue |
default_concurrency_limit |
1 |
Default concurrency_limit for events that don't set one |
status_update_rate |
"auto" |
How often queue positions are broadcast |
api_open |
— | If True, REST routes bypass the queue |
Set per-event limits with concurrency_limit= on .click()/.then()/etc., and group events that share a resource with the same concurrency_id.
Note
The environment variable
GRADIO_DEFAULT_CONCURRENCY_LIMITsets the default concurrency limit globally without editing code.
11. Hot Reload & Vibe Mode — the gradio CLI
Installing Gradio adds a gradio command-line tool.
11.1 Hot reload
Run your app with gradio instead of python to auto-reload on every file change:
gradio app.py
If your Blocks/Interface object is named something other than demo, pass the name:
gradio app.py my_app
11.2 Vibe mode — edit your app in natural language
gradio --vibe app.py
This opens an in-browser chat panel that can write or edit your Gradio app from natural-language instructions.
Caution
Vibe mode lets anyone who can reach the app endpoint modify files and run arbitrary code on the host machine. Use it only locally, never on a public or production server.
11.3 The full CLI
| Command | Purpose |
|---|---|
gradio app.py |
Run in hot-reload mode (default) |
gradio --vibe [app.py] |
Hot reload + in-browser natural-language editor |
gradio deploy |
Deploy the current directory to Hugging Face Spaces or Google Cloud Run |
gradio sketch |
Visually design a Gradio app |
gradio environment |
Print Gradio environment info (for bug reports) |
gradio info |
Print the JSON payload schema for an app's endpoints |
gradio predict |
Send a prediction request to an app endpoint |
gradio load <space> |
Load and run a remote Space locally |
gradio skills add ... |
Install AI coding skills |
gradio cc <build|dev|create|show|publish|install> |
Custom-component development |
12. Querying Apps Programmatically
Every Gradio app is also an API. Any event with an api_name is exposed as a REST endpoint, and Gradio generates client libraries for it.
12.1 View the API
Click the "Use via API" link in your app's footer, or visit http://localhost:7860/?view=api, to see auto-generated docs with copy-paste snippets for Python, JavaScript, and cURL.
12.2 The Python client
pip install gradio_client
from gradio_client import Client
client = Client("http://127.0.0.1:7860/") # or "username/space-name" on Spaces
result = client.predict("Alice", 3, api_name="/predict")
print(result)
| Method | Purpose |
|---|---|
client.predict(*args, api_name=...) |
Call an endpoint and block for the result |
client.submit(*args, api_name=...) |
Call asynchronously; returns a Job future |
client.view_api() |
Print all endpoints and their signatures |
client.duplicate(...) |
Duplicate a Space and connect to your copy |
For file inputs, wrap paths with handle_file():
from gradio_client import Client, handle_file
client.predict(handle_file("cat.png"), api_name="/classify")
12.3 The JavaScript client
npm install @gradio/client
import { Client } from "@gradio/client";
const client = await Client.connect("username/space-name");
const result = await client.predict("/predict", ["Alice", 3]);
console.log(result.data);
12.4 Controlling API visibility
Set api_visibility on any event:
| Value | Shown in API docs? | Callable by clients? |
|---|---|---|
"public" (default) |
Yes | Yes |
"undocumented" |
No | Yes |
"private" |
No | No |
13. Examples & Caching
Provide examples so users can try your app with one click. Cache them to display results instantly.
gr.Interface(
fn=classify,
inputs=gr.Image(),
outputs=gr.Label(),
examples=["cat.png", "dog.png"],
cache_examples=True, # pre-compute outputs at launch
cache_mode="eager", # or "lazy" (compute on first use)
)
| Option | Effect |
|---|---|
cache_examples=True |
Pre-run examples so clicking shows the cached output instantly |
cache_mode="eager" |
Compute all examples at launch |
cache_mode="lazy" |
Compute each example the first time any user clicks it |
examples_per_page |
How many examples to show per page |
Note
On Hugging Face Spaces,
cache_examplesdefaults toTrue. TheGRADIO_CACHE_EXAMPLESandGRADIO_CACHE_MODEenvironment variables override the defaults.
14. Gradio as an MCP Server
Gradio apps can act as Model Context Protocol (MCP) servers, exposing your documented functions as tools that AI agents (Claude, Cursor, etc.) can call.
import gradio as gr
def letter_counter(word: str, letter: str) -> int:
"""Count occurrences of a letter in a word."""
return word.lower().count(letter.lower())
demo = gr.Interface(fn=letter_counter, inputs=["text", "text"], outputs="number")
demo.launch(mcp_server=True)
With mcp_server=True, every public, documented function becomes an MCP tool. The MCP endpoint and a landing page are served automatically.
Tip
Install the MCP extra first:
pip install "gradio[mcp]". You can also enable MCP without code by settingGRADIO_MCP_SERVER=True.
For fine-grained control, Server mode (gr.Server) lets you register MCP tools, resources, and prompts with decorators alongside ordinary FastAPI routes — see the Admin Guide.
15. Authentication
15.1 Username/password
demo.launch(auth=("admin", "secret")) # single user
demo.launch(auth=[("alice", "pw1"), ("bob", "pw2")]) # multiple users
Or pass a function for custom logic:
def check(username, password):
return username == "admin" and verify(password)
demo.launch(auth=check, auth_message="Please sign in.")
15.2 OAuth / external auth
Use auth_dependency (a function taking a FastAPI request and returning a user id or None) to integrate OAuth and other external systems. Add a gr.LoginButton for Hugging Face sign-in. The [oauth] extra is required.
Warning
authandauth_dependencyare mutually exclusive — pass only one to.launch().
16. Themes & Styling
16.1 Built-in themes
demo.launch(theme="soft") # "default", "soft", "monochrome", "glass", "origin", "citrus", "ocean"
You can also load community themes from the Hub: theme="gradio/seafoam".
16.2 Custom CSS
demo.launch(
css=".gradio-container {max-width: 800px !important}",
)
Target individual components with elem_id / elem_classes and matching CSS selectors. Use css_paths to load CSS from a file.
16.3 Building a theme
gr.themes.Base (and Soft, Monochrome, etc.) can be subclassed and tweaked. Build interactively with the theme builder:
import gradio as gr
gr.themes.builder()
17. Deploying to Hugging Face Spaces
The easiest permanent host is a free Hugging Face Space:
gradio deploy
Run this inside your app's directory; the CLI prompts for a Space name and uploads your files. Alternatively, create a Space on huggingface.co, choose the Gradio SDK, and push an app.py plus a requirements.txt.
Tip
On Spaces, Gradio automatically enables example caching, a "Duplicate this Space" button (when
allow_duplication=True), and Progressive Web App support.
gradio deploy can also target Google Cloud Run.
18. AI Coding Skills
Gradio ships a "skill" that teaches AI coding assistants (Cursor, Claude Code, Codex, OpenCode) how to build Gradio apps correctly — especially custom components and styling:
gradio skills add --cursor # or --claude, --codex, --opencode
Add --global to install for all projects. You can also generate API-usage docs for a specific Space:
gradio skills add abidlabs/en2fr --cursor
19. Custom Components
Build and publish your own reusable component (Python backend + Svelte frontend) with the gradio cc toolchain:
| Command | Purpose |
|---|---|
gradio cc create <Name> |
Scaffold a new custom component |
gradio cc dev |
Run the component's dev server with hot reload |
gradio cc build |
Build the component for distribution |
gradio cc show |
List installed custom components |
gradio cc publish |
Publish to PyPI and the Hugging Face gallery |
gradio cc install |
Install a custom component's dependencies |
20. Troubleshooting
Error: ValueError: When localhost is not accessible, a shareable link must be created. Please set share=True
Cause: You are in an environment (e.g. Google Colab, some containers) where localhost is not reachable.
Solution: Call demo.launch(share=True).
Prevention: In notebooks/Colab, always launch with share=True.
Error: Queue needs to be enabled!
Cause: You used a generator (yield) function, or an event that cancels another, without the queue enabled.
Solution: The queue is on by default; if you disabled it, call demo.queue() before demo.launch().
Prevention: Don't pass api_open/queue settings that disable queuing for streaming apps.
Error: inputs must be a string, list, or Component
Cause: Something other than a component (or its string shortcut) was passed to inputs/outputs.
Solution: Pass gr.Textbox() (or "text"), not a raw value or unrelated object.
Prevention: Remember inputs/outputs take components, while value= takes data.
Problem: The number of inputs doesn't match my function
Cause: The count of inputs components must equal the number of fn parameters (and outputs the number of return values).
Solution: Add/remove components so the counts line up, or use additional_inputs for optional ones.
Problem: My app runs but isn't reachable from another machine
Cause: By default Gradio binds to 127.0.0.1 (localhost only).
Solution: demo.launch(server_name="0.0.0.0") (or set GRADIO_SERVER_NAME=0.0.0.0).
Prevention: Only expose 0.0.0.0 on trusted networks, and add auth= if needed.
Problem: A local file (image/CSV) won't display or download
Cause: Gradio only serves files inside its working/cache directories by default for security.
Solution: Add the file's directory to allowed_paths=[...] in .launch() (or GRADIO_ALLOWED_PATHS).
Prevention: Keep user-served assets under the app directory; use allowed_paths deliberately.
Error: Cannot find empty port in range
Cause: Ports 7860–7959 are all occupied.
Solution: Free a port or set server_port= / GRADIO_SERVER_PORT to an open one.
Problem: Custom theme/CSS passed to gr.Blocks() is ignored (Gradio 6)
Cause: In Gradio 6.0 these moved to .launch().
Solution: Pass theme=, css=, js=, head= to demo.launch(...) instead of gr.Blocks(...).
Problem: SSR mode warning or failure
Cause: ssr_mode=True requires Node.js 20+ on the host.
Solution: Install Node 20+, or set ssr_mode=False (the default).
Problem: gr.Dataframe freezes inside a Tab after upgrading
Cause: Known issue (#13448) on certain 6.x versions. Solution: Upgrade to the latest patch release; track the issue for fixes.
Problem: Telemetry / version-check network calls at startup
Cause: Gradio performs anonymous analytics and a version check by default.
Solution: Set analytics_enabled=False (constructor) or GRADIO_ANALYTICS_ENABLED=False.
21. Frequently Asked Questions
Q: Do I need to know JavaScript, HTML, or CSS to use Gradio? No. Everything — layout, interactivity, events — is written in Python. CSS/JS are optional escape hatches for advanced styling.
Q: When should I use Interface vs Blocks?
Use Interface to wrap a single function with fixed inputs/outputs. Use Blocks when you need custom layouts, multiple interacting functions, or dynamic UIs. Use ChatInterface for chatbots.
Q: How do I stream output token-by-token?
Make fn a generator and yield partial results. The queue (on by default) handles streaming.
Q: Is the share link permanent?
No — share=True links last about 72 hours and tunnel from your machine. For permanent hosting, deploy to Hugging Face Spaces with gradio deploy.
Q: How do I keep per-user data between interactions?
Use gr.State() for in-memory session state, or gr.BrowserState() to persist in the browser across reloads.
Q: Can other programs call my Gradio app?
Yes. Every app exposes a REST API. Use gradio_client (Python) or @gradio/client (JS), or visit /?view=api for snippets.
Q: How do I add a temperature/system-prompt knob to a chatbot?
Pass additional_inputs=[...] to gr.ChatInterface; the values are appended to your function's arguments after history.
Q: How do I let an AI agent call my function?
Launch with mcp_server=True (and pip install "gradio[mcp]"). Documented functions become MCP tools.
Q: How do I run my app for development with auto-reload?
Run gradio app.py instead of python app.py.
Q: How do I limit how many people run my model at once?
Set concurrency_limit= on the event (or default_concurrency_limit in .queue()), and cap the queue with max_size.
Q: How do I require a login?
Pass auth=("user", "password") (or a list, or a function) to .launch().
Q: Why does my function receive a numpy array / PIL image / DataFrame instead of a file path?
Each component preprocesses its value into a convenient Python type. Configure the format with the component's type= argument (e.g. gr.Image(type="filepath")).
Q: Can I embed a Gradio app in my own website?
Yes — use the auto-generated Web Component / iframe embed code shown on a Space, or mount it in your FastAPI app with gr.mount_gradio_app.
22. Quick Reference
Minimal apps
# Interface
gr.Interface(fn, inputs, outputs).launch()
# Blocks
with gr.Blocks() as demo:
inp = gr.Textbox(); out = gr.Textbox(); btn = gr.Button("Go")
btn.click(fn, inp, out)
demo.launch()
# ChatInterface
gr.ChatInterface(fn).launch()
Launch cheat-sheet
| Goal | Code |
|---|---|
| Public link | demo.launch(share=True) |
| LAN access | demo.launch(server_name="0.0.0.0") |
| Require login | demo.launch(auth=("user","pw")) |
| Choose port | demo.launch(server_port=8080) |
| MCP server | demo.launch(mcp_server=True) |
| Apply theme | demo.launch(theme="soft") |
| Cap uploads | demo.launch(max_file_size="5mb") |
Key environment variables
| Variable | Default | Effect |
|---|---|---|
GRADIO_SERVER_NAME |
127.0.0.1 |
Bind address |
GRADIO_SERVER_PORT |
7860 |
Port |
GRADIO_SHARE |
False |
Force a share link |
GRADIO_ANALYTICS_ENABLED |
True |
Anonymous telemetry |
GRADIO_TEMP_DIR |
system tmp | Where Gradio caches files |
GRADIO_ALLOWED_PATHS / GRADIO_BLOCKED_PATHS |
— | Extra/forbidden served paths |
GRADIO_MCP_SERVER |
False |
Enable MCP server |
GRADIO_SSR_MODE |
False |
Server-side rendering |
The gradio CLI
| Command | Purpose |
|---|---|
gradio app.py |
Hot-reload dev server |
gradio --vibe app.py |
Natural-language editor (local only ⚠️) |
gradio deploy |
Deploy to Spaces / Cloud Run |
gradio sketch |
Visual app designer |
gradio cc ... |
Custom component toolchain |
gradio environment |
Print env info |
gradio skills add |
Install AI coding skills |