# Gradio User Guide

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), and **`gr.ChatInterface`** (purpose-built for chatbots). All three are entirely Python.

---

## 1. Quick Start

### 1.1 Your first app

Create a file named `app.py`:

```python
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:

```bash
python app.py
```

Expected output:

```text
* 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](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).

```python
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:

```python
demo.launch(share=True)
```

```text
* 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](#18-authentication).

---

## 2. Installation

**Prerequisite:** Gradio requires **Python 3.10 or higher** (3.10–3.13 are supported).

=== "pip (recommended)"

    ```bash
    pip install --upgrade gradio
    ```

=== "With OAuth support"

    ```bash
    pip install --upgrade "gradio[oauth]"
    ```

=== "With MCP server support"

    ```bash
    pip install --upgrade "gradio[mcp]"
    ```

=== "uv"

    ```bash
    uv add gradio
    ```

Verify the install:

```bash
python -c "import gradio; print(gradio.__version__)"
```

```text
6.17.0
```

> [!TIP]
> Always install Gradio inside a virtual environment to avoid dependency conflicts:
> ```bash
> 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.Interface` and `gr.ChatInterface` are both built *on top of* `gr.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):

```python
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:

```python
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):

```python
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](#13-examples--caching) for caching and performance.

### 4.5 Titles, descriptions, and articles

```python
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](#14-querying-apps-programmatically) |

> [!TIP]
> `additional_inputs` is 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:

```python
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:

```python
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

```python
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:

1. **Components** (`gr.Markdown`, `gr.Textbox`, `gr.Button`) are declared in the order they should appear.
2. **Layout blocks** (`gr.Row`) control arrangement.
3. **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 |

```python
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:

```python
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:

```python
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:

```python
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:

```python
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`

```python
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:

```python
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:

```python
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:

```python
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

```python
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](#18-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`, and `head_paths` moved from the `gr.Blocks(...)` constructor to **`.launch(...)`**. Passing them to the constructor now emits a warning. Update older code accordingly.

```python
demo.launch(
    theme="soft",
    css=".gradio-container {background: #f0f0f0}",
)
```

See [Themes & Styling](#17-themes--styling).

### 9.3 Custom HTTPS

```python
demo.launch(
    ssl_keyfile="key.pem",
    ssl_certfile="cert.pem",
)
```

### 9.4 Mounting inside an existing FastAPI app

```python
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.**

```python
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_LIMIT` sets 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:

```bash
gradio app.py
```

If your `Blocks`/`Interface` object is named something other than `demo`, pass the name:

```bash
gradio app.py my_app
```

### 11.2 Vibe mode — edit your app in natural language

```bash
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](#20-ai-coding-skills) |
| `gradio cc <build\|dev\|create\|show\|publish\|install>` | [Custom-component](#21-custom-components) 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

```bash
pip install gradio_client
```

```python
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()`:

```python
from gradio_client import Client, handle_file
client.predict(handle_file("cat.png"), api_name="/classify")
```

### 12.3 The JavaScript client

```bash
npm install @gradio/client
```

```javascript
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.

```python
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_examples` defaults to `True`. The `GRADIO_CACHE_EXAMPLES` and `GRADIO_CACHE_MODE` environment 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.

```python
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 setting `GRADIO_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

```python
demo.launch(auth=("admin", "secret"))                       # single user
demo.launch(auth=[("alice", "pw1"), ("bob", "pw2")])         # multiple users
```

Or pass a function for custom logic:

```python
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]
> `auth` and `auth_dependency` are mutually exclusive — pass only one to `.launch()`.

---

## 16. Themes & Styling

### 16.1 Built-in themes

```python
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

```python
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:

```python
import gradio as gr
gr.themes.builder()
```

---

## 17. Deploying to Hugging Face Spaces

The easiest permanent host is a free Hugging Face Space:

```bash
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:

```bash
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:

```bash
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](https://github.com/gradio-app/gradio/issues/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

```python
# 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 |

---

_Generated June 2026 from gradio-app/gradio at e4e84a2. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
