ConversationBot doesn't detect installations or members (Teams App Express Server Typescript)

Senjuti Kundu 0 Reputation points
2025-04-30T14:54:18.7766667+00:00

I have a Multitenant Microsoft Teams app, written as an Express App in Typescript, that uses a ConversationBot. I'm trying to track members who have installed the Teams app but am getting zero results. So far I've tried:

I'm able to track onTeamsMemberAddedEvent, onMembersAddedActivity and on InstallationUpdateActivity. I initialize my ConversationBot as:


const config = {
  MicrosoftAppId: process.env.BOT_ID || process.env.MicrosoftAppId,
  MicrosoftAppType: process.env.BOT_TYPE || process.env.MicrosoftAppType,
  MicrosoftAppTenantId: process.env.MicrosoftAppTenantId,
  MicrosoftAppPassword: process.env.BOT_PASSWORD || process.env.MicrosoftAppPassword,
};

const notificationApp = new ConversationBot({
  adapterConfig: {
    ...config
  },
  notification: {
    enabled: true,
  },
});

This is my TeamsBot class:


class TeamsBot extends TeamsActivityHandler {
  constructor() {
      super();

	this.onTeamsMembersAddedEvent(async (membersAdded: ChannelAccount[], teamInfo: TeamsInfo, context: TurnContext, next: () => Promise<void>): Promise<void> => {...}
	this.onMembersAddedActivity(async (context, next) => {...}
	this.onTeamsMembersAddedEvent(async (membersAdded: ChannelAccount[], teamInfo: TeamsInfo, context: TurnContext, next: () => Promise<void>): Promise<void> => {...}

 });
  }
// This fails
  async getPagedMembers(context) {
      console.log('[TeamsBot] Starting to get paged members');
      let continuationToken;
      const members = [];

      do {
          console.log('[TeamsBot] Fetching page of members:', {
              continuationToken: continuationToken ? 'present' : 'none'
          });
          const page = await TeamsInfo.getPagedMembers(
              context,
              100,
              continuationToken
          );

          continuationToken = page.continuationToken;
          members.push(...page.members);
          console.log('[TeamsBot] Retrieved page of members:', {
              count: page.members.length,
              hasMore: !!continuationToken
          });
      } while (continuationToken !== undefined);

      console.log('[TeamsBot] Completed getting all members:', {
          totalCount: members.length,
          members: JSON.stringify(members, null, 2)
      });
      return members;
  }
}

This is how I initialize my server and /api/messages:


const server = expressApp.listen(process.env.port || process.env.PORT || 3978)
expressApp.post("/api/messages", async (req, res) => {
  await notificationApp.requestHandler(req, res, async (context) => {
    await teamsBot.run(context);
  });
});

These are the parts of the code that I use to find all members and paged installations:

// Fails
const pageSize = 100;
    let continuationToken: string | undefined = undefined;
    let totalInstallations = 0;
    const installationTypes: Record<string, number> = {};
    const allMembers: any[] = [];
    const allTeams: any[] = [];
    do {
      const pagedData = await notificationApp.notification.getPagedInstallations(
        pageSize,
        continuationToken
      ) || { data: [] };
      
      const installations = pagedData.data;
      continuationToken = pagedData.continuationToken;
      for (const installation of installations) {
          totalInstallations++;
          installationTypes[type] = (installationTypes[type] || 0) + 1;
          // Get members for this installation
          try {
            const membersData = await installation.getPagedMembers(pageSize);
            if (membersData?.data?.length > 0) {
              allMembers.push(...membersData.data);
            } 
          } catch (memberError) {
          ...
          }
    } while (continuationToken);

//Fails -> cannot detect any member emails
    const members = await notificationApp.notification.findAllMembers(
      async (member) => {
        logToAzure(`📝 Evaluating member: ${member.account.email}`);
        return true;
      }
    );
    

The relevant section of my manifest.json:


  "bots": [
    {
      "botId": "${{BOT_ID}}",
      "scopes": [
        "personal"
      ],
      "supportsFiles": false,
      "isNotificationOnly": false
    }
  ],
  "composeExtensions": [],
  "configurableTabs": [],
  "staticTabs": [],
  "permissions": [
    "identity",
    "messageTeamMembers"
  ],
  "authorization": {
    "permissions": {
      "resourceSpecific": [
      ]
    }
  },
  "validDomains": [
    "${{BOT_DOMAIN}}", "token.botframework.com"
  ]

This is my teamsapp.yml

version: v1.7
environmentFolderPath: ./env
provision:
  # Creates a Teams app
  - uses: teamsApp/create
    with:
      name: ${{APP_NAME}}
    writeToEnvironmentFile:
      teamsAppId: TEAMS_APP_ID
  - uses: botAadApp/create 
    with:
      name: ${{APP_NAME}}-${{APP_NAME_SUFFIX}}
    writeToEnvironmentFile:
      botId: BOT_ID
      botPassword: SECRET_BOT_PASSWORD
  - uses: arm/deploy 
    with:
      subscriptionId: ${{AZURE_SUBSCRIPTION_ID}}
      resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}}
      templates:
        - path: ./infra/azure.bicep 
          parameters: ./infra/azure.parameters.json
          deploymentName: Create-resources-for-bot
  - uses: teamsApp/validateManifest
    with:
      manifestPath: ./appPackage/manifest.json
  - uses: teamsApp/zipAppPackage
    with:
      manifestPath: ./appPackage/manifest.json
      outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
      outputFolder: ./appPackage/build
  - uses: teamsApp/validateAppPackage
    with:
      # Relative path to this file. This is the path for built zip file.
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
  - uses: teamsApp/update
    with:
      # Relative path to this file. This is the path for built zip file.
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
deploy:
  # Run npm command
  - uses: cli/runNpmCommand
    name: install dependencies
    with:
      args: install
    
  - uses: cli/runNpmCommand
    name: build app
    with:
      args: run build --if-present
      
  - uses: azureAppService/zipDeploy
    with:
      artifactFolder: .
      ignoreFile: .appserviceignore
      resourceId: ${{BOT_AZURE_APP_SERVICE_RESOURCE_ID}}
      
  - uses: file/createOrUpdateEnvironmentFile
    with:
      target: env/.env.dev
      envs:
        MicrosoftAppId: ${{BOT_ID}}
        MicrosoftAppPassword: ${{SECRET_BOT_PASSWORD}}
        BOT_ID: ${{BOT_ID}}
        BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}}
        BOT_TYPE: 'MultiTenant'
        BOT_DOMAIN: ${{BOT_DOMAIN}}
