Migrar para as dicas de cliente do user agent

Estratégias para migrar seu site da string do user agent para as novas dicas do cliente do user agent.

A string do user agent é uma superfície significativa de impressão digital passiva nos navegadores e é difícil de processar. No entanto, há vários motivos válidos para coletar e processar dados do user agent, portanto, o que você precisa é um caminho para uma solução melhor. As dicas de cliente do user agent são uma maneira explícita de declarar a necessidade de dados do user agent e métodos para retornar os dados em um formato fácil de usar.

Neste artigo, você verá como auditar seu acesso aos dados do user agent e migrar o uso de strings do user agent para as dicas do cliente do user agent.

Auditar a coleta e o uso de dados do user agent

Assim como em qualquer forma de coleta de dados, é preciso sempre entender por que você os está coletando. A primeira etapa, independentemente de você realizar ou não alguma ação, é entender onde e por que você está usando os dados do user agent.

Se você não souber se ou onde os dados do user agent estão sendo usados, pesquise no código de front-end para usar navigator.userAgent e no código de back-end para usar o cabeçalho HTTP User-Agent. Verifique também seu código de front-end para o uso de recursos já descontinuados, como navigator.platform e navigator.appVersion.

Do ponto de vista funcional, pense em qualquer parte do código em que você esteja gravando ou processando:

  • Nome ou versão do navegador
  • Nome ou versão do sistema operacional
  • Marca ou modelo do dispositivo
  • Tipo de CPU, arquitetura ou quantidade de bits (por exemplo, 64 bits)

Também é provável que você esteja usando uma biblioteca ou um serviço de terceiros para processar o user agent. Nesse caso, verifique se elas estão sendo atualizadas para oferecer suporte às dicas do cliente do user agent.

Você está usando somente dados básicos do user agent?

O conjunto padrão de dicas do cliente do user agent inclui o seguinte:

  • Sec-CH-UA: nome do navegador e versão principal/significativa
  • Sec-CH-UA-Mobile: valor booleano que indica um dispositivo móvel
  • Sec-CH-UA-Platform: nome do sistema operacional
    • Observe que isso foi atualizado na especificação e será reflexivo no Chrome e em outros navegadores baseados no Chromium em breve.

A versão reduzida da string do user agent proposta também manterá essas informações básicas de maneira compatível com versões anteriores. Por exemplo, em vez de Chrome/90.0.4430.85, a string incluiria Chrome/90.0.0.0.

Se você estiver verificando apenas a string do user agent para saber o nome do navegador, a versão principal ou o sistema operacional, seu código continuará funcionando, embora seja provável que você veja avisos de suspensão de uso.

Embora você possa e precise migrar para as dicas de cliente do user agent, talvez tenha restrições de código ou recursos legados que impedem isso. A redução de informações na string do user agent dessa maneira compatível com versões anteriores visa garantir que, embora o código existente receba informações menos detalhadas, ele ainda manterá a funcionalidade básica.

Estratégia: API JavaScript sob demanda do lado do cliente

Se você estiver usando navigator.userAgent, faça a transição para priorizar navigator.userAgentData antes de voltar à análise da string do user agent.

if (navigator.userAgentData) {
  // use new hints
} else {
  // fall back to user-agent string parsing
}

Se você estiver verificando dispositivos móveis ou computadores, use o valor booleano mobile:

const isMobile = navigator.userAgentData.mobile;

userAgentData.brands é uma matriz de objetos com as propriedades brand e version em que o navegador pode listar a compatibilidade com as marcas. É possível acessá-la diretamente como uma matriz ou usar uma chamada some() para verificar se uma entrada específica está presente:

function isCompatible(item) {
  // In real life you most likely have more complex rules here
  return ['Chromium', 'Google Chrome', 'NewBrowser'].includes(item.brand);
}
if (navigator.userAgentData.brands.some(isCompatible)) {
  // browser reports as compatible
}

Se você precisar de um dos valores de user agent mais detalhados e de alta entropia, especifique-o e verifique o resultado no Promise retornado:

