Post

Every Path to Integrating Your Copilot Studio Agent

An interactive decision wizard that helps you pick the right integration pattern for your Copilot Studio agent, from no-code embeds to native mobile apps, custom UIs, and server-side connectors.

Every Path to Integrating Your Copilot Studio Agent

When I was a kid, I thought Choose Your Own Adventure and Fighting Fantasy gamebooks were the coolest thing. The Warlock of Firetop Mountain, Citadel of Chaos, that whole world. You’d read a page, make a choice, flip to a new section, and the story would branch in a completely different direction. They were also brutally hard, and I’ll admit I peeked ahead more than a couple of times to avoid walking straight into Zagor’s dragon.

I think about those books sometimes when someone asks me: “How do I get my Copilot Studio agent into my website or app?” Because the landscape is wider than it looks. You’ve got no-code embeds, Teams publishing, self-hosted WebChat with two distinct APIs behind it (Direct Line and the M365 Agents SDK), server-side clients, and even the option to skip WebChat entirely and bring your own UI framework. Each path has different strengths, different authentication models, and different levels of effort. Unlike Fighting Fantasy, we don’t want you picking an integration strategy only to end up lost in the Maze of Zagor three sprints in, out of stamina, with the wrong keys.

The good news is that the branching structure actually works here. Three or four questions, and the right answer falls out naturally. So instead of writing another comparison table that you’ll skim and forget, I built a small interactive wizard. Answer the questions, land on a recommendation, jump straight to a working code sample. No peeking required.


The Wizard


No API Needed (Publish to Teams/M365)

If your employees already live in Teams, this is a no-brainer. Copilot Studio publishes directly to Teams as a first-class channel. No token endpoints, no JavaScript, no infrastructure to maintain. And choosing Teams now doesn’t lock you in. You can always add a web-based experience later using any of the patterns below. For deployment tips, see Best Practices for Deploying Copilot Studio Agents in Microsoft Teams, and for why publishing to Teams and M365 doesn’t limit you later on, see You Probably Don’t Need Manual Auth in Copilot Studio.

When to use this: Internal knowledge bases, IT help desks, HR FAQ agents, or any scenario where your users already spend their day in Teams/M365.

Back to wizard ↑


Microsoft-Hosted WebChat (No-Code)

If you need a web-based chat experience but don’t want to write code, Copilot Studio can host WebChat for you. This works for both employee-facing intranets and customer-facing websites. Navigate to Channels > Web app in the portal, and you’ll find an iframe embed snippet you can paste straight into your HTML:

1
2
3
4
5
<iframe
  src="https://copilotstudio.microsoft.com/environments/YOUR-ENV/bots/YOUR-AGENT-ID/webchat?__version__=2"
  frameborder="0"
  style="width: 100%; height: 500px;">
</iframe>

That’s it. Microsoft hosts the WebChat instance, handles the token lifecycle, and serves the chat UI. You get a functional agent on your site with zero build steps. The same page also shows the M365 Agents SDK connection string (docs).

The trade-off? When authentication is configured, the Microsoft-hosted embed uses manual authentication, which in this implementation means a magic validation code that users copy-paste from a browser tab. Manual auth itself doesn’t mandate the magic code (that’s just how the hosted WebChat implements it), but the result is the same: there’s no way to get SSO through the embed. If your users are already signed into your site and you want seamless authentication, you’ll need to self-host WebChat instead.

Heads up (March 2026): The official docs currently state the embed code is only available when authentication is set to “No authentication.” That’s not quite right. The embed code is available for both “No authentication” and “Manual authentication,” but not for agents configured with “Authenticate with Microsoft.” We’re working on getting the docs updated.

Would you like to see an SSO-enabled embed experience? If a no-code embed with seamless Entra ID sign-in would be useful for your scenario, let us know in the comments.

When to use this: Internal portals, intranet sites, customer-facing websites, proof-of-concepts, or anywhere “it just works” matters more than SSO.

Back to wizard ↑


Self-Hosted WebChat (Employee-Facing)

This is the most common pattern for custom-branded agent experiences. You host the botframework-webchat library yourself, giving you full control over styling, behavior, and authentication. And it’s not limited to standalone web apps. The same WebChat component can be embedded natively in SharePoint, ServiceNow (see our field report), or any platform that can host JavaScript.

The core pattern is almost always the same. You import the WebChat library, create a connection to your agent (more on the options below), and hand it to WebChat:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<script>
// 1. Create a connection to your Copilot Studio agent.
//    This can use Direct Line or the M365 Agents SDK — see below.
var directLine = /* your connection */;

