← Todos os Posts

Análise profunda do privacy manifest: o que conta como coleta de dados

Desde 1º de maio de 2024, todo app e SDK de terceiros enviado ao App Store Connect precisa ter um privacy manifest declarando seu uso de “APIs com motivo obrigatório”, seu comportamento de tracking e os tipos de dados coletados1. O manifest é um property list (PrivacyInfo.xcprivacy) que a App Store ingere no momento do envio, valida contra uma superfície conhecida de APIs sensíveis à privacidade e expõe no nutrition label de privacidade voltado ao usuário. Apps que omitem o manifest, ou que usam um API sensível à privacidade sem declarar um motivo aprovado, são rejeitados no envio com ITMS-91053 ou códigos relacionados2.

A maioria dos times trata o manifest como uma tarefa de compliance única: escreve, envia e nunca mais olha. O manifest é mais do que isso. Ele é um contrato estruturado entre o app e a Apple que codifica o que o app faz com dados privados, e é o único lugar onde esse contrato existe em formato legível por máquina. Lê-lo com atenção revela o que a Apple considera sensível à privacidade (a superfície é mais ampla do que a maioria dos desenvolvedores espera), o que o usuário realmente vê no nutrition label (mais granular do que a maioria dos times percebe) e o que SDKs de terceiros têm de divulgar (uma obrigação real, não uma cortesia).

TL;DR

  • O privacy manifest tem quatro seções de nível superior: NSPrivacyTracking, NSPrivacyTrackingDomains, NSPrivacyCollectedDataTypes e NSPrivacyAccessedAPITypes3.
  • A lista de API com motivo obrigatório cobre cinco categorias iniciais: timestamp de arquivo, boot time do sistema, espaço em disco, teclados ativos e User Defaults. Cada categoria tem uma lista fechada de códigos de motivo aprovados; os apps precisam escolher um ou reescrever para evitar o API4.
  • Tracking é definido de forma restrita: vincular dados do usuário a dados de outras empresas para publicidade ou compartilhamento com data brokers. Se NSPrivacyTracking for true, todo domínio usado para tracking precisa aparecer em NSPrivacyTrackingDomains3.
  • SDKs de terceiros precisam enviar seus próprios manifests. O manifest do app é mesclado com os manifests de todos os SDKs linkados no momento do envio; manifests ausentes de SDKs presentes na lista publicada pela Apple bloqueiam o app5.
  • A maior armadilha: o acesso ao UserDefaults sempre conta como uma chamada a um API com motivo obrigatório. Um simples UserDefaults.standard.set(...) requer um código de motivo declarado.

As quatro seções

Um arquivo PrivacyInfo.xcprivacy completo tem quatro chaves de nível superior3. A estrutura é um property list, editado como XML em formato bruto ou através do editor de privacy manifest do Xcode.

NSPrivacyTracking (Boolean)

Declara se o app ou SDK rastreia o usuário através de apps e sites de outras empresas. A definição semântica está alinhada com o App Tracking Transparency: vincular dados do usuário a dados de outras empresas com a finalidade de publicidade direcionada, entrega de publicidade direcionada ou compartilhamento de dados do usuário com data brokers6.

Se NSPrivacyTracking for true, todo domínio usado para tracking precisa aparecer na lista NSPrivacyTrackingDomains. Se false, a lista é omitida (ou fica vazia).

A definição restrita importa. Muitos apps que mostram anúncios (através do próprio SKAdNetwork da Apple ou de SDKs de anúncios sem tracking) podem declarar NSPrivacyTracking como false. Tracking é a vinculação a dados externos, não a exibição de anúncios.

NSPrivacyTrackingDomains (Array de strings)

A lista de domínios que o app ou SDK contata para fins de tracking. Apps que declaram NSPrivacyTracking como true precisam enumerar todos os endpoints de tracking aqui.

A lista é aplicada em runtime via App Privacy Report: se o app contatar um domínio sinalizado como tracking mas não declarado, o App Privacy Report expõe a discrepância ao usuário. Violações repetidas correm o risco de remoção da App Store.

NSPrivacyCollectedDataTypes (Array de dicionários)

