How a Teams Bot Is Wired Together
A Teams bot isn't hosted by Teams itself; it's your own web service (Node.js, C#, or Python) that Azure Bot Service forwards conversations to via a messaging endpoint HTTPS URL. When a user sends a message, Teams posts an Activity object to that endpoint, your CloudAdapter authenticates the request, wraps it in a TurnContext, and routes it into an ActivityHandler subclass where you override methods like onMessageActivity to react. The bot's identity is a Microsoft App ID and secret registered in Azure, and that same App ID is what the manifest's bots array references as botId, tying the Teams app registration to the Azure bot registration.
Cricket analogy: The messaging endpoint receiving forwarded activities is like a stadium's PA announcer relaying the umpire's decision to the crowd; the umpire (Teams) makes the call, but a separate system (your bot service) broadcasts and acts on it.
Handling Conversations and Turns
Each incoming message is one turn, and the ActivityHandler dispatches based on activity.type: onMessageActivity for text, onMembersAddedActivity for when the bot is added to a team, and onTeamsMembersAddedActivity/onTeamsChannelCreatedEvent for Teams-specific events not present in the base Bot Framework. Within a turn, turnContext.sendActivity() replies synchronously in the same conversation, while conversation state (multi-turn context like "which step of a form is the user on") is persisted between turns using a ConversationState object backed by durable storage such as Azure Blob or Cosmos DB, since your bot process may not be the same instance handling the next message.
Cricket analogy: onMembersAddedActivity firing when the bot joins a team is like a new signing's unveiling ceremony at a franchise, a distinct one-time event separate from that player's actual performance in matches.
Proactive Messaging and Notifications
Not every bot message is a reply to user input. To send a notification the user didn't just trigger, such as an approval alert or a scheduled reminder, the bot needs a saved ConversationReference captured from a prior turn (typically in onMembersAddedActivity or the first message), then calls adapter.continueConversationAsync (or CloudAdapter.processProactive in newer SDKs) with that reference to open a new turn and send a message outside any active conversation. This requires the bot to have already been installed for that user or team, since Teams will not deliver a proactive message to someone who has never interacted with the app.
Cricket analogy: Saving a ConversationReference is like a broadcaster keeping a commentator's contact on file so they can be called back for a rain-delay update, without needing the original live feed still running.
import { TeamsActivityHandler, TurnContext, CardFactory } from "botbuilder";
export class HelpdeskBot extends TeamsActivityHandler {
constructor() {
super();
this.onMessage(async (context: TurnContext, next) => {
const text = context.activity.text?.trim().toLowerCase();
if (text === "new ticket") {
await context.sendActivity({
attachments: [CardFactory.adaptiveCard(newTicketCard)]
});
} else {
await context.sendActivity(`I didn't understand "${text}". Try "new ticket".`);
}
await next();
});
this.onMembersAdded(async (context, next) => {
for (const member of context.activity.membersAdded ?? []) {
if (member.id !== context.activity.recipient.id) {
await context.sendActivity("Welcome! Type 'new ticket' to file a request.");
}
}
await next();
});
}
}Test bots locally with the Bot Framework Emulator or (for Teams-specific features like adaptive card actions and SSO) sideload the app into a real Teams client via ngrok or Dev Tunnels, since some Teams channel-specific payloads aren't fully reproducible in the generic emulator.
Proactive messaging fails silently with a 403/404 if the ConversationReference is stale (e.g., the user removed the app) or if the bot was never actually installed for that conversation. Always wrap proactive sends in error handling and consider re-installation prompts rather than assuming delivery succeeded.
- A Teams bot is your own hosted service; Azure Bot Service forwards activities to its messaging endpoint over HTTPS.
- ActivityHandler (or TeamsActivityHandler) methods like onMessage and onMembersAdded are the primary extension points.
- The botId in manifest.json must match the Microsoft App ID from the Azure Bot Service registration.
- ConversationState persists multi-turn context and must use durable storage since bot instances aren't guaranteed sticky.
- Proactive messaging requires a saved ConversationReference and prior app installation for that user or conversation.
- TeamsActivityHandler extends the base ActivityHandler with Teams-specific events like onTeamsMembersAddedActivity.
- Local testing with Bot Framework Emulator won't catch every Teams-specific behavior; sideload for full verification.
Practice what you learned
1. Where does the actual logic of a Teams bot run?
2. What must match between the manifest's bots array and the Azure bot registration?
3. Why does conversation state need to be stored in something like Cosmos DB rather than in-memory?
4. What is required before a bot can successfully send a proactive message to a user?
5. Which method would you override to greet a user the first time the bot is added to a team?
Was this page helpful?
You May Also Like
The Teams App Manifest
The manifest.json file is the declarative blueprint that tells Microsoft Teams who an app is, what it can do, and where it is allowed to run.
Adaptive Cards
Adaptive Cards are a JSON-based UI format for rendering rich, interactive content consistently across bots, tabs, and message extensions in Teams.
Message Extensions
Message extensions let users search external systems or trigger actions directly from the Teams compose box, message context menu, or link previews.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics