Debug a bot with inspection middleware
APPLIES TO: SDK v4
This article describes how to debug a bot using inspection middleware. This feature allows the Bot Framework Emulator to debug traffic into and out of the bot in addition to looking at the current state of the bot. You can use a trace message to send data to the Emulator and then inspect the state of your bot in any given turn of the conversation.
We use an EchoBot built locally using the Bot Framework v4 Create a bot to show how to debug and inspect the bot's message state. You can also Debug a bot using IDE or Debug with the Bot Framework Emulator, but to debug state you need to add inspection middleware to your bot. The Inspection bot samples are available here: C#, JavaScript, Java and Python.
Prerequisites
- Download and install the Bot Framework Emulator
- Knowledge of bot Middleware
- knowledge of bot Managing state
- Download and install ngrok (if you want to debug a bot configured in Azure to use additional channels)
Update your Emulator to the latest version
Before using the bot inspection middleware to debug your bot, you need to update your Emulator to be version 4.5 or newer. Check the latest version for updates.
To check the version of your Emulator, select Help > About in the menu. You will see the current version of your Emulator.

Update your bot's code
Set up the inspection state and add the inspection middleware to the adapter in the Startup.cs file. The inspection state is provided through dependency injection. See the code update below or refer to the inspection sample here: C#.
Startup.cs
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient().AddControllers().AddNewtonsoftJson();
services.AddSingleton<IStorage, MemoryStorage>();
// The Inspection Middleware needs some scratch state to keep track of the (logical) listening connections.
services.AddSingleton<InspectionState>();
// You can inspect the UserState
services.AddSingleton<UserState>();
// You can inspect the ConversationState
services.AddSingleton<ConversationState>();
// Create the Bot Framework Authentication to be used with the Bot Adapter.
services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();
// Create the Bot Adapter with error handling enabled.
services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithInspection>();
AdapterWithInspection.cs
{
public AdapterWithInspection(BotFrameworkAuthentication auth, IConfiguration configuration, InspectionState inspectionState, UserState userState, ConversationState conversationState, ILogger<IBotFrameworkHttpAdapter> logger)
: base(auth, logger)
{
// Inspection needs credentials because it will be sending the Activities and User and Conversation State to the emulator
var credentials = new MicrosoftAppCredentials(configuration["MicrosoftAppId"], configuration["MicrosoftAppPassword"]);
Use(new InspectionMiddleware(inspectionState, userState, conversationState, credentials));
OnTurnError = async (turnContext, exception) =>
{
// Log any leaked exception from the application.
logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");
// Send a message to the user
await turnContext.SendActivityAsync("The bot encountered an error or bug.");
await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code.");
// Send a trace activity, which will be displayed in the Bot Framework Emulator
await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError");
};
}
}
}
Update the bot class in the EchoBot.cs file.
EchoBot.cs
private readonly ConversationState _conversationState;
private readonly UserState _userState;
public EchoBot(ConversationState conversationState, UserState userState)
{
_conversationState = conversationState;
_userState = userState;
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
await base.OnTurnAsync(turnContext, cancellationToken);
await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
var conversationStateProp = _conversationState.CreateProperty<CustomState>("customState");
var convProp = await conversationStateProp.GetAsync(turnContext, () => new CustomState { Value = 0 }, cancellationToken);
var userStateProp = _userState.CreateProperty<CustomState>("customState");
var userProp = await userStateProp.GetAsync(turnContext, () => new CustomState { Value = 0 }, cancellationToken);
await turnContext.SendActivityAsync(MessageFactory.Text($"Echo: {turnContext.Activity.Text} conversation state: {convProp.Value} user state: {userProp.Value}"), cancellationToken);
convProp.Value++;
userProp.Value++;
}
Test your bot locally
After updating the code you can run your bot locally and test the debugging feature using two Emulators: one to send and receive messages, and the other to inspect the state of messages in debugging mode. To test your bot locally take the following steps:
Navigate to your bot's directory in a terminal and execute the following command to run your bot locally:
dotnet runOpen your Emulator. Select Open Bot. Fill in Bot URL with
http://localhost:3978/api/messagesand the MicrosoftAppId and MicrosoftAppPassword values. If you have a JavaScript bot you can find these values in your bot's .env file. If you have a C# bot you can find these values in the appsettings.json file. For a Java bot you can find these values in the application.properties file. Select Connect.Now open another Emulator window. This second Emulator window will work as a debugger. Follow the instructions as described in the previous step. Check Open in debug mode and then click Connect.
At this point you will see a command with a unique identifier (
/INSPECT attach <identifier>) in your debugging Emulator. Copy the whole command with the identifier from the debugging Emulator and paste it into the chat box of the first Emulator.Note
A unique identifier is generated every time when the Emulator is launched in debug mode after you add the inspection middleware in your bot's code.
Now you can send messages in the chat box of your first Emulator and inspect the messages in the debugging Emulator. To inspect the state of the messages click Bot State in the debugging Emulator and unfold values on the right JSON window. You will see the state of your bot in the debugging Emulator:

Inspect the state of a bot configured in Azure
If you want to inspect the state of your bot configured in Azure and connected to channels (like Teams) you will need to install and run ngrok.
Run ngrok
At this point you have updated your Emulator to the latest version and added the inspection middleware in your bot's code. The next step is to run ngrok and configure your local bot to your Azure Bot Channels Registration. Before running ngrok you need to run your bot locally.
To run your bot locally do the following:
Navigate to your bot's folder in a terminal and set your npm registration to use the latest builds
Run your bot locally. You will see your bot expose a port number like
3978.Open another command prompt and navigate to your bot's project folder. Run the following command:
ngrok http 3978ngrok is now connected to your locally running bot. Copy the public IP address.

Update channel registrations for your bot
Now that your local bot is connected to ngrok you can configure your local bot to your Bot Channels Registration in Azure.
Go to your Bot Channels Registration in Azure. Click Settings on the left menu and set the Messaging endpoint with your ngrok IP. If necessary add /api/messages after the IP address. For example,
https://e58549b6.ngrok.io/api/messages. Check Enable Streaming Endpoint and Save.
Tip
If Save is not enabled, you can uncheck Enable Streaming Endpoint and click Save, then check Enable Streaming Endpoint and click Save again. You need to make sure that Enable Streaming Endpoint is checked and the configuration of the endpoint is saved.
Go to your bot's resource group, click Deployment, and select your Bot Channels Registration that previously deployed successfully. Click Inputs on the left side to get the appId and appSecret. Update your bot's .env file (or appsettings.json file if you have a C# bot) with the appId and appSecret.

Start your Emulator, select Open Bot, and put
http://localhost:3978/api/messagesin the Bot URL. Fill Microsoft App ID and Microsoft App password with the same appId and appSecret you added to our bot's .env (appsettings.json) file. Then select Connect.Your running bot is now connected to your Bot Channels Registration in Azure. You can test the web chat by clicking Test in Web Chat and sending messages in the chat box.

Now let's enable the debugging mode in the Emulator. In your Emulator select Debug > Start Debugging. Enter the ngrok IP address (don't forget to add /api/messages) for the Bot URL (for example,
https://e58549b6.ngrok.io/api/messages). For Microsoft App ID, enter your bot's app ID. For Microsoft App password, enter your bot's app secret. Make sure Open in debug mode is checked as well. Click Connect.When the debugging mode is enabled a UUID will be generated in your Emulator. A UUID is a unique ID generated every time you start the debugging mode in your Emulator. Copy and paste the UUID to the Test in Web Chat chat box or your channel's chat box. You will see the message "Attached to session, all traffic is being replicated for inspection" in the chat box.
You can start debugging your bot by sending messages in the configured channel's chat box. Your local Emulator will automatically update the messages with all the details for debugging. To inspect your bot's state of messages click Bot State and unfold the values in the right JSON window.

Additional resources
- Try the inspection middleware bot sample in C#, JavaScript, or Python .
- Read troubleshoot general problems and the other troubleshooting articles in that section.
- Read the how to Debug with the Emulator article.