// 2. Render WebChat — this part is the same regardless of connection method.
window.WebChat.renderWebChat(
  {
    directLine: directLine,
    styleOptions: {
      hideUploadButton: true,
      bubbleBackground: '#e8f0fe',
      primaryFont: "'Segoe UI', sans-serif"
    }
  },
  document.getElementById('webchat')
);
</script>

The styleOptions object gives you control over colors, fonts, bubble shapes, avatar images, and more, all without writing CSS.

Which Adapter: Direct Line or M365 Agents SDK?

Copilot Studio exposes two APIs for connecting WebChat to your agent: Direct Line (a public API) and the M365 Agents SDK Copilot Studio client (which wraps a private API only accessible through the SDK). WebChat has adapters for both, so the rendering code above stays the same either way.

For employee-facing scenarios, we recommend the M365 Agents SDK client. Here’s why:

  • “Authenticate with Microsoft”: The SDK client requires this auth mode, which is exactly what you want for B2E. It gives you seamless Entra ID SSO (no magic codes), simpler configuration (one app registration), and unlocks Tenant Graph Grounding for higher quality responses grounded in SharePoint and Graph Connectors. For why this beats manual auth in almost every employee scenario, read You Probably Don’t Need Manual Auth in Copilot Studio.
  • Streaming: The SDK client supports streaming responses. Direct Line does support streaming for code-first agents built with the M365 Agents SDK, but not for Copilot Studio agents. Yes, we see the irony.

Direct Line is still a valid choice if you specifically need manual authentication (e.g., a non-Entra OAuth provider), but that’s a rare requirement for internal agents.

Official samples and docs:

When to use this: Internal web apps, SharePoint sites, ServiceNow portals, or any employee-facing platform where you need styling control and authenticated access to your agent.

Back to wizard ↑


Bring Your Own UI (Employee-Facing)

Maybe WebChat isn’t your thing. Maybe your team already has a React design system, you’re deep into a framework like Assistant UI or the Vercel AI SDK, and the idea of wrapping a Microsoft chat component doesn’t fit your architecture. That’s a valid position, and Copilot Studio supports it.

The connection layer is the same M365 Agents SDK client discussed above, with the same authentication and streaming benefits. The difference is that instead of handing the connection to WebChat, you wire it into your own components. The Assistant UI + Copilot Studio sample shows what this looks like: a React app using Assistant UI components connected to a Copilot Studio agent through the SDK.

The trade-off: WebChat handles adaptive cards, suggested actions, file attachments, typing indicators, and dozens of Bot Framework activity types out of the box. When you bring your own UI, you’re responsible for all of that. If your agent sends an adaptive card and your custom UI doesn’t render it, the user sees nothing (or worse, raw JSON). And WebChat itself is heavily customizable. We’ll dig deeper into this comparison in an upcoming WebChat series.

The gap between “I need BYO” and “I didn’t realize WebChat could do that” is often thinner than people expect.

When to use this: When you’re already invested in a specific agentic UX framework (Assistant UI, Vercel AI SDK, etc.) and want your Copilot Studio agent to plug into it natively.

Back to wizard ↑


WebChat + Direct Line (Customer-Facing)

The most straightforward way to embed a chat experience in your customer-facing website or web app. The code is nearly identical to the employee version. What changes is the context: your customers may not authenticate at all, or they authenticate with non-Entra providers. Direct Line supports both. For authenticated customers, you can wire up SSO with identity providers like Google, Okta, or Auth0.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div id="webchat"></div>

<script
  src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js">
</script>
<script>
  fetch('https://YOUR-TOKEN-ENDPOINT/api/token')
    .then(function(response) { return response.json(); })
    .then(function(data) {
      window.WebChat.renderWebChat(
        {
          directLine: window.WebChat.createDirectLine({ token: data.token }),
          styleOptions: {
            botAvatarImage: 'https://your-site.com/bot-avatar.png',
            bubbleBackground: '#f0f0f0',
            bubbleFromUserBackground: '#0078d4',
            bubbleFromUserTextColor: '#ffffff',
            primaryFont: "'Your Brand Font', sans-serif",
            hideUploadButton: true
          }
        },
        document.getElementById('webchat')
      );
    });
</script>

Want it even simpler? Embedding WebChat Without Writing a Single Line of JavaScript covers an open-source library that turns this already straightforward setup into a declarative HTML snippet.

For deeper customization (custom activity renderers, middleware, telemetry), the WebChat Middlewares post covers the full pattern.

When to use this: Customer-facing chat widgets, support portals, marketing sites, or any scenario where external users interact with your agent through a browser.

Back to wizard ↑


Bring Your Own UI (Customer-Facing)

Not every agent experience is a chat window. Maybe you want a search box that sends a query to your Copilot Studio agent and displays the answer inline, or a product page that pulls a recommendation without any visible chat UI. For these scenarios, you can call Direct Line directly from your own components.

