Store meeting transcript on SharePoint
Microsoft Teams has great features like automatic recordings and transcripts. It is even possible to download the transcript after the meeting. In this blog I will show you how you can retrieve and store a meeting transcript on SharePoint Online via a Power Automate flow.
Inspiration
I was inspired by the tweet below from Lee Holmes. He showed that it was possible to retrieve the transcript content via PowerShell. And I thought, why not try it via Power Automate as well?
So cool! Recorded Teams meetings have a JSON version of the transcript. You can use PowerShell to find out if you’re consuming all of the air in the room.
Look for the ‘streamContent?format=json’ URL in the DevTools Network tab. pic.twitter.com/8FksKtNqw5
— Lee Holmes (@Lee_Holmes) October 7, 2022
YouTube video
Before you continue reading. I also have a YouTube video about the setup.
Meeting Policies
Transcription is a feature which will be enabled or disabled in one of your Meeting Policies. Double check this before you start with your Power Automate setup.
GET callTranscript content
After reading some several Graph API docs I figured out this would be possible.
The onlineMeeting id can be retrieved via the Get onlineMeeting method and a $filter query parameter and the JoinWebUrl.
After that it is possible to retrieve all transcripts of our meeting with a List transcripts method.
And finally the transcript content can be retrieved in application/vnd.openxmlformats-officedocument.wordprocessingml.document format via the Get callTranscript method.
Lets try and turn this into a working flow!
Flow setup
Checklist before you start:
– This example uses HTTP connector actions which are part of a premium feature, make sure you have a license which covers this.
– The HTTP actions also use an app (with the correct Graph API permissions) in Azure Active Directory for authentication.
1. Add a When an upcoming event is starting soon (V3) action.
a. Select your Calendar Id, in this case Calendar
2. Add a Get my profile (v2) action.
To retrieve my own email for the Author field of the SharePoint page.
3. Add a Initialize variable action.
a. Provide a Name, in this example onlineMeetingId
b. Select a Type, String
c. Leave Value empty
4. Add a second Initialize variable action.
a. Provide a Name, in this example transcriptId
b. Select a Type, String
c. Leave Value empty
5. Add a Condition action.
In this condition the body field within the body is checked for the meetup-join hyperlink. A indexOf function is used. If this is found it will output 1. If it is not found (equal to -1), it will output 0.
a. Use the expression below for the where statement
6. Add a HTTP action (in the If Yes section).
A Get onlineMeeting method from the Graph API is used. In this case specifically with a $filter query parameter and the JoinWebUrl. This is information we can retrieve from the body/body of the event message.
a. Select the GET method
b. Use the URI from the code snippet below
c. Select Active Directory OAuth for the Authentication, provide the details of your Azure AD App.
7. Add a Set Variable action (in the If Yes section).
a. In the Name field select the onlineMeetingId variable
b. In the Value field use the expression from the code snippet below
8. Add a Delay until action (in the If Yes section).
a. In the Timestamp field use the expression from the code snippet below
9. Add a second HTTP action (in the If Yes section).
A List transcripts method is used to retrieve the transcripts of the specific online meeting.
a. Select the GET method
b. Use the URI from the code snippet below
c. Select Active Directory OAuth for the Authentication, provide the details of your Azure AD App.
10. Add a second Set Variable action (in the If Yes section).
a. In the Name field select the transcriptId variable
b. In the Value field use the expression from the code snippet below
11. Add a third HTTP action (in the If Yes section).
A Get callTranscript method is used to retrieve the content of an individual transcripts in the application/vnd.openxmlformats-officedocument.wordprocessingml.document format.
a. Select the GET method
b. Use the URI from the code snippet below
c. Select Active Directory OAuth for the Authentication, provide the details of your Azure AD App.
12. Add a Create File action.
a. Select the Site Address from the dropdown, or use an environment variable (parameter) like me
b. Select a Folder Path, in this example /Shared Documents/Meeting Transcripts
c. Use the expression from the code snippet below for the File Name
d. Use the Body field of the HTTP – Transcript action
That is it for the setup of this example.
Testing Transcription
You can start a transcript from within the More menu option.
When the transcript is started you would see it in the side panel during the meeting.
After the meeting you will see it in the Recordings & Transcripts tab
But also as a file in our specified Document Library
When you open the file you should see something like below
You can now e-mail/share a link to the document. Or potentially process it with an AI model. More on that in a future blog…
For now, Happy testing!
This is great, Dennis! Thanks so much for documenting!
Do you think that the same process could be used to obtain the Attendance reports for meetings? If so, do you know how the process would differ?
@S. Sprague, yes the process would be pretty much the same. I actually have written another blog about this as well: https://www.expiscornovus.com/2022/10/24/share-attendance-directly-after-meeting/
Hi,
Thank you for you tutorial. I seem to be getting this error on the first HTTP
ActionBranchingConditionNotSatisfied. The execution of template action ‘HTTP’ skipped: the branching condition for this action is not satisfied.
Great work Dennis, i think this is the only post online to do this
I am nevertheless struggling with the authentication part keep getting 403 forbidden maybe as ai am trying to access then from zapier (if you know the tool); I will try through power automate and see
i followed you instructions step by step but I keep getting below error at there first API call where all stops
can you tell where I might getting this wrong? thanks for the great effort in your video and blog!
{
“statusCode”: 403,
“headers”: {
“Transfer-Encoding”: “chunked”,
“Vary”: “Accept-Encoding”,
“Strict-Transport-Security”: “removed”,
“request-id”: “removed”,
“client-request-id”: “removed”,
“x-ms-ags-diagnostic”: “removed”,
“scenario-id”: “removed”,
“Date”: “Tue, 26 Mar 2024 18:34:31 GMT”,
“Content-Type”: “application/json”,
“Content-Length”: “198”
},
“body”: {
“error”: {
“code”: “Forbidden”,
“message”: “”,
“innerError”: {
“request-id”: “removed”,
“date”: “2024-03-26T18:34:32”,
“client-request-id”: “removed”
}
}
}
}
Hi Samer,
That first call uses the Get OnlineMeeting method of the Graph API. Have you made sure that the app you registered in Entra Id has the correct permissions?
https://learn.microsoft.com/en-us/graph/api/onlinemeeting-get?view=graph-rest-1.0&tabs=http#permissions
Thanks Dennis
I figured it out, for some reason the formula to pick the teams url was generating a faulty link (including more text); i replaced it by two compose steps removing text before the link and then after the first “ and now it works 🙂
Now stuck with creating the file as the $format part which i reconfirmed from ms docs is generating an error, i tried it in header with the ‘accept’ header and same as value and in the uri as you did and it is giving an error everytime
Looking for some third party to convert transcript data body to .docx
By the way what you did is super! Might be the only comprehensive guide on this on the internet
@Dennis – nice one.
I’m struggling to get Step 6b working – seems to be an issue with:
https://graph.microsoft.com/v1.0/users/@{outputs(‘Get_my_profile_(V2)’)?[‘body/id’]}/onlineMeetings?$filter=JoinWebUrl eq ‘@{if(equals(indexOf(triggerOutputs()?[‘body/body’], ‘https://teams.microsoft.com/l/meetup-join/’), -1), ‘No Teams Meeting’, concat(‘https://teams.microsoft.com/l/meetup-join/’, slice(split(split(triggerOutputs()?[‘body/body’], ‘https://teams.microsoft.com/l/meetup-join/’)[1], ‘class’)[0], 0, -2)))}’
Has Microsoft changed something so this is broken now OR is it me? Anyone else having issues extracting the MeetingID ?
Thanks
@Dennis – can you share the full string URI being used in HTTP? Mine is kicking back that HTML is invalid and HTML tags and formatting need to be removed. URLs should only contain URL data not HTML coding.
Do you need to be invited to the meeting for you to be able to get the transcript? I need meeting transcripts to be downloaded so I can use Co-Pilot to generate meeting notes for a wide range of meetings, I wouldn’t necessarily be invited to these meetings but would need the transcripts to be stored somewhere for Co-Pilot to reference.
I am thinking that creating a service account that can be invited to all required meetings would allow me to create the flow under the service account and access the transcripts, would this be the correct approach?
Hi Ali,
Good question. I have only tested it with meetings where I was either the organizer or an attendee.
But yes, I would say that service account approach should work. Let me know about your progress or if you have any other challenges with this setup.
Hi Dennis, yes unfortunately I’m getting the following error when I try to test – No application access policy found for this app.
I created an App in azure with the following permissions granted
OnlineMeetings.Read
OnlineMeetings.Read.All
I have now ran the following command in Power shell
New-ApplicationAccessPolicy -AppId ‘xxxx’ -PolicyScopeGroupId ‘Ali.Muayad@xxx.xxx.uk’ -AccessRight RestrictAccess -Description “Restrict app to Ali ”
But I still get the same error, am I missing something? If you have documentation on how you set up the app in Azure that would be really helpful. To add. the Tenant, Client ID and Secret are all values I got from the Azure App overview
Hi Ali,
Have you also granted the policy to the user? The steps for this policy setup can be found in this Microsoft document:
https://learn.microsoft.com/en-us/graph/cloud-communication-online-meeting-application-access-policy#configure-application-access-policy
Hi Dennis, Yes I’m just having trouble creating the file at the moment, the 3rd HTTP request has issues with the format
{
“error”: {
“code”: “BadRequest”,
“message”: “Invalid format ‘application/vnd.openxmlformats-officedocument.wordprocessingml.document’ specified.”,
Can you try the ?$format=text/vtt instead?
Looks like Microsoft have deprecated that docx format in this specific method:
https://learn.microsoft.com/en-us/graph/api/calltranscript-get?view=graph-rest-beta&tabs=http#examples
Hi Dennis, not sure how I didn’t see that but yes /vtt worked, I had to create a Word template, compose the vtt output, populate the word template with the compose output and then save in sharepoint as a new file. Thanks very much for your assistance with this I learned a lot, if you think that it can be achieved in less steps than I mentioned it would be great to know how.
Hi Ali,
Great to hear that it worked and thanks for your nice feedback, appreciate it 🙂
Thanks Dennis for pulling this together, we have been able to set up the flow to do this and the results are great !! We have created a record in SharePoint where we are storing the transcript text and then we are also running it through Google Gemini to get a summary and also storing that as well. We tried to get the summary using Copilot but it could not handle the transcript from a 1 hour meeting. Hopefully the following will be going GA soon so we can really start using this
https://graph.microsoft.com/beta/users/@{outputs(‘Get_my_profile_(V2)’)?[‘body/id’]}/onlineMeetings/@{variables(‘onlineMeetingId’)}/transcripts/@{variables(‘transcriptId’)}/content?$format=application/vnd.openxmlformats-officedocument.wordprocessingml.document
Thanks again !!
Hi Gerard,
Great to hear this was useful for you, happy to share it.
I have been doing some testing with this and it has been working great. Today I just received the message below. I was wondering what kind of billing plan some other folks have implemented in order to be able to download transcripts for their organizations:
Evaluation capacity for the month has exceeded. To continue beyond the evaluation limits complete billing onboarding. Visit https://docs.microsoft.com/en-us/graph/teams-licenses for API specific requirements.
Thanks !!
Hello Dennis,
Thank you for this informative blog! I am actually getting a bad request at the first GET Action. The output coming from the initial workflow trigger is coming in an HTML format and the HTTP trigger is apparently using a wrong URI such as the following:
https://graph.microsoft.com/v1.0/users/12345-678-9012-a15a-25428b58/onlineMeetings?$filter=JoinWebUrl eq ‘https://teams.microsoft.com/l/meetup-join/19%3ameeting_ZmMwLTk1ZjgtNmI37wr4ZTJkZDQz%40thread.v2/0?context=%7b%22Tid%22%3a%222da697b3-7qtr-4a85-8act-e6bafd2a7ate%22%2c%22Oid%22%3a%221234567r-f678-4567-8910-12345678912345%22%7d” id=”meet_invite_block.action.join_link” title=”Meeting join link’
I guess the problem is with the URL encoding where the id is not getting populated. id=”meet_invite_block.action.join_link” title=”Meeting join link’
I appreciate your help. Cheers!
Hi Bassel,
I see you filter contains a link which has some html attributes at the end of the string (id & title). My suggestion would be to trim that part. You can use a split function for that.
first(split(variables('YourJoinWebUrlLink'), '" id='))
Thank you so much, Dennis, worked just as expected! I am at the end of the flow now and getting another error related to the .docs file format. When the flow reaches the HTTP Transcript step, I am getting a Bad request. The output of the action is: {
“error”: {
“code”: “BadRequest”,
“message”: “Invalid format ‘application/vnd.openxmlformats-officedocument.wordprocessingml.document’ specified.”,
“innerError”: {
“date”: “2024-06-02T20:08:13”
}
}
}
It seems there’s a problem with the file format. Based on the Microsoft documentation (https://learn.microsoft.com/en-us/microsoftteams/platform/graph-api/meeting-transcripts/api-transcripts), adding an ‘Accept’ Header with “application/vnd.openxmlformats-officedocument.wordprocessingml.document” Value should get the callTranscript content in .docs format but unfortunately, this didn’t work either. Any suggestions, please?
Thanks!
Hi Bassel,
Yes, this error was mentioned by Ali, earlier in the comments. I will also update my post shortly to highlight this deprecation.
Microsoft have deprecated that docx format in the Get CallTranscript method:
https://learn.microsoft.com/en-us/graph/api/calltranscript-get?view=graph-rest-beta&tabs=http#examples.
Can you try the ?$format=text/vtt instead?
Hi Dennis,
This is so awesome. Just wanted to say thank you for sharing. I was doing the same thing and the format transcript step had me completely stumped. Still haven’t seen anything else online around this and it’s 2 years old!
Have a blog suggestion for you. I have had a lot of interest for reposting AI Summary notes from meetings back into the meeting chat. Currently Teams pro license allows you to get them, but obviously only for those that have the licence. I was looking at your method as a way of getting transcript to do it automatically, but feel like I am reinventing the whel. Fun mission though 🙂