publish:
  - uses: teamsApp/validateManifest
    with:
      manifestPath: ./appPackage/manifest.json
  - uses: teamsApp/zipAppPackage
    with:
      manifestPath: ./appPackage/manifest.json
      outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
      outputFolder: ./appPackage/build
  - uses: teamsApp/validateAppPackage
    with:
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
  - uses: teamsApp/update
    with:
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
  - uses: teamsApp/publishAppPackage
    with:
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
    writeToEnvironmentFile:
      publishedAppId: TEAMS_APP_PUBLISHED_APP_ID
projectId: ${{PROJECT_ID}}

I've been following the Microsoft guide to creating a Teams Conversation bot. At this point, I'm not sure how to detect installations (I always. get0 installations). My ultimate purpose is to message members who have installed the app, who have specific email addresses, when I had an endpoint on my Express app where the request contains a member's email address. I'm open to any recommendations where I can track the email addresses of all members who have the app currently installed. I have an app registration on the Azure portal but I haven't added any specific API permissions to it. In my resource group, I have an Azure bot, an App Service and an App Service Plan.

Microsoft Teams Development
Microsoft Teams Development
Microsoft Teams: A Microsoft customizable chat-based workspace.Development: The process of researching, productizing, and refining new or existing technologies.
3,868 questions
{count} votes

Your answer

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