A declaração estruturada de coleta de dados que alimenta o nutrition label de privacidade da App Store3. Cada entrada descreve um tipo de dado que o app coleta, com sub-chaves:

  • NSPrivacyCollectedDataType: o tipo de dado da lista fechada da Apple (por exemplo, NSPrivacyCollectedDataTypeName, NSPrivacyCollectedDataTypeEmailAddress, NSPrivacyCollectedDataTypeCrashData).
  • NSPrivacyCollectedDataTypeLinked: Boolean, indica se o dado está vinculado à identidade do usuário.
  • NSPrivacyCollectedDataTypeTracking: Boolean, indica se o dado é usado para tracking.
  • NSPrivacyCollectedDataTypePurposes: array, as finalidades para as quais o dado é coletado (analytics, funcionalidade do app, publicidade, etc.).

Esta seção é a fonte da verdade para o nutrition label de privacidade. As categorias “Dados Usados para Rastrear Você” e “Dados Vinculados a Você” do nutrition label são calculadas a partir desses flags. Declarações imprecisas produzem nutrition labels imprecisos e correm risco de ações de enforcement da App Store.

NSPrivacyAccessedAPITypes (Array de dicionários)

A declaração de API com motivo obrigatório. Cada entrada associa uma categoria de API com motivo obrigatório a um conjunto de códigos de motivo aprovados4.

<key>NSPrivacyAccessedAPITypes</key>
<array>
    <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
            <string>CA92.1</string>
        </array>
    </dict>
    <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
            <string>C617.1</string>
        </array>
    </dict>
</array>

Os motivos são listas fechadas. O app escolhe um ou mais da lista publicada pela Apple por categoria; strings arbitrárias são rejeitadas no envio.

As cinco categorias de API com motivo obrigatório

A lista inicial da Apple de 2024 definiu cinco categorias de API que requerem um motivo declarado4:

NSPrivacyAccessedAPICategoryFileTimestamp

Acionada por qualquer API que retorne data de criação, modificação ou acesso de arquivos. Pontos de entrada comuns: URL.resourceValues(forKeys: [.creationDateKey, ...]), FileManager.attributesOfItem(atPath:), stat(), fstat(), lstat(). Os quatro motivos aprovados4:

  • DDA9.1. Mostrar timestamps de arquivos ao usuário do dispositivo. Informações acessadas por esse motivo não podem ser enviadas para fora do dispositivo.
  • C617.1. Acessar metadados de arquivo (timestamps, tamanho, etc.) para arquivos dentro do container do app, container do app group ou container do CloudKit.
  • 3B52.1. Acessar metadados de arquivo para arquivos ou diretórios aos quais o usuário concedeu acesso explicitamente (document picker, etc.).
  • 0A2A.1. Wrappers de SDK de terceiros que acessam APIs de timestamp de arquivo apenas quando o app chama o wrapper. Apenas para SDK.

A maioria dos apps usa C617.1 (acesso ao próprio container) para gerenciamento interno de arquivos. Apps que mostram datas de arquivo na UI voltada ao usuário usam DDA9.1. Apps que leem arquivos concedidos pelo usuário (document picker, alvos de share extension) usam 3B52.1. Autores de SDK usam 0A2A.1 apenas.

NSPrivacyAccessedAPICategorySystemBootTime

Acionada por mach_absolute_time(), mach_continuous_time() e APIs de uptime relacionados. A preocupação com privacidade: o boot time do sistema é um sinal identificável que pode ser usado para identificar o dispositivo entre reinstalações. Os três motivos aprovados4:

  • 35F9.1. Acessar boot time do sistema para medir intervalos de tempo entre eventos do app ou para habilitar timers.
  • 8FFB.1. Acessar boot time do sistema para calcular timestamps absolutos de eventos dentro do app.
  • 3D61.1. Adicionar informação de boot time do sistema em um relatório opcional de bug que o usuário escolhe enviar.

A maioria dos apps usa 35F9.1 para medição de performance. 8FFB.1 cobre casos onde o app deriva timestamps de eventos a partir do boot time (relativo à sessão do dispositivo). Note que Date() e Date.now não acionam essa categoria; eles usam uma fonte de tempo diferente. A categoria cobre especificamente chamadas da família mach_*_time.

NSPrivacyAccessedAPICategoryDiskSpace

Acionada por APIs que retornam capacidade de disco ou espaço livre, incluindo URL.resourceValues(forKeys: [.volumeAvailableCapacityKey, ...]) e os APIs de atributos de sistema de arquivos do NSFileManager. A preocupação com privacidade: padrões de espaço em disco são um sinal identificável. Os quatro motivos aprovados4:

  • 854F.1. Exibir informação de espaço em disco ao usuário do dispositivo, em unidades de dados ou unidades de tempo de mídia.
  • E174.1. Verificar espaço em disco ao gravar arquivos ou para gerenciar pouco espaço em disco (decidir se baixa um asset, limpar arquivos em cache).
  • 7D9E.1. Incluir informação de espaço em disco em um relatório opcional de bug que o usuário escolhe enviar.
  • B728.1. Apps de pesquisa em saúde detectando e informando participantes sobre pouco espaço em disco afetando a coleta de dados do estudo.

