Skip to main content
A custom frontend is any application you write that calls a deployment directly instead of reaching the agent through a channel or LangSmith Studio. Use one when the agent belongs inside a product surface you control, such as a support console, an internal dashboard, or a customer-facing chat page. Managed Deep Agents deployments run on LangSmith Agent Server, so a frontend talks to the same threads, runs, and streaming endpoints that every Agent Server client uses. Nothing on the agent side changes to support one.
Managed Deep Agents is in public beta on LangSmith Cloud and Bring Your Own Cloud (BYOC). Use Managed Deep Agents CLI and SDK v0.10 or later for BYOC.

Choose an identity mode

Where your frontend code runs determines which identity mode it can use. A LangSmith API key grants access to the whole workspace, so it must never reach a browser. With backend identity, the browser never calls the deployment. Your API authenticates the user, then calls the deployment with the ingress secret. Supabase and backend identity also give each signed-in user private threads. The API-key default does not: every caller holding the key shares the same thread space.
Anyone with a LangSmith API key can reach the deployment and every other resource in the workspace. Shipping one in browser JavaScript exposes it to every visitor. When the browser calls the deployment, use Supabase. Otherwise keep credentials on a server route the browser calls.

Connect to the deployment

A frontend needs two values. Deployment API URL. mda deploy prints the LangSmith deployment dashboard URL, not the API URL. Open that dashboard, then copy the API URL from the deployment details view. The local server started by mda dev serves the same routes at the URL the CLI prints. Assistant ID. Clients pass the agent’s name from the agent definition, which Managed Deep Agents also uses as the graph ID:
agent.ts
Clients address an agent named research-assistant as assistantId: "research-assistant". Renaming the agent changes the value clients send, so treat the name as part of the deployment’s public interface.

Build a web frontend

The LangChain frontend SDKs connect a browser application to an Agent Server deployment. useStream exposes messages, tool calls, interrupts, and thread state as reactive values: A frontend is a web application, so these examples are TypeScript whether the agent is written in Python or TypeScript. Point the hook at the deployment API URL and the agent name:
Chat.tsx
defaultHeaders carries the Supabase access token that the signed-in user obtained from your auth flow. For the API-key default, pass apiKey instead, which the SDK sends as x-api-key. Only do so from code that runs on a server. These patterns apply unchanged to a Managed Deep Agents deployment: tool-call rendering, generative UI, human-in-the-loop approval, queued submissions, and durable rejoin.

Handle authorization interrupts

When the agent needs a user-owned connection the caller has not granted, the run pauses and stream.interrupt carries a credential gate payload. A browser frontend renders the consent links and resumes with stream.respond. For the payload shape and a worked example, see Handle the authorization interrupt.

Build a Python frontend

Streamlit, Gradio, and Dash render on the server, so the LangSmith API key stays out of the browser and the API-key default works without extra setup. All three use the same LangGraph SDK client, so the connection code below applies to any of them. Install the SDK alongside your application framework:
Create a client, then stream a run against a thread:
Three details govern how that loop behaves:
  • api_key: Sets the x-api-key header. Passing headers={"x-api-key": ...} instead raises ValueError: Cannot set reserved header 'x-api-key'.
  • Environment fallback: When api_key is omitted, the client tries LANGGRAPH_API_KEY, then LANGSMITH_API_KEY, then LANGCHAIN_API_KEY. For Supabase or backend identity, pass api_key=None explicitly and put the token in headers, or a stray environment variable attaches a second credential.
  • messages/partial: Carries the whole message so far, not a delta. Replace the rendered text on each event rather than appending, or the output repeats itself.

Stream into a Streamlit chat

This application keeps one thread per browser session and rewrites the assistant bubble as each event arrives:
app.py
The highlighted line replaces the bubble contents on every event. Appending there produces duplicated text, because each event repeats the message from the beginning. text_of reads content blocks rather than a plain string. Agent messages arrive as a list of typed blocks, so a frontend that expects message["content"] to be text renders nothing. The web SDKs deserialize each event into a message object that exposes a text accessor, which is why the React example above reads message.text. The LangGraph SDK yields plain dictionaries, so a Python frontend extracts the text itself. Gradio and Dash use the same client and the same loop. Substitute their streaming primitive for the Streamlit placeholder: a generator function for gr.ChatInterface, or a dcc.Interval callback for Dash.

See also

  • Identity: configure how callers authenticate to the deployment.
  • Frontend overview: message rendering, tool calls, interrupts, and generative UI patterns.
  • Connections: handle the credential authorization interrupt in your UI.
  • MCP endpoint: expose the agent to MCP clients instead of calling the API.
  • Channels: reach the agent from Slack or your own HTTP service.