navigator.userAgentData.getHighEntropyValues(['model'])
  .then(ua => {
    // requested hints available as attributes
    const model = ua.model
  });

Também é possível usar essa estratégia se você quiser migrar do processamento do lado do servidor para o processamento no lado do cliente. Como a API JavaScript não requer acesso a cabeçalhos de solicitação HTTP, os valores do user agent podem ser solicitados a qualquer momento.

Estratégia: cabeçalho estático do lado do servidor

Se você estiver usando o cabeçalho de solicitação User-Agent no servidor e as necessidades de dados forem relativamente consistentes em todo o site, especifique as dicas do cliente desejadas como um conjunto estático nas suas respostas. Essa é uma abordagem relativamente simples, porque geralmente você só precisa configurá-la em um local. Por exemplo, ela pode estar na configuração do servidor da Web se você já adicionou cabeçalhos, na configuração de hospedagem ou na configuração de nível superior do framework ou da plataforma usada para o site.

Considere essa estratégia se você estiver transformando ou personalizando as respostas veiculadas com base nos dados do user agent.

Navegadores ou outros clientes podem optar por fornecer dicas padrão diferentes. Por isso, é recomendável especificar tudo o que você precisa, mesmo que isso geralmente seja fornecido por padrão.

Por exemplo, os padrões atuais do Chrome seriam representados como:

⬇️ Cabeçalhos de resposta

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

Se você também quiser receber o modelo do dispositivo nas respostas, envie:

⬇️ Cabeçalhos de resposta

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA

Ao processar isso no lado do servidor, verifique primeiro se o cabeçalho Sec-CH-UA desejado foi enviado e, em seguida, faça a análise do cabeçalho User-Agent se ele não estiver disponível.

Estratégia: delegar dicas para solicitações de origem cruzada

Se você estiver solicitando sub-recursos de origem cruzada ou entre sites que exigem o envio de dicas do cliente do user agent nas solicitações, será necessário especificar explicitamente as dicas desejadas usando uma política de permissões.

Por exemplo, digamos que https://blog.site hospeda recursos em https://cdn.site, que podem retornar recursos otimizados para um dispositivo específico. https://blog.site pode solicitar a dica Sec-CH-UA-Model, mas precisa delegá-la explicitamente para https://cdn.site usando o cabeçalho Permissions-Policy. A lista de dicas controladas por políticas está disponível no rascunho da infraestrutura de dicas de clientes

⬇️ Resposta de blog.site delegando a dica

Accept-CH: Sec-CH-UA-Model
Permissions-Policy: ch-ua-model=(self "https://cdn.site")

⬆️ A solicitação de sub-recursos em cdn.site inclui a dica delegada

Sec-CH-UA-Model: "Pixel 5"

Você pode especificar várias dicas para diversas origens, e não apenas para o intervalo ch-ua:

⬇️ Resposta de blog.site deletando várias dicas a diversas origens

Accept-CH: Sec-CH-UA-Model, DPR
Permissions-Policy: ch-ua-model=(self "https://cdn.site"),
                    ch-dpr=(self "https://cdn.site" "https://img.site")

Estratégia: delegar dicas a iframes

Os iframes de origem cruzada funcionam de maneira semelhante aos recursos de origem cruzada, mas você especifica as dicas que quer delegar no atributo allow.

⬇️ Resposta de blog.site

Accept-CH: Sec-CH-UA-Model

↪️ HTML para blog.site

<iframe src="https://widget.site" allow="ch-ua-model"></iframe>

⬆️ Solicitar para widget.site

Sec-CH-UA-Model: "Pixel 5"

O atributo allow no iframe substitui qualquer cabeçalho Accept-CH enviado pela widget.site. Portanto, verifique se você especificou tudo que o site precisa para o iframe.

Estratégia: dicas dinâmicas do lado do servidor