NSPrivacyAccessedAPICategoryActiveKeyboards

Acionada por UITextInputMode.activeInputModes. Apps que leem essa lista (tipicamente para localizar comportamento ou detectar idioma de entrada) precisam declarar um motivo. Os dois motivos aprovados4:

  • 3EC4.1. Um app de teclado customizado determinando os teclados ativos no dispositivo.
  • 54BD.1. Acessar informação de teclado ativo para customizar a interface do usuário de acordo (tipicamente para UX consciente do idioma de entrada).

A maioria dos apps não precisa dessa categoria. Se seu código chama activeInputModes indiretamente através de uma biblioteca de terceiros, o manifest dessa biblioteca a declara.

NSPrivacyAccessedAPICategoryUserDefaults

A categoria que pega quase todo app. Qualquer acesso ao UserDefaults (UserDefaults.standard, app group defaults via init(suiteName:), chamadas individuais de set/get) aciona o requisito7. Os quatro motivos aprovados4:

  • CA92.1. Acessar user defaults para ler/escrever dados exclusivos do próprio app (ou de uma app extension pareada apenas com o app).
  • 1C8F.1. Acessar user defaults para ler/escrever dados apenas dentro de apps, app extensions e App Clips que são membros do mesmo App Group.
  • C56D.1. Wrappers de SDK de terceiros que acessam APIs de user defaults apenas quando o app chama o wrapper. Apenas para SDK.
  • AC6B.1. Acessar user defaults para recuperar configurações gerenciadas do app definidas por um administrador MDM/IT, ou para armazenar informação de feedback para o administrador.

Quase todo app iOS usa UserDefaults.standard para pelo menos um pedaço de estado (a última aba selecionada pelo usuário, sua ordem de classificação preferida, uma feature flag). O motivo CA92.1 cobre isso. Apps que compartilham estado entre app extensions através de um app group adicionam 1C8F.1. Autores de SDK usam C56D.1. Apps implantados através de um MDM que leem chaves definidas pelo administrador (por exemplo, com.apple.configuration.managed) usam AC6B.1.

A pegadinha: um SDK de terceiros que toca em UserDefaults aciona o requisito em nome do app. O manifest do SDK precisa declarar o motivo. Se o SDK está na lista da Apple de SDKs que devem enviar um privacy manifest, a ausência do manifest do SDK bloqueia o app.

Domínios de tracking: validação em runtime

NSPrivacyTrackingDomains é aplicado através do App Privacy Report em runtime6. Quando um app declara NSPrivacyTracking = true, o sistema rastreia toda requisição de rede e compara o destino com a lista declarada. Domínios contatados para tracking mas não declarados aparecem nas seções “Localizações Frequentes” e “Outros Domínios Contatados” do App Privacy Report.

A validação em runtime cria uma estrutura interessante de incentivos. Um app que declara NSPrivacyTracking = false (sem tracking) mas é observado contatando domínios conhecidos de tracking é sinalizado no App Privacy Report e corre risco de reclamações de usuários. A jogada certa é declaração honesta.

Para SDKs, o privacy manifest do SDK declara seu comportamento de tracking. O manifest do app não precisa enumerar os domínios de tracking do SDK; o manifest do SDK já faz isso. No envio, a Apple mescla os manifests e verifica consistência.

Manifests de SDK: uma obrigação real

SDKs de terceiros em duas categorias precisam enviar um privacy manifest5:

  1. SDKs na lista publicada pela Apple de SDKs que requerem privacy manifests. A lista inclui Firebase Analytics, Google Mobile Ads, Adjust, Segment, AppsFlyer e cerca de 30 outros, conforme o iOS 26.
  2. SDKs distribuídos como binários pré-compilados (XCFrameworks, bibliotecas estáticas) aos quais o app é linkado.

O envio de um app que linka um SDK obrigatório sem o manifest do SDK falha com um erro da série ITMS-91xxx cobrindo privacy manifest ausente, assinatura de manifest ausente ou declaração de API ausente no namespace do SDK2. A correção é atualizar para uma versão do SDK que envie manifest ou remover o SDK.

