Forum Discussion

viswaaa's avatar
viswaaa
Icon for Helper IV rankHelper IV
8 months ago
Solved

Feature Usage and Adoption symantic model report

Hi All,

 

I need to created a report with Feature Usage and Adoption symantic model where I need to show workspaces and reports in my org and it should be dynamic.

I connected with Adoption symantic model from Power Bi desktop  and for some reason other users are unable to see as we moved to Fabric capacity license.

 

Is there any other alternate to do this like by using some API's or anything.

Please suggest.

 

 

  • Hi viswaaa

     

    I can't build a full solution for you, but here's something to get you started. 

     

    from sempy.fabric import FabricRestClient
    from urllib.parse import urlencode
    import pandas as pd
    
    client = FabricRestClient()  # Auth tokens are acquired from the Fabric execution context. 
    
    def paged_get(path: str, params: dict | None = None) -> list[dict]:
        """
        Calls a Fabric REST API GET endpoint that returns:
          { "value": [...], "continuationToken": "...", "continuationUri": "..." }
        and keeps fetching until all pages are retrieved.
        """
        all_rows = []
        continuation = None
        params = dict(params or {})
    
        while True:
            q = dict(params)
            if continuation:
                q["continuationToken"] = continuation
    
            url = path + (("?" + urlencode(q)) if q else "")
            resp = client.get(url)
            resp.raise_for_status()
    
            payload = resp.json()
            all_rows.extend(payload.get("value", []))
    
            continuation = payload.get("continuationToken")
            if not continuation:
                break
    
        return all_rows
    
    def list_workspaces(roles: list[str] | None = None) -> list[dict]:
        # roles example: ["Admin","Member","Contributor","Viewer"] 
        params = {}
        if roles:
            params["roles"] = ",".join(roles)
        return paged_get("/v1/workspaces", params=params)
    
    def list_reports_in_workspace(workspace_id: str, recursive: bool = True) -> list[dict]:
        # List Items supports filtering by item type; "Report" is a valid type. 
        params = {
            "type": "Report",
            "recursive": str(recursive)  # API expects boolean; sending "True"/"False" works well in practice
        }
        items = paged_get(f"/v1/workspaces/{workspace_id}/items", params=params)
    
        # Defensive filter in case anything unexpected slips through
        return [i for i in items if i.get("type") == "Report"]
    
    # --- Main ---
    workspaces = list_workspaces()
    rows = []
    
    for ws in workspaces:
        ws_id = ws["id"]
        ws_name = ws.get("displayName")
    
        try:
            reports = list_reports_in_workspace(ws_id, recursive=True)
            for r in reports:
                rows.append({
                    "workspaceId": ws_id,
                    "workspaceName": ws_name,
                    "reportId": r["id"],
                    "reportName": r.get("displayName"),
                    "folderId": r.get("folderId"),
                })
        except Exception as ex:
            # If you ever hit a permissions edge-case, keep going and log it
            rows.append({
                "workspaceId": ws_id,
                "workspaceName": ws_name,
                "reportId": None,
                "reportName": f"ERROR listing reports: {ex}",
                "folderId": None,
            })
    
    df_reports = pd.DataFrame(rows)
    df_reports

    If you found this helpful, consider giving some Kudos. If I answered your question or solved your problem, mark this post as the solution.

     