The Direct Line JS sample shows this pattern: a lightweight JavaScript client that talks to Direct Line without any WebChat dependency. You send activities, receive responses, and render them however you want.

Before going this route, remember that WebChat is heavily customizable. You can strip it down, replace components, or restyle it completely. But if what you’re building doesn’t resemble a chat interface at all, Direct Line without WebChat is the right call.

When to use this: Search experiences, inline answers, product recommendations, or any customer-facing scenario where you need agent responses without a chat UI.

Back to wizard ↑


Native Mobile SDK (Preview)

If you’re building a native mobile app, Microsoft provides the Agents Client SDK for Android, iOS, and Windows. The SDK handles the connection to your agent under the hood. You call sendMessage(), observe responses via platform-native patterns (Kotlin StateFlow, SwiftUI @ObservedObject, C# events), and get Adaptive Cards rendering and optional speech support built in. On iOS, there’s even a drop-in PluggableChatComponent that gives you a themed chat UI out of the box.

Preview (March 2026). The SDK currently requires your agent to be configured with “No Authentication.” The config schema has fields for Entra ID auth, but it’s not functional yet. Plan accordingly.

When to use this: Customer-facing native apps (Android, iOS, Windows) where a web-based chat widget isn’t the right fit and you don’t need authenticated users.

Back to wizard ↑


Server-Side Connector

Some organizations, especially in regulated industries, need a server-side layer between their users and the agent. Maybe you need to sanitize sensitive information before it reaches the agent (or before responses reach the user), enforce compliance rules, or translate adaptive cards into your own UI component library. The pattern is the same: your backend talks to Copilot Studio, and your frontend talks to your backend.

You have two options for the backend-to-agent connection: the M365 Agents SDK client or Direct Line over HTTP.

M365 Agents SDK Client

The SDK gives you a developer-friendly client (available for .NET, Node.js, and Python) with an async activity iterator that yields just the agent’s responses. Embed it in your server, sanitize or transform what you need, and expose a simple HTTP endpoint to your frontend. Your client doesn’t need to know about the underlying protocol, and neither does your server code. The Node.js console sample shows the full pattern end to end.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Activity, ActivityTypes } from '@microsoft/agents-activity';
import {
  CopilotStudioClient,
  loadCopilotStudioConnectionSettingsFromEnv
} from '@microsoft/agents-copilotstudio-client';

const settings = loadCopilotStudioConnectionSettingsFromEnv();
const token = await acquireToken(settings); // your MSAL token acquisition
const client = new CopilotStudioClient(settings, token);

// Send a message and stream the response
const activity = new Activity('message');
activity.text = 'What is the return policy?';

for await (const reply of client.sendActivityStreaming(activity)) {
  if (reply.type === ActivityTypes.Message) {
    console.log(reply.text);
  }
}

But we’re not there yet. The SDK client currently requires delegated (user) authentication through Entra ID. No service principal auth, no app-only tokens, no secure anonymous. For B2C scenarios where your customers aren’t authenticating with Entra, this is a non-starter. Support for app-only auth is on the roadmap, and we want it as badly as you do. For now, this pattern works for employee-facing backends where delegated auth is acceptable.

Direct Line over HTTP

If you need to support unauthenticated customers or can’t use the SDK client, you can talk to Direct Line directly over HTTP. For a walkthrough of this approach, see Triggering Copilot Studio Agents with HTTP Calls. Be aware of two things:

  1. Intercepting the stream is painful. Direct Line delivers responses via WebSocket (real-time push) or HTTP polling (1-10 seconds of latency per cycle). If your goal is to sanitize PII or transform content before it reaches the user, you’re building a real-time message router on top of a persistent WebSocket connection (which you’d want to avoid). With polling, the architecture is simpler but the latency adds up fast.
  2. There’s no “last message” concept. Direct Line models a conversation where either party can send messages at any time. There’s no built-in signal that says “the agent is done responding.” Some customers work around this by embedding a “last message” signal in channelData, but that’s a convention you have to build and maintain yourself.

When to use this: When you need a server-side layer between your users and the agent for sanitization, compliance, or custom rendering. Use the SDK client if your users authenticate with Entra ID, or Direct Line over HTTP for anonymous and non-Entra scenarios.

Back to wizard ↑


What’s Next

Each section above gives you enough to get started, but there’s always more to dig into: token refresh strategies, error handling patterns, production deployment considerations. If you want a deeper dive on any specific path, let me know in the comments.

What are you building? Did the wizard point you in the right direction, or is your scenario missing from the tree?

Further Reading

This post is licensed under CC BY 4.0 by the author.