Para SDKs de primeira parte (seu time envia um framework interno usado por seus apps), você pode escolher pular o manifest se o framework não estiver na lista da Apple. A jogada pragmática é enviar um mesmo assim: futuras expansões da lista da Apple, futuro trabalho de auditoria, futuro reuso por terceiros, todos se beneficiam de ter o manifest no lugar.

Armadilhas comuns

Cinco modos recorrentes de falha dos logs de rejeição da App Store:

1. Declaração esquecida de UserDefaults. A rejeição mais comum. O app usa @AppStorage (que envolve UserDefaults) em algum lugar inocente, e o manifest não declara isso. Correção: todo app que usa @AppStorage, UserDefaults ou qualquer wrapper em torno deles precisa de NSPrivacyAccessedAPICategoryUserDefaults com CA92.1.

2. Acesso oculto a timestamp de arquivo através de URLResourceValues. Código que lê datas de modificação de arquivo através de URL.resourceValues(forKeys: [.contentModificationDateKey]) aciona a categoria, mesmo que o ponto de chamada não pareça um stat.

3. Expectativas sobre o manifest do SDK. Times de app assumem que o manifest do SDK é problema do autor do SDK. É, mas o envio do time do app falha até que o SDK envie um.

4. NSPrivacyTracking = false apesar de SDK de tracking linkado. Linkar Firebase Analytics ou Google Mobile Ads com configurações padrão frequentemente aciona comportamento de tracking. O manifest do app declarando NSPrivacyTracking = false enquanto o manifest do SDK declara true produz uma contradição que o merger sinaliza.

5. Códigos de motivo desatualizados. A Apple atualiza os códigos de motivo aprovados ocasionalmente. Códigos que eram válidos em 2024 podem ser substituídos ou expandidos. A correção é re-checar a lista publicada atual a cada release maior em vez de copiar manifests antigos para frente.

Ferramentas de validação

Três checagens que vale a pena rodar antes do envio:

Workflow de archive “Generate Privacy Report” do Xcode. Após Product > Archive, o Organizer oferece uma ação “Generate Privacy Report” que produz um relatório agregado a partir do app e do manifest de cada SDK linkado. O relatório é o que o App Store Connect ingere; rodá-lo localmente é o equivalente mais próximo a um dry-run pré-envio.

Análise estática em APIs com motivo obrigatório. Ferramentas open-source escaneiam um projeto buscando os pontos de chamada de API que acionam as cinco categorias. A CLI mantida pela comunidade stelabouras/privacy-manifest faz parsing de fontes Swift e binários xcframework para expor códigos de motivo declarados e não declarados; crasowas/app_store_required_privacy_manifest_analyser fornece um scan similar. Qualquer um dá uma captura útil pré-envio para declarações ausentes.

Cross-check com App Privacy Report. Rode o app no modo App Privacy Report do iOS (Configurações > Privacidade e Segurança > App Privacy Report). Os domínios que o app contata aparecem no relatório; faça cross-check com as declarações de tracking do manifest.

O que esse padrão significa para apps iOS 26+

Três pontos a levar.

  1. Trate o privacy manifest como um contrato estruturado, não um checkbox. O manifest é o único registro legível por máquina do que o app faz com dados privados. Construí-lo uma vez, ignorá-lo para sempre, é o caminho para um envio rejeitado seis meses depois quando uma atualização de SDK silenciosamente expande a superfície obrigatória do manifest.

  2. Audite seu acesso a UserDefaults e timestamp de arquivo a cada release. Estas são as duas categorias que crescem silenciosamente com o codebase. Uma view SwiftUI que usa @AppStorage adicionada em um refactor traz NSPrivacyAccessedAPICategoryUserDefaults para o escopo; um recurso de listagem de arquivos adicionado depois traz NSPrivacyAccessedAPICategoryFileTimestamp junto. Revalide toda vez.

  3. Use SDKs que enviam seus próprios manifests. Ao avaliar um SDK de terceiros, a presença e qualidade de seu privacy manifest é agora um sinal de qualidade. SDKs sem manifests forçam o time do app a brigar upstream; SDKs com manifests se encaixam limpamente na mesclagem.