9 Replies

  • Hi viswaaa

     

    Okay, then you're probably going to want to get workspace details using this endpoint: https://learn.microsoft.com/en-us/rest/api/fabric/admin/workspaces/list-workspaces?tabs=HTTP

     

    That will return workspace details. 

     

    To get reports, you can use the List Items endpoint: 
    https://learn.microsoft.com/en-us/rest/api/fabric/admin/items/list-items?tabs=HTTP

     

    Both of these endpoints are in preview, so if you want to rely on fully released APIs, then it gets a bit messier, you can use getModifiedWorkspaces to get IDs of workspaces that have changed: 
    https://learn.microsoft.com/en-us/rest/api/power-bi/admin/workspace-info-get-modified-workspaces

    (there is no nice way to get all workspace IDs without using the preview APIs)

    then you can use GetGroup to get workspace details: 
    https://learn.microsoft.com/en-us/rest/api/power-bi/groups/get-group

    and then you can use GetReportsInGroup to get the reports: 
    https://learn.microsoft.com/en-us/rest/api/power-bi/reports/get-reports-in-group

     

    If you found this helpful, consider giving some Kudos. If I answered your question or solved your problem, mark this post as the solution.

     

    • viswaaa's avatar
      viswaaa
      Icon for Helper IV rankHelper IV

      Hi tayloramy ,

       

      Thanks for the info.

      Can you please help me how to run these API's in Power BI and automate this process.

      • tayloramy's avatar
        tayloramy
        Icon for Super User rankSuper User

        Hi viswaaa

         

        I can't build a full solution for you, but here's something to get you started. 

         

        from sempy.fabric import FabricRestClient
        from urllib.parse import urlencode
        import pandas as pd
        
        client = FabricRestClient()  # Auth tokens are acquired from the Fabric execution context. 
        
        def paged_get(path: str, params: dict | None = None) -> list[dict]:
            """
            Calls a Fabric REST API GET endpoint that returns:
              { "value": [...], "continuationToken": "...", "continuationUri": "..." }
            and keeps fetching until all pages are retrieved.
            """
            all_rows = []
            continuation = None
            params = dict(params or {})
        
            while True:
                q = dict(params)
                if continuation:
                    q["continuationToken"] = continuation
        
                url = path + (("?" + urlencode(q)) if q else "")
                resp = client.get(url)
                resp.raise_for_status()
        
                payload = resp.json()
                all_rows.extend(payload.get("value", []))
        
                continuation = payload.get("continuationToken")
                if not continuation:
                    break
        
            return all_rows
        
        def list_workspaces(roles: list[str] | None = None) -> list[dict]:
            # roles example: ["Admin","Member","Contributor","Viewer"] 
            params = {}
            if roles:
                params["roles"] = ",".join(roles)
            return paged_get("/v1/workspaces", params=params)
        
        def list_reports_in_workspace(workspace_id: str, recursive: bool = True) -> list[dict]:
            # List Items supports filtering by item type; "Report" is a valid type. 
            params = {
                "type": "Report",
                "recursive": str(recursive)  # API expects boolean; sending "True"/"False" works well in practice
            }
            items = paged_get(f"/v1/workspaces/{workspace_id}/items", params=params)
        
            # Defensive filter in case anything unexpected slips through
            return [i for i in items if i.get("type") == "Report"]
        
        # --- Main ---
        workspaces = list_workspaces()
        rows = []
        
        for ws in workspaces:
            ws_id = ws["id"]
            ws_name = ws.get("displayName")
        
            try:
                reports = list_reports_in_workspace(ws_id, recursive=True)
                for r in reports:
                    rows.append({
                        "workspaceId": ws_id,
                        "workspaceName": ws_name,
                        "reportId": r["id"],
                        "reportName": r.get("displayName"),
                        "folderId": r.get("folderId"),
                    })
            except Exception as ex:
                # If you ever hit a permissions edge-case, keep going and log it
                rows.append({
                    "workspaceId": ws_id,
                    "workspaceName": ws_name,
                    "reportId": None,
                    "reportName": f"ERROR listing reports: {ex}",
                    "folderId": None,
                })
        
        df_reports = pd.DataFrame(rows)
        df_reports

        If you found this helpful, consider giving some Kudos. If I answered your question or solved your problem, mark this post as the solution.

         

  • Hi viswaaa

     

    Only Fabric Admins can see the workspace that contains the feature usage and adoption report by default, if you're building other reports on those models (not recommended as the models will change without notice) you will also need to add those users as viewers in the Admin Monitoring workspace. 

    Ideally you would only grant read permissions on the model, but as this is a special model you do not have the ability to do that, so you need to grant viewer on the workspace which will in turn grant read on the models. 

     

    Most of the data in that report is available from the APIs, most of it can be derived from GetActivityEvents if you're storing that data somewhere. 

     

    If you found this helpful, consider giving some Kudos. If I answered your question or solved your problem, mark this post as the solution. 

  • v-sgandrathi's avatar
    v-sgandrathi
    Icon for Community Support rankCommunity Support

    Hi viswaaa,

     

    Thank you tayloramy for your constant replies for the queries.

    We wanted to check if you had a chance to review our last reply. Let us know if it helped or if you need more guidance, we're always happy to help further.

    Looking forward to hearing from you!

     

    Thank you.

  • v-sgandrathi's avatar
    v-sgandrathi
    Icon for Community Support rankCommunity Support

    Hi viswaaa,

     

    we haven't heard back from you regarding our last response and wanted to check if your issue has been resolved.

    Should you have any further questions, feel free to reach out.
    Thank you for being a part of the Microsoft Fabric Community Forum!