Se você tiver partes específicas da jornada do usuário em que precisa de uma seleção maior de dicas do que em todo o restante do site, poderá solicitar essas dicas sob demanda em vez de estaticamente em todo o site. Isso é mais complexo de gerenciar, mas se você já definiu cabeçalhos diferentes por rota, pode ser viável.

O importante a ser lembrado aqui é que cada instância do cabeçalho Accept-CH substituirá efetivamente o conjunto existente. Portanto, se você estiver definindo dinamicamente o cabeçalho, cada página precisará solicitar o conjunto completo de dicas necessárias.

Por exemplo, você pode ter uma seção no seu site em que queira fornecer ícones e controles que correspondam ao sistema operacional do usuário. Para isso, você pode extrair Sec-CH-UA-Platform-Version adicionalmente para disponibilizar os sub-recursos apropriados.

⬇️ Cabeçalhos de resposta para /blog

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

⬇️ Cabeçalhos de resposta para /app

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA

Estratégia: dicas do lado do servidor necessárias na primeira solicitação

Pode haver casos em que você precise de mais do que o conjunto padrão de dicas na primeira solicitação. No entanto, isso provavelmente é raro, então analise o raciocínio.

A primeira solicitação realmente significa a primeira solicitação de nível superior para essa origem, enviada naquela sessão de navegação. O conjunto padrão de dicas inclui o nome do navegador com a versão principal, a plataforma e o indicador de dispositivo móvel. A pergunta a ser feita aqui é: você precisa de dados estendidos no carregamento da página inicial?

Para dicas adicionais na primeira solicitação, há duas opções. Primeiro, você pode usar o cabeçalho Critical-CH. Ele tem o mesmo formato de Accept-CH, mas informa ao navegador que ele precisará repetir a solicitação imediatamente se a primeira tiver sido enviada sem a dica crítica.

⬆️ Solicitação inicial

[With default headers]

⬇️ Cabeçalhos de resposta

Accept-CH: Sec-CH-UA-Model
Critical-CH: Sec-CH-UA-Model

🔃 O navegador tenta fazer a solicitação inicial novamente com o cabeçalho extra

[With default headers + …]
Sec-CH-UA-Model: Pixel 5

Isso vai sobrecarregar a nova tentativa na primeira solicitação, mas o custo de implementação é relativamente baixo. Envie o cabeçalho extra e o navegador fará o resto.

Para situações em que você realmente precisa de mais dicas no primeiro carregamento de página, a proposta de confiabilidade das dicas do cliente mostra uma rota para especificar dicas nas configurações do nível da conexão. Isso faz uso da extensão Application-Layer Protocol Settings(ALPS) para TLS 1.3 para ativar a transmissão antecipada de dicas em conexões HTTP/2 e HTTP/3. Esse está ainda no estágio inicial, mas se você gerencia ativamente suas próprias configurações de TLS e conexão, esse é um momento ideal para contribuir.

Estratégia: suporte legado

Talvez você tenha código legado ou de terceiros no seu site que dependa de navigator.userAgent, incluindo partes da string do user agent que serão reduzidas. Em longo prazo, você deve planejar a migração para as chamadas navigator.userAgentData equivalentes, mas há uma solução provisória.

UA-CH retrofill é uma pequena biblioteca que permite substituir navigator.userAgent por uma nova string criada a partir dos valores navigator.userAgentData solicitados.

Por exemplo, o código a seguir gera uma string de user agent que inclui também a dica "modelo":

import { overrideUserAgentUsingClientHints } from './uach-retrofill.js';
overrideUserAgentUsingClientHints(['model'])
  .then(() => { console.log(navigator.userAgent); });

A string resultante mostraria o modelo Pixel 5, mas ainda mostraria a 92.0.0.0 reduzida porque a dica uaFullVersion não foi solicitada:

Mozilla/5.0 (Linux; Android 10.0; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.0.0 Mobile Safari/537.36

Suporte adicional

Se essas estratégias não abrangem seu caso de uso, inicie uma Discussão no repositório privacy-sandbox-dev-support para que possamos analisar seu problema juntos.

Foto de Ricardo Rocha no Unsplash