O cluster completo do Apple Ecosystem: App Intents tipados; servidores MCP; a questão do roteamento; Foundation Models; a distinção LLM entre runtime e tooling; três superfícies; o padrão de fonte única da verdade; Dois Servidores MCP; hooks para desenvolvimento Apple; Live Activities; o contrato de runtime do watchOS; internals do SwiftUI; o modelo mental espacial do RealityKit; disciplina de schema do SwiftData; padrões do Liquid Glass; shipping multi-plataforma; a matriz de plataformas; framework Vision; Symbol Effects; inferência Core ML; API Writing Tools; Swift Testing; sobre o que me recuso a escrever. O hub está na Série Apple Ecosystem. Para contexto mais amplo de iOS com agentes de IA, veja o guia de Desenvolvimento de Agentes iOS.

FAQ

Qual a diferença entre NSPrivacyTracking e NSPrivacyCollectedDataTypeTracking?

NSPrivacyTracking é o boolean a nível de app: este app rastreia usuários (segundo a definição restrita da Apple) de alguma forma? NSPrivacyCollectedDataTypeTracking é por tipo de dado: para um determinado tipo de dado que o app coleta, esse dado é usado para tracking? Um app pode coletar dados sem fazer tracking (analytics que não vincula entre empresas); o flag por tipo captura se cada tipo específico de dado contribui para o comportamento de tracking.

Preciso de um privacy manifest para um app TestFlight apenas interno?

Sim. O enforcement de privacy manifest roda no envio para o App Store Connect, incluindo builds do TestFlight. Um beta interno sem manifest falha na mesma checagem ITMS-91053 que um release público.

O que acontece se eu declarar um API com motivo obrigatório sem usá-lo?

Nada funcional. O manifest declara um limite superior na superfície de API; declarar uma categoria não usada é inofensivo. O custo é desvio de documentação: futuros mantenedores podem assumir que a declaração reflete o código atual, quando na verdade a chamada foi removida. A jogada certa é declarar o que o app realmente usa, auditado a cada release maior.

Existem categorias de API com motivo obrigatório além das cinco originais?

Conforme o iOS 26, as cinco categorias originais (timestamp de arquivo, boot time do sistema, espaço em disco, teclados ativos, User Defaults) permanecem como a lista canônica4. A Apple adicionou códigos de motivo aprovados dentro das categorias ao longo do tempo, mas não expandiu a lista de categorias. Acompanhe a página de documentação de API com motivo obrigatório da Apple para adições.

Como o privacy manifest interage com o App Tracking Transparency?

O App Tracking Transparency (ATT) governa o prompt de permissão em runtime para tracking entre apps. O privacy manifest declara a intenção do app estaticamente. Eles são complementares: um app que faz tracking entre apps declara NSPrivacyTracking = true no manifest e solicita permissão ATT em runtime. Um app declarando NSPrivacyTracking = false não deve solicitar ATT (a ausência de tracking entre apps significa que o prompt é desnecessário).

Referências


  1. Apple Developer Documentation: Privacy manifest files. A referência de formato e o cronograma de enforcement de 1º de maio de 2024. 

  2. Apple Developer: App Store Connect submission errors cobrindo ITMS-91053 (declaração de API ausente) e códigos relacionados. 

  3. Apple Developer Documentation: App privacy configuration. As quatro chaves de nível superior (NSPrivacyTracking, NSPrivacyTrackingDomains, NSPrivacyCollectedDataTypes, NSPrivacyAccessedAPITypes) e seus schemas. 

  4. Apple Developer Documentation: Describing use of required reason API. As cinco categorias de API com motivo obrigatório com códigos de motivo aprovados. 

  5. Apple Developer: Third-party SDK privacy manifest requirements. A lista de SDKs que devem enviar um privacy manifest. 

  6. Apple Developer Documentation: User privacy and data use. A definição restrita de tracking e o framework do App Tracking Transparency. 

  7. Apple Developer Documentation: NSPrivacyAccessedAPICategoryUserDefaults. A categoria que cobre todo acesso ao UserDefaults incluindo wrappers baseados em @AppStorage

Artigos relacionados

SwiftData's Real Cost Is Schema Discipline

SwiftData's API is two macros. The cost is what happens after you ship. Optional fields are the cheap migration; non-opt…

15 min de leitura

HealthKit + SwiftUI on iOS 26: Authorization, Sample Types, and Cross-Platform Patterns

Real production patterns from Water (water tracking, HKQuantitySample) and Return (mindful sessions, HKCategorySample). …

17 min de leitura

The Cleanup Layer Is the Real AI Agent Market

Charlie Labs pivoted from building agents to cleaning up after them. The AI agent market is moving from generation to pr…

15 min de leitura