Share via

Azure Bot joins ghost Teams meeting instead of the real one

Daniel Saner 65 Reputation points
2026-02-24T12:00:03.4166667+00:00

Hello,

I'm trying to implement a Teams meeting bot using the Azure Bot service, controlled from a C# .NET 10 application using the Graph Communications API. The bot is supposed to join specific Teams meetings where it will post chat messages and play audio prompts. I'm having very confusing and frustrating issues with getting the bot to join meetings.

When I give my bot application a Teams online meeting join URL, it's supposed to join it using its Azure Bot identity through the AddAsync() call in the ICallCollection of the ICommunicationsClient.

ICall call = await communicationsClient.Calls().AddAsync(joinParameters).ConfigureAwait(false);

I extract the joinParameters with ChatInfo and OrganizerMeetingInfofrom the Teams meeting join URL like this (some parsing details omitted):

Uri joinUrl = new("https://teams.microsoft.com/l/meetup-join/19%3ameeting_.....");string[]? segments = joinUrl.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries);string threadId = Uri.UnescapeDataString(segments[^2]);ChatInfo chatInfo = new() { ThreadId = threadId };Identity organizerIdentity = new() { Id = organizerId };organizerIdentity.SetTenantId(tenantId);OrganizerMeetingInfo meetingInfo = new() { Organizer = new IdentitySet { User = organizerIdentity } };

The call succeeds and the client returns a call ID. I can send commands to this client to play audio prompts, etc.

However, if I'm in this meeting myself when the bot joins, I don't see the bot. Even after minutes of waiting, it will not show up. If I leave the meeting and immediately rejoin, it's still not there. Only if I leave, wait around 30 seconds or more, and then rejoin, I can see the bot. However, now I seem to be in a completely separate call (but joined from the same join URL!) I verified this by testing with multiple people. The same Teams online meeting now has two calls. The bot always joins a separate one, and people have to leave, wait, and rejoin before they join the other, "ghost" or "phantom" meeting with the bot in it.

The reason why I call it a ghost or phantom meeting is that, while it's reached through the same join URL as the real meeting, the call doesn't have a meeting ID or short join URL. That is, if in the Teams client I click "Meeting info" in the first call, I get the usual information with a short join URL, meeting ID and passcode. But if I leave and use the same join URL to join the meeting again after the bot has joined, I land in a different call which, when I open the "Meeting info" pane, shows no information at all. There is no join link and no meeting ID.

If I reverse the order and let the bot open the online meeting by joining first, before any human participants, later human joiners will land in the call with the bot in it, the one without any join URL or meeting ID.

But this isn't robust enough. I want the bot to be able to join meetings even if they are already in progress and, going by the documentation, that shouldn't be an issue. Also, I'm fairly sure that these "ghost meetings" are an issue on the Teams infrastructure and shouldn't exist. They have no URL, no meeting ID, and now we have the situation that different people join a meeting using the same join URL but end up in separate calls, not seeing each other. (I've had the case where external users I invited to such a call ended up in the waiting room of call instance A, but when I clicked the notification, I was just sent back to call instance B where I was in with the bot, with no option to see or admit the guest participant).

How can I prevent this from happening?

Microsoft Teams | Development
Microsoft Teams | Development

Building, integrating, or customizing apps and workflows within Microsoft Teams using developer tools and APIs

{count} votes

Answer accepted by question author
  1. Amanda Zhu 80 Reputation points
    2026-03-07T21:34:50.5566667+00:00

    What you’re seeing is most likely a meeting-coordinates mismatch, not a supported “second live view” of the same active meeting. Microsoft’s cloud communications flow says callers join a meeting through the meeting coordinates, and the create call API is explicit that, for a scheduled Teams meeting, you need thread ID, message ID, organizer ID, and tenant ID. In your snippet you only build chatInfo.threadId plus organizerMeetingInfo, so you are not supplying the full documented join coordinates.

    The fix is to stop reconstructing coordinates from the URL path and instead resolve the join link to the canonical meeting object first. Microsoft documents retrieving an online meeting by joinWebUrl with an app token, which is the safest way to get the exact chatInfo and organizer data for the real meeting instance. Then pass the returned chatInfo including messageId, plus the returned organizer identity and tenant, into Calls().AddAsync(...). That removes the ambiguity that can land the bot in a separate call context with no normal meeting info surface in Teams.

    Two checks are worth doing. First, log the exact threadId, messageId, organizer user ID, and organizer tenant ID you send to AddAsync, and verify they came from onlineMeeting rather than URL parsing or a cached organizer record. Second, verify the bot is registered as a Teams calling bot and has the app permissions required by the calling bot setup and Calls.JoinGroupCall.All, because permission or registration gaps can make call state debugging much harder.

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.