Vous ne pouvez pas cacher une fenêtre à Zoom sur macOS 15
Sur macOS moderne, il est impossible de cacher de manière fiable une fenêtre aux captures d'écran — ni depuis une autre application, ni même depuis votre propre application. C'est l'histoire technique de la suppression de CGSSetWindowCaptureExcluded, de l'ignorance silencieuse de SLSSetWindowSharingState entre processus, et de la raison pour laquelle NSWindow.sharingType = .none est une suggestion douce pour Zoom et QuickTime, et non une garantie rigoureuse.
Un bref retour d'expérience d'ingénieur sur la conception d'une application « fenêtre privée » qui ne fonctionne pas tout à fait.
L'idée
Comme beaucoup de gens, je travaille avec une fenêtre de Claude ouverte pendant les réunions. Comme beaucoup de gens, je partage parfois mon écran sur Zoom et j'aimerais que cette fenêtre ne soit pas visible pour tout le monde dans la réunion. Ce n'est pas à cause de données sensibles — juste parce que c'est un état de travail privé.
J'ai suivi des outils comme 1Password ou Hand Mirror qui peuvent cacher leurs propres fenêtres des enregistrements d'écran. J'ai pensé pouvoir construire un petit utilitaire en barre de menu qui me permettrait de choisir n'importe quelle application — Claude, Notes, n'importe quoi — et d'activer ou désactiver l'invisibilité de ses fenêtres pendant l'enregistrement tout en gardant ces fenêtres pleinement visibles et interactives sur mon écran.
Projet de week-end. Au maximum deux heures.
Cela a pris plus de temps. Et la conclusion est : sur macOS moderne, vous ne pouvez pas faire cela. Pas pour une autre application, et — comme on s'est aperçu — pas de manière fiable même pour votre propre application.
Voici l'histoire d'ingénierie pour expliquer pourquoi.
Essai 1 : cacher une fenêtre d'une autre application
La méthode classique pour rendre une fenêtre macOS invisible lors d'un enregistrement d'écran est NSWindow.sharingType = .none. Mais c'est un indicateur par fenêtre qui ne peut être défini que par le processus propriétaire de la fenêtre. AppKit ne permet pas d'accéder à la liste des fenêtres d'une autre application.
L'astuce bien connue, utilisée depuis des années par des outils comme Hand Mirror ou diverses applications de masquage d'écran, est la fonction privée SkyLight :
OSStatus CGSSetWindowCaptureExcluded(CGSConnectionID cid, CGWindowID wid, bool excluded);
Vous itérez sur les fenêtres via CGWindowListCopyWindowInfo, filtrez pour le PID de l'application cible, puis appelez cette fonction sur chaque ID de fenêtre. Puisque l'appel passe par le WindowServer (et non par le processus propriétaire), il peut exclure n'importe quelle fenêtre de l'enregistrement.
J'ai mis en place cela via dlsym sur /System/Library/PrivateFrameworks/SkyLight.framework/..., j'ai construit l'outil, l'ai exécuté sur macOS 15.3.1, et j'ai obtenu :
[InvisibleApp] symbol not found: CGSSetWindowCaptureExcluded
[InvisibleApp] symbol not found: SLSSetWindowCaptureExcluded
La fonction est disparue. Apple l'a supprimée. J'ai cherché une version renommée (SLSSetWindowExcludedFromCapture, CGSSetWindowSharingState, toutes les variantes évidentes). La plupart n'existent pas, mais j'ai trouvé deux qui existent :
SLSSetWindowSharingState(CGSConnectionID, CGWindowID, int sharingState)— l'appel sous-jacent queNSWindow.sharingType = .noneutilise internement. Partage de l'état0estNSWindowSharingNone.SLSGetWindowOwner— vous donne l'identifiant de connexion du processus propriétaire de la fenêtre.
J'ai donc réétabli le pont pour appeler SLSSetWindowSharingState sur la fenêtre cible, en essayant à la fois ma connexion principale et la connexion du processus propriétaire de la fenêtre.
Compilation, exécution, activation, le journal indique qu'elle a retourné noErr, prenez une capture d'écran — Claude est toujours visible dans la capture. Essayez Zoom — Claude est toujours visible dans le partage.
SLSSetWindowSharingState réussit lorsqu'elle est appelée entre processus, mais le WindowServer l'ignore silencieusement. Seul le processus propriétaire peut modifier l'état de partage de sa propre fenêtre sur macOS 15.
J'ai également confirmé que l'issue de fuite est fermée : DYLD_INSERT_LIBRARIES l'injection dans le processus de Claude est bloquée car Claude (comme la plupart des applications modernes) est livré avec un runtime renforcé activé et sans l' disable-library-validation entitlement.
Cela est donc terminé : aucune application tierce ne peut rendre une fenêtre d'une autre application invisible lors d'un enregistrement sur macOS 15. La conclusion correspond à ce que Apple souhaite : l'état de capture au niveau de la fenêtre est la propriété exclusive de l'application propriétaire, sans exception.
Essai 2 : cacher notre propre fenêtre
Plan B : pivoter le produit. Au lieu d'un outil qui cache Claude, construisons une petite fenêtre de chat de notre propre création — même fonction, forme différente. Notre fenêtre, notre sharingType = .none. C'est le mécanisme bien connu que chaque outil de masquage d'écran utilise, et c'est une ligne de code :
window.sharingType = .none
Mettre en place un flux de chat vers l'API Anthropic Messages (ou vers la CLI locale claude pour l'authentification par abonnement), définir sharingType = .none sur la fenêtre de chat, la livrer. C'est une API publique, clairement supportée.
J'ai construit cela. J'ai enregistré la valeur réelle de partage à l'exécution pour s'assurer que macOS l'a acceptée :
[InvisibleApp] window 151526 sharingType=0
J'ai pris une capture d'écran — la fenêtre de chat était correctement absente. ✅
J'ai enregistré l'écran avec QuickTime — la fenêtre de chat apparaissait dans l'enregistrement. ❌
J'ai partagé l'écran sur Zoom — la fenêtre de chat était visible pour l'autre côté. ❌
C'était inattendu. L'objectif principal de indiquer de NSWindowSharingNone est de l'extraire de ces flux. J'ai donc construit un test interne dans l'application qui effectue une capture d'écran en utilisant ScreenCaptureKit (l'API publique moderne de capture), le même framework utilisé par QuickTime en interne. J'ai essayé à la fois une capture unique (SCScreenshotManager.captureImage) et une capture continue (SCStream) — les deux ont produit une image PNG avec la fenêtre de chat correctement exclue.
Donc :
| Méthode de capture | Masque la fenêtre ? |
|---|---|
| Cmd-Shift-3/4/5 (capture système) | ✅ |
| Capture unique de l'application SCK | ✅ |
| Capture continue de l'application SCK | ✅ |
| QuickTime « Nouvelle enregistrement d'écran » | ❌ |
| Zoom « Partager l'écran → Bureau » | ❌ |
Même OS, même machine, même écran, même sharingType = .none. La seule chose qui varie, c'est celui qui effectue la capture.
Chemins privilégiés de capture
C'est la partie que la plupart des ingénieurs ne réalisent pas : sur macOS 15, la capture d'écran n'est pas une seule API ; il y a au moins deux — une publique et une privée avec des autorisations supplémentaires.
J'ai décomposé les autorisations de QuickTime Player :
codesign -d --entitlements - /System/Applications/QuickTime\ Player.app
com.apple.private.screencapturekit.noprompt = true
com.apple.private.tcc.allow = [
kTCCServiceMicrophone,
kTCCServiceCamera,
kTCCServiceScreenCapture,
]
Ces com.apple.private.* clés ne peuvent être accordées que par Apple aux binaires de première partie. Vous et moi ne pouvons pas les demander. Le processus de notarisation les refuserait. L'App Store l'aurait certainement refusé.
Et ce qu'ils accordent, en plus de passerover le prompt de permission de capture, est la possibilité de capturer une image de l'écran avant que le WindowServer n'applique le filtrage de partage. La fenêtre est présente dans le framebuffer qui sort — les outils d'Apple voient tout.
Zoom utilise un chemin analogue de privilège. Il pourrait s'agir d'une extension du noyau, d'une extension système ou d'une API privée obtenue en tant qu'application de conférence longuement bénie — je n'ai pas encore exploré assez pour le dire. Mais le comportement est le même : le mécanisme public de filtrage ne s'applique pas.
Ce qui signifie
Si vous êtes un développeur tiers et que votre objectif est « cette fenêtre ne doit jamais apparaître dans un enregistrement d'écran sur n'importe quel Mac », vous ne pouvez pas garantir cela sur macOS 15. Votre fenêtre est cachée de toutes les méthodes de capture que vous pouvez écrire vous-même. Elle est cachée de Google Meet (navigateur → getDisplayMedia → SCK), Microsoft Teams (SCK), OBS (SCK), tous les outils tiers conformes. Mais QuickTime d'Apple et les applications de conférence autorisées par Apple peuvent encore la voir.
La fonction de « protection contre la capture d'écran » de 1Password / Hand Mirror a la même limitation. Les gens ne font pas souvent d'enregistrements d'écran de leur coffre 1Password avec QuickTime, donc la fuite reste inaperçue.
Le résumé honnête que je donnerais à Apple sur ce sujet : publiez une autorisation publique équivalente à com.apple.private.screencapturekit.noprompt, ou déclarez que NSWindow.sharingType = .none est une garantie ferme contre toutes méthodes de capture. À partir de macOS 15.3.1, ce n'est ni l'un ni l'autre — c'est une garantie ferme contre la plupart des méthodes et une suggestion faible que les outils privilégiés peuvent contourner. L'état actuel crée une posture de sécurité où les utilisateurs croient qu'une fenêtre est invisible lors d'une capture, alors qu'elle ne l'est pas, ce qui est pire qu'aucune protection du tout.
Les contournements, classés par leur impact négatif
Pour mon cas d'usage — garder une fenêtre de chat invisible pendant un partage sur Zoom — tous fonctionnent et aucun n'est parfait :
- Partagez une seule fenêtre sur Zoom, pas l'ensemble de l'écran. Dans la fenêtre de partage, il y a une onglet « Fenêtre ». Zoom capture uniquement les pixels de cette fenêtre et rien d'autre, donc mon chat — et tout ce qui se trouve sur l'écran — est automatiquement absent. C'est la solution la plus fiable et nécessite zéro code. Inconvénient : les spectateurs ne voient pas le contexte global de l'écran.
- Utilisez Meet ou Teams au lieu de Zoom. Les deux respectent
sharingType = .none. C'est excellent si vous contrôlez l'outil de réunion, mauvais si vous ne le faites pas. - Mettez le chat sur un espace séparé. Mission Control vous donne plusieurs bureaux. Partagez l'espace 1, gardez le chat sur l'espace 2. Faites glisser pour interagir. C'est lent, brise le flux, mais ça fonctionne.
- Utilisez un deuxième appareil. Un téléphone ou une iPad à côté de votre ordinateur est indépassable par tout outil de capture, par définition.
J'ai choisi l'option 1 plus l'application de chat que j'ai déjà construite. Le chat est invisible à environ 95% des méthodes de capture, et dans le cas du partage d'écran sur Zoom, je n'utilise pas le partage d'écran sur le bureau.
Ce que je voudrais voir ensuite
- Une autorisation publique permettant à une application notariée de déclarer « cette fenêtre de mon application est exclue de toutes la capture, y compris par les appels privilégiés ». Aujourd'hui, cela n'est pas possible.
- Honnêteté dans
NSWindow.sharingTypela documentation. Les documents font croire qu'il s'agit d'une garantie ferme. Ce n'est pas le cas — au minimum, les documents devraient mentionner que les outils privilégiés d'Apple et les applications avec des autorisations privées peuvent capturer indépendamment. Aujourd'hui, ils ne le font pas. - Un moyen de consulter les applications présentes sur un système qui ont accès à la capture privilégiée — analogue à « Fichiers et Dossiers » dans la Sécurité et la Confidentialité. Aujourd'hui, il n'y a pas de surface pour les utilisateurs de voir qui peut contourner leur confidentialité.
Jusqu'à ce que l'un de ces points soit mis en place, le conseil pratique est : assumez que toute fenêtre sur votre écran est capturable par le système et par les principales applications de conférence, indépendamment de ce que sharingType vous avez défini. Les API d'exclusion sont réelles — elles fonctionnent contre la plupart du monde — mais elles ne constituent pas une frontière de sécurité que vous pouvez confier face aux parties du monde qui comptent le plus.
Vous aimerez peut-être aussi
Installez nos extensions
Ajoutez des outils IO à votre navigateur préféré pour un accès instantané et une recherche plus rapide
恵 Le Tableau de Bord Est Arrivé !
Tableau de Bord est une façon amusante de suivre vos jeux, toutes les données sont stockées dans votre navigateur. D'autres fonctionnalités arrivent bientôt !
Outils essentiels
Tout voir Nouveautés
Tout voirMise à jour: Notre dernier outil ajouté le 18 mai 2026
