Download Transcript option in Botframework v4

This is a whistle stop tour for adding a method to allow the user to download their transcript.

Automatically record the transcript

You need to add the built-in transcript services. In this example I’ll use the In-Memory store, you’ll want to evaluate the others for production code. Add this to the startup.cs

var memoryTranscriptStore = new MemoryTranscriptStore();
options.Middleware.Add(new TranscriptLoggerMiddleware(memoryTranscriptStore));

Next we’ll create a component to expose the ITranscriptStore (memoryTranscriptStore) to the dialog context. We’ll do that via our own middleware;

public class TranscriptProvider : IMiddleware
    private readonly ITranscriptStore transcriptStore;

    public TranscriptProvider(ITranscriptStore transcriptStore)
        this.transcriptStore = transcriptStore;

    public async Task OnTurn(ITurnContext context, MiddlewareSet.NextDelegate next)
        await next();

Now add this to the startup middleware;

options.Middleware.Add(new TranscriptProvider(memoryTranscriptStore));

Download the transcript

The middleware will now capture all the activity traffic too and from the bot and user. We can add a simple mechanism to request the transcript file. In your bot’s OnTurn method we can hardcode a ‘Transcript’ message/command;

if (context.Activity.Text.Equals("Transcript", StringComparison.InvariantCultureIgnoreCase))
    var transcriptStore = context.Services.Get();
    var transcripts = await transcriptStore.GetTranscriptActivities(context.Activity.ChannelId, context.Activity.Conversation.Id);

    var transcriptContents = new StringBuilder();
    foreach (var transcript in transcripts.Items.Where(i => i.Type == ActivityTypes.Message))
        transcriptContents.AppendLine((transcript.From.Name == "Bot" ? "\t\t" : "") + transcript.AsMessageActivity().Text);

    byte[] bytes = StringToBytes(transcriptContents.ToString());

    var contentType = "text/plain";
    var attachment = new Attachment
        Name = "Transcript.txt",
        ContentUrl = $"data:{contentType};base64,{Convert.ToBase64String(bytes)}",
        ContentType = contentType

    var activity = MessageFactory.Attachment(attachment);
    await context.SendActivity(activity);

private byte[] StringToBytes(string transcriptToSend)
    byte[] bytes = new byte[transcriptToSend.Length * sizeof(char)];
    System.Buffer.BlockCopy(transcriptToSend.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;

When your user types in ‘Transcript’ they’ll be provided with a download attachment called ‘Transcript.txt’.

Production Ready

The above code is great for early testing but you should probably consider using the Download Activity Type and providing a URL to the full transcript. The above code has a nasty weakness in that it must fit inside the maximum reply payload for the bot, ~94K. You could just truncate the body but I’ll leave that up to you. Note, as of writing the emulator has an issue where it will allow you to click on the download but then it gets into a pickle and launches Windows Store. If you try this on a webchat it works fine.