# Programmatically Control Copilot access for semantic models

In the flood of announcements at FabCon Barcelona, you may have missed this feature our customers and users have been asking for - controlling Copilot/AI access to semantic models. Previously, if you had a semantic model which has not been prepared for AI, a user could still use it in Copilot or data agent which can affect response accuracy and experience. Now you can control if *read-only users* can see/use a semantic model in Copilot or data agent.

You can watch the demo by my colleague Jacinda Eng below:

%[https://youtu.be/8f_PrrtbIOM?si=PlVCJ2UoZqJw0BZy&t=1214] 

If you have write permissions to the semantic model, you can toggle it on/off in the semantic model settings.

![](https://cdn.hashnode.com/uploads/covers/619d4cccfa52cd31fe52d25d/0e265c19-0c6b-47f8-b5b3-8b701167894a.png align="center")

Read the [documentation](https://learn.microsoft.com/en-us/power-bi/create-reports/copilot-semantic-models#control-copilot-access-for-semantic-models) for more details.

## Programmatic approach

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">🚨<strong>Below I use an internal API which can change at any point</strong></div>
</div>

If you have write access to the semantic model, you can use SemPy to toggle this setting in a Fabric notebook.

```python
import sempy.fabric as fabric
from sempy.fabric import PowerBIRestClient


def build_client():
    """A client that takes a fresh notebook token on every request.

    The settings endpoint rejects sempy's default credential with a 401, so the
    token has to come from notebookutils explicitly.
    """
    try:
        import notebookutils  # noqa: F401
        import base64
        import json
        from azure.core.credentials import AccessToken

        class Cred:
            def get_token(self, *scopes, **kwargs):
                token = notebookutils.credentials.getToken("pbi")
                payload = token.split(".")[1]
                payload += "=" * (-len(payload) % 4)
                exp = int(json.loads(base64.urlsafe_b64decode(payload))["exp"])
                return AccessToken(token, exp)

        return PowerBIRestClient(credential=Cred())
    except ImportError:
        return PowerBIRestClient()


client = build_client()


def allow_copilot_for_readers(workspace, dataset, allow=True, apply_changes=False):
    """Read or update whether read-only users may use Copilot on one model.
    apply_changes=False: return the current setting, changing nothing.
    apply_changes=True: allow=True lets readers use Copilot (portal toggle, allow=False blocks it (toggle Off).

    
    """
    workspace = fabric.resolve_workspace_name(workspace)
    dataset = fabric.resolve_dataset_name(dataset, workspace)

    item = fabric.get_item(
        dataset,
        item_type="SemanticModel",
        workspace=workspace,
        return_dataframe=False,
    )
    body = client.get(
        f"https://api.powerbi.com/v1.0/myorg/groups/{item['workspaceId']}/datasets"
    ).json()
    cluster = body["@odata.context"].split("/v1.0")[0]

    meta = client.get(f"{cluster}/metadata/models/{item['id']}").json()
    model = meta["model"]
    switches = meta.get("featureSwitches") or {}
    result = {
        "workspace": workspace,
        "model": dataset,
        "settings": f"{cluster}/metadata/models/{model['id']}/settings",
        "allowCopilotForReaders": switches.get("restrictCopilotForReaders"),
        "status": "read",
        "detail": "" if "restrictCopilotForReaders" in switches else "not in featureSwitches",
    }

    if apply_changes:
        try:
            client.post(
                result["settings"],
                json={"restrictCopilotForReaders": not allow},
            )
            result["allowCopilotForReaders"] = not allow
            result["status"] = "updated"
        except Exception as e:
            result["status"] = "failed"
            result["detail"] = f"{type(e).__name__}: {e}"
    return result
```

By default this setting is toggle on. To restrict:

```python
allow_copilot_for_readers("<workspace id/name>", "dataset id/name", allow=False, apply_changes=True)
```

After restricting, for read-only users:

*   any reports using this semantic model will not be discoverable from Microsoft Copilot and cannot be queried from Copilot
    
*   they will not be able to use report Copilot on report using this semantic model
    
*   they will not be able to use the semantic model in data agent
    

This is a great way to enforce AI governance.

Thanks to my colleagues Jacinda Eng and Darren Gosebell for their inputs and help.
