Este documento é um guia de início rápido para usar o Armazenamento compartilhado e a API Private Aggregation. Você precisa entender as duas APIs porque o Shared Storage armazena os valores e a Private Aggregation cria os relatórios agregáveis.
Público-alvo:tecnologias de publicidade e provedores de medição.
API Shared Storage
Para evitar o rastreamento entre sites, os navegadores começaram a particionar todas as formas de armazenamento, incluindo armazenamento local, cookies e assim por diante. Mas há casos de uso em que o armazenamento não particionado é necessário. A API Shared Storage oferece acesso de gravação ilimitado em diferentes sites de nível superior com acesso de leitura que preserva a privacidade.
O armazenamento compartilhado é restrito à origem do contexto (o autor da chamada de
sharedStorage).
O armazenamento compartilhado tem um limite de capacidade por origem, e cada entrada é limitada a um número máximo de caracteres. Se o limite for atingido, nenhuma outra entrada será armazenada. Os limites de armazenamento de dados estão descritos na explicação sobre o armazenamento compartilhado.
Invocar o armazenamento compartilhado
As adtechs podem gravar no armazenamento compartilhado usando JavaScript ou um cabeçalho de resposta. A leitura do armazenamento compartilhado só ocorre em um ambiente JavaScript isolado chamado worklet.
Usando JavaScript: as adtechs podem realizar funções específicas do armazenamento compartilhado, como definir, anexar e excluir valores fora de um worklet JavaScript. No entanto, funções como leitura do armazenamento compartilhado e execução de agregação privada precisam ser concluídas por um worklet JavaScript. Os métodos que podem ser usados fora de um worklet JavaScript estão em Superfície da API proposta: fora do worklet.
Os métodos usados no worklet durante uma operação podem ser encontrados em Superfície da API proposta: no worklet.
Como usar cabeçalhos de resposta
Assim como no JavaScript, apenas funções específicas, como definir, anexar e excluir valores no armazenamento compartilhado, podem ser feitas usando cabeçalhos de resposta. Para trabalhar com o armazenamento compartilhado em um cabeçalho de resposta,
Shared-Storage-Writable: ?1precisa ser incluído no cabeçalho da solicitação.Para iniciar uma solicitação do cliente, execute o seguinte código, dependendo do método escolhido:
Como usar o
fetch()fetch("https://a.example/path/for/updates", {sharedStorageWritable: true});Como usar uma tag
iframeouimg<iframe src="https://a.example/path/for/updates" sharedstoragewritable></iframe>Usar um atributo IDL com uma tag
iframeouimglet iframe = document.getElementById("my-iframe"); iframe.sharedStorageWritable = true; iframe.src = "https://a.example/path/for/updates";
Para mais informações, consulte Armazenamento compartilhado: cabeçalhos de resposta.
Como gravar no armazenamento compartilhado
Para gravar no armazenamento compartilhado, chame sharedStorage.set() de dentro ou de fora de um
worklet JavaScript. Se for chamada de fora do worklet, os dados serão gravados na origem do contexto de navegação de onde a chamada foi feita. Se for chamado de
dentro do worklet, os dados serão gravados na origem do contexto de navegação
que carregou o worklet. As chaves definidas têm uma data de validade de 30 dias a partir da última atualização.
O campo ignoreIfPresent é opcional. Se estiver presente e definido como true, a chave não será atualizada se já existir. A validade da chave é renovada para 30 dias a partir da chamada set(), mesmo que a chave não seja atualizada.
Se o armazenamento compartilhado for acessado várias vezes no mesmo carregamento de página com a mesma
chave, o valor da chave será substituído. É uma boa ideia usar sharedStorage.append() se a chave precisar manter o valor anterior.
Usando JavaScript
Fora do worklet:
window.sharedStorage.set('myKey', 'myValue1', { ignoreIfPresent: true }); // Shared Storage: {'myKey': 'myValue1'} window.sharedStorage.set('myKey', 'myValue2', { ignoreIfPresent: true }); // Shared Storage: {'myKey': 'myValue1'} window.sharedStorage.set('myKey', 'myValue2', { ignoreIfPresent: false }); // Shared Storage: {'myKey': 'myValue2'}Da mesma forma, dentro do worklet:
sharedStorage.set('myKey', 'myValue1', { ignoreIfPresent: true });Como usar cabeçalhos de resposta
Também é possível gravar no armazenamento compartilhado usando cabeçalhos de resposta. Para fazer isso, use
Shared-Storage-Writeno cabeçalho da resposta com os seguintes comandos:Shared-Storage-Write : set;key="myKey";value="myValue";ignore_if_presentShared-Storage-Write : set;key="myKey";value="myValue";ignore_if_present=?0Vários itens podem ser separados por vírgulas e combinar
set,append,deleteeclear.Shared-Storage-Write : set;key="hello";value="world";ignore_if_present, set;key="good";value="bye"
Como anexar um valor
É possível anexar um valor a uma chave usando o método "append". Se a chave não existir, chamar append() vai criar a chave e definir o valor. Isso pode
ser feito usando JavaScript ou um cabeçalho de resposta.
Usando JavaScript
Para atualizar valores de chaves atuais, use
sharedStorage.append()de dentro ou de fora do worklet.window.sharedStorage.append('myKey', 'myValue1'); // Shared Storage: {'myKey': 'myValue1'} window.sharedStorage.append('myKey', 'myValue2'); // Shared Storage: {'myKey': 'myValue1myValue2'} window.sharedStorage.append('anotherKey', 'hello'); // Shared Storage: {'myKey': 'myValue1myValue2', 'anotherKey': 'hello'}Para anexar dentro do worklet:
sharedStorage.append('myKey', 'myValue1');Como usar cabeçalhos de resposta
Assim como ao definir um valor no armazenamento compartilhado, você pode usar o
Shared-Storage-Writeno cabeçalho da resposta para transmitir o par de chave-valor.Shared-Storage-Write : append;key="myKey";value="myValue2"
Atualização em lote de valores
É possível chamar sharedStorage.batchUpdate() de dentro ou de fora de um worklet JavaScript e transmitir uma matriz ordenada de métodos que especificam as operações escolhidas. Cada construtor de método aceita os mesmos parâmetros que o método individual correspondente para definir, adicionar, excluir e limpar.
É possível chamar batchUpdate() do JavaScript ou usar um cabeçalho de resposta:
Usando JavaScript
Os métodos JavaScript que podem ser usados com
batchUpdate()incluem:SharedStorageSetMethod(): grava um par de chave-valor no armazenamento compartilhado.SharedStorageAppendMethod(): adiciona um valor a uma chave existente no armazenamento compartilhado ou grava um par de chave-valor se a chave ainda não existir.SharedStorageDeleteMethod(): exclui um par de chave-valor do armazenamento compartilhado.SharedStorageClearMethod(): limpa todas as chaves no armazenamento compartilhado.
sharedStorage.batchUpdate([ new SharedStorageSetMethod('keyOne', 'valueOne'), new SharedStorageAppendMethod('keyTwo', 'valueTwo'), new SharedStorageDeleteMethod('keyThree'), new SharedStorageClearMethod() ]);Como usar cabeçalhos de resposta
Shared-Storage-Write : set;key=keyOne;value=valueOne, append;key=keyTwo;value=valueTwo,delete;key=keyThree,clear
Usar cabeçalhos de resposta realiza batchUpdate() para todos os métodos no cabeçalho.
Como fazer a leitura do armazenamento compartilhado
Só é possível ler do armazenamento compartilhado em um worklet.
await sharedStorage.get('mykey');
A origem do contexto de navegação de onde o módulo do worklet foi carregado determina de quem o armazenamento compartilhado é lido.
Excluir do armazenamento compartilhado
É possível fazer exclusões do armazenamento compartilhado usando JavaScript de dentro
ou fora do worklet ou usando cabeçalhos de resposta com delete(). Para excluir todas as chaves de uma vez, use clear() em qualquer uma das opções.
Usando JavaScript
Para excluir do armazenamento compartilhado fora do worklet:
window.sharedStorage.delete('myKey');Para excluir do armazenamento compartilhado de dentro do worklet:
sharedStorage.delete('myKey');Para excluir todas as chaves de uma só vez de fora do worklet:
window.sharedStorage.clear();Para excluir todas as chaves de uma vez de dentro do worklet:
sharedStorage.clear();Como usar cabeçalhos de resposta
Para excluir valores usando cabeçalhos de resposta, também é possível usar
Shared-Storage-Writeno cabeçalho de resposta para transmitir a chave a ser excluída.delete;key="myKey"Para excluir todas as chaves usando cabeçalhos de resposta:
clear;
Como ler grupos de interesse da API Protected Audience do armazenamento compartilhado
É possível ler os grupos de interesse da API Protected Audience em um worklet do armazenamento compartilhado. O método interestGroups() retorna uma matriz de objetos StorageInterestGroup, incluindo os atributos AuctionInterestGroup e GenerateBidInterestGroup.
O exemplo a seguir mostra como ler os grupos de interesse do contexto de navegação e algumas operações possíveis que podem ser realizadas nos grupos de interesse recuperados. Duas operações possíveis usadas são encontrar o número de grupos de interesse e encontrar o grupo com a maior contagem de lances.
async function analyzeInterestGroups() {
const interestGroups = await interestGroups();
numIGs = interestGroups.length;
maxBidCountIG = interestGroups.reduce((max, cur) => { return cur.bidCount > max.bidCount ? cur : max; }, interestGroups[0]);
console.log("The IG that bid the most has name " + maxBidCountIG.name);
}
A origem do contexto de navegação de onde o módulo worklet foi carregado determina a origem dos grupos de interesse que estão sendo lidos por padrão. Para saber mais sobre a origem padrão do worklet e como mudá-la, consulte a seção Execução do armazenamento compartilhado e da agregação privada no tutorial da API Shared Storage.
Opções
Todos os métodos modificadores do armazenamento compartilhado aceitam um objeto de opções opcional como o último argumento.
withLock
A opção withLock é opcional. Se especificada, essa opção instrui o método a adquirir um bloqueio para o recurso definido usando a API Web Locks antes de continuar. Um nome de bloqueio é transmitido ao solicitar o bloqueio. O nome representa um recurso cujo uso é coordenado em várias guias,trabalhadores ou códigos na origem.
A opção withLock pode ser usada com os seguintes métodos modificadores do armazenamento compartilhado:
- set
- append
- excluir
- limpar
- atualização em lote
É possível definir o bloqueio usando JavaScript ou um cabeçalho de resposta:
Usando JavaScript
sharedStorage.set('myKey', 'myValue', { withLock: 'myResource' });Como usar cabeçalhos de resposta
Shared-Storage-Write : set;key="myKey";value="myValue",options;with_lock="myResource"
Os bloqueios do armazenamento compartilhado são particionados pela origem dos dados. Os bloqueios são independentes de qualquer bloqueio obtido usando o método request() do LockManager, seja em um contexto window ou worker. No entanto, eles compartilham o mesmo escopo que os bloqueios obtidos usando request() no contexto SharedStorageWorklet.
Embora o método request() permita várias opções de configuração, os bloqueios adquiridos no armazenamento compartilhado sempre obedecem às seguintes configurações padrão:
mode: "exclusive": nenhum outro bloqueio com o mesmo nome pode ser mantido simultaneamente.steal: false: os bloqueios atuais com o mesmo nome não são liberados para acomodar outras solicitações.ifAvailable: false: as solicitações aguardam indefinidamente até que o bloqueio fique disponível.
Quando usar withLock
Os bloqueios são úteis em cenários em que pode haver vários worklets em execução simultânea (por exemplo, vários worklets em uma página ou em guias diferentes), cada um analisando os mesmos dados. Nesse cenário, é uma boa ideia envolver o código do worklet relevante com um bloqueio para garantir que apenas um worklet esteja processando relatórios por vez.
Outra situação em que os bloqueios são úteis é quando há várias chaves que precisam ser lidas juntas em um worklet e o estado delas precisa ser sincronizado. Nesse caso, é necessário envolver as chamadas get com um bloqueio e adquirir o mesmo bloqueio ao gravar nessas chaves.
Ordem dos bloqueios
Devido à natureza dos bloqueios da Web, os métodos modificadores podem não ser executados na ordem definida. Se a primeira operação exigir um bloqueio e for atrasada, a segunda poderá começar antes da conclusão da primeira.
Por exemplo:
// This line might pause until the lock is available.
sharedStorage.set('keyOne', 'valueOne', { withLock: 'resource-lock' });
// This line will run right away, even if the first one is still waiting.
sharedStorage.set('keyOne', 'valueTwo');
Exemplo de modificação de várias chaves
A opção withLock com batchUpdate() garante a exclusão mútua com outras operações simultâneas que adquirem o mesmo bloqueio. Você só pode aplicar a opção withLock para batchUpdate() em todo o lote. Aplicar withLock a qualquer objeto de método individual no lote gera uma exceção.
Este exemplo usa um bloqueio para garantir que as operações de leitura e exclusão no worklet aconteçam juntas, evitando interferências de fora do worklet.
O exemplo de modify-multiple-keys.js a seguir define novos valores para keyOne e keyTwo com modify-lock e executa a operação modify-multiple-keys do worklet:
// modify-multiple-keys.js
sharedStorage.batchUpdate([
new SharedStorageSetMethod('keyOne', calculateValueFor('keyOne')),
new SharedStorageSetMethod('keyTwo', calculateValueFor('keyTwo'))
], { withLock: 'modify-lock' });
const modifyWorklet = await sharedStorage.createWorklet('modify-multiple-keys-worklet.js');
await modifyWorklet.run('modify-multiple-keys');
Em seguida, dentro do modify-multiple-keys-worklet.js, você pode solicitar o bloqueio usando navigator.locks.request() para ler e modificar as chaves conforme necessário.
// modify-multiple-keys-worklet.js
class ModifyMultipleKeysOperation {
async run(data) {
await navigator.locks.request('modify-lock', async (lock) => {
const value1 = await sharedStorage.get('keyOne');
const value2 = await sharedStorage.get('keyTwo');
// Do something with `value1` and `value2` here.
await sharedStorage.delete('keyOne');
await sharedStorage.delete('keyTwo');
});
}
}
register('modify-multiple-keys', ModifyMultipleKeysOperation);
Troca de contexto
Os dados do armazenamento compartilhado são gravados na origem (por exemplo, https://example.adtech.com) do contexto de navegação de onde a chamada foi originada.
Quando você carrega o código de terceiros usando uma tag <script>, ele é executado
no contexto de navegação do incorporador. Portanto, quando o código de terceiros
chama sharedStorage.set(), os dados são gravados no armazenamento
compartilhado do incorporador. Quando você carrega o código de terceiros em um iframe, ele recebe um novo contexto de navegação, e a origem dele é a do iframe. Portanto, a chamada sharedStorage.set() feita do iframe armazena os dados no armazenamento compartilhado da origem do iframe.
Contexto próprio
Se uma página própria tiver um código JavaScript de terceiros incorporado que chame
sharedStorage.set() ou sharedStorage.delete(), o par de chave-valor será armazenado
no contexto próprio.
Contexto de terceiros
O par de chave-valor pode ser armazenado no contexto da adtech ou de terceiros
criando um iframe e chamando set() ou delete() no código JavaScript de
dentro do iframe.
API Private Aggregation
Para medir dados agregáveis armazenados no Shared Storage, use a API Private Aggregation.
Para criar um relatório, chame contributeToHistogram() em um worklet com um
bucket e um valor. O bucket é representado por um número inteiro sem sinal de 128 bits, que precisa ser transmitido para a função como um BigInt. O valor é um número inteiro positivo.
Para proteger a privacidade, o payload do relatório, que contém o agrupamento e o valor, é criptografado em trânsito e só pode ser descriptografado e agregado usando o serviço de agregação.
O navegador também limita as contribuições que um site pode fazer para uma consulta de saída. Especificamente, o orçamento de contribuição limita o total de todos os relatórios de um único site para um determinado navegador em um período específico em todos os agrupamentos. Se o orçamento atual for excedido, um relatório não será gerado.
privateAggregation.contributeToHistogram({
bucket: BigInt(myBucket),
value: parseInt(myBucketValue)
});
Execução do armazenamento compartilhado e da agregação privada
Por padrão, ao usar o armazenamento compartilhado com createWorklet(), a origem da partição de dados será a origem do contexto de navegação de invocação, não a origem do próprio script do worklet.
Para mudar o comportamento padrão, defina a propriedade dataOrigin ao chamar
createWorklet.
dataOrigin: "context-origin": (padrão) os dados são armazenados no armazenamento compartilhado da origem do contexto de navegação de invocação.dataOrigin: "script-origin": os dados são armazenados no armazenamento compartilhado da origem do script do worklet. É necessário ativar esse modo.dataOrigin: "https://custom-data-origin.example": os dados são armazenados no armazenamento compartilhado de uma origem de dados personalizada. É necessário ativar esse modo e ter o consentimento do proprietário da origem de dados personalizada, conforme detalhado em Origem de dados personalizada.
sharedStorage.createWorklet(scriptUrl, {dataOrigin: "script-origin"});
Para ativar, ao usar "script-origin" ou uma origem personalizada, o endpoint do script precisa responder com o cabeçalho Shared-Storage-Cross-Origin-Worklet-Allowed. Para solicitações entre origens, o CORS também precisa estar ativado.
Shared-Storage-Cross-Origin-Worklet-Allowed : ?1
Access-Control-Allow-Origin: *
Também é possível executar scripts de origem cruzada usando um iframe de terceiros. Nesse caso, as ações do armazenamento compartilhado estarão no contexto de navegação de terceiros.
Como usar um iframe entre origens
Um iframe é necessário para invocar o worklet de armazenamento compartilhado.
No iframe do anúncio, carregue o módulo worklet chamando addModule(). Para executar o método registrado no arquivo worklet sharedStorageWorklet.js, chame sharedStorage.run() no mesmo JavaScript do iframe de anúncio.
const sharedStorageWorklet = await window.sharedStorage.createWorklet(
'https://any-origin.example/modules/sharedStorageWorklet.js'
);
await sharedStorageWorklet.run('shared-storage-report', {
data: { campaignId: '1234' },
});
No script do worklet, você precisará criar uma classe com um método run
assíncrono e register para ser executado no iframe do anúncio. Dentro de
sharedStorageWorklet.js:
class SharedStorageReportOperation {
async run(data) {
// Other code goes here.
bucket = getBucket(...);
value = getValue(...);
privateAggregation.contributeToHistogram({
bucket,
value
});
}
}
register('shared-storage-report', SharedStorageReportOperation);
Como usar solicitações entre origens
O Shared Storage e a Private Aggregation permitem a criação de worklets de origem cruzada sem a necessidade de iframes de origem cruzada.
A página própria também pode invocar uma chamada createWorklet() para o endpoint JavaScript de origem cruzada. Você precisa definir a origem da partição de dados
do worklet como a origem do script ao criar o worklet.
async function crossOriginCall() {
const privateAggregationWorklet = await sharedStorage.createWorklet(
'https://cross-origin.example/js/worklet.js',
{ dataOrigin: 'script-origin' }
);
await privateAggregationWorklet.run('pa-worklet');
}
crossOriginCall();
O endpoint JavaScript de origem cruzada precisa responder com os cabeçalhos
Shared-Storage-Cross-Origin-Worklet-Allowed e observar que o CORS está ativado para
a solicitação.
Shared-Storage-Cross-Origin-Worklet-Allowed : ?1
Os worklets criados com o createWorklet() terão selectURL e run().
O recurso addModule() não está disponível para isso.
class CrossOriginWorklet {
async run(data){
// Other code goes here.
bucket = getBucket(...);
value = getValue(...);
privateAggregation.contributeToHistogram({
bucket,
value
});
}
}
Origem de dados personalizada
Quando o dataOrigin é definido como uma origem válida, o proprietário do dataOrigin precisa consentir com o processamento do armazenamento compartilhado para esse dataOrigin hospedando um arquivo JSON que lista a origem do script do worklet no caminho /.well-known/shared-storage/trusted-origins. O arquivo precisa ser uma matriz de objetos com as chaves scriptOrigin e contextOrigin. Os valores dessas chaves podem ser uma string ou uma matriz de strings.
Crie o arquivo trusted-origins usando as seguintes informações:
- Contexto do autor da chamada
- Origem e URL do script do worklet
- Origem e proprietário dos dados
A tabela a seguir mostra como você pode construir o arquivo trusted-origins com base nessas informações:
| Contexto do autor da chamada | URL do script do worklet | Origem dos dados | Proprietário dos dados | Arquivo JSON de origens confiáveis do proprietário da origem de dados |
|---|---|---|---|---|
| https://publisher.example | https://publisher.example/script.js | context-origin | https://publisher.example | JSON não é necessário |
| https://publisher.example | https://ad.example/script.js | script-origin | https://ad.example | JSON não é necessário |
| https://publisher.example | https://cdn-ad.example/script.js | https://ad.example | https://ad.example |
[{ "scriptOrigin": "https://cdn-ad.example", "contextOrigin": "https://publisher.example" }] |
| Qualquer pessoa que ligar | https://cdn-ad.example/script.js | https://ad.example | https://ad.example |
[{ "scriptOrigin": "https://cdn-ad.example", "contextOrigin": "*" }] |
| https://publisher-a.example, OR https://publisher-b.example | https://cdn-ad.example/script.js | https://ad.example | https://ad.example |
[{ "scriptOrigin": "https://cdn-ad.example", "contextOrigin": [ "https://publisher-a.example", "https://publisher-b.example" ] }] |
| https://publisher.example | https://cdn-a-ad.example/script.js, OR https://cdn-b-ad.example/script.js | https://ad.example | https://ad.example |
[{ "scriptOrigin": [ "https://cdn-a-ad.example", "https://cdn-b-ad.example" ], "contextOrigin": "https://publisher.example" }] |
Por exemplo, o JSON a seguir pode ser hospedado em https://custom-data-origin.example/.well-known/shared-storage/trusted-origins e combinar todos os processadores permitidos de dados do armazenamento compartilhado para a origem https://custom-data-origin.example.
[
{
"scriptOrigin": "https://script-origin.a.example",
"contextOrigin": "https://context-origin.a.example"
},
{
"scriptOrigin": "https://script-origin.b.example",
"contextOrigin": [
"https://context-origin.a.example",
"https://context-origin.b.example"
]
}]
Próximas etapas
As páginas a seguir explicam aspectos importantes das APIs Shared Storage e Private Aggregation.
- Introdução ao Shared Storage (Chrome para desenvolvedores)
- Casos de uso do Shared Storage (Chrome para desenvolvedores)
- Introdução à agregação particular (Chrome para desenvolvedores)
- Explicação do armazenamento compartilhado (GitHub)
- Explicação sobre agregação privada (GitHub)
- Demonstração de Shared Storage e Private Aggregation
Depois de conhecer as APIs, comece a coletar os relatórios, que são enviados como uma solicitação POST para os seguintes endpoints como JSON no corpo da solicitação.
- Relatórios de depuração:
context-origin/.well-known/private-aggregation/debug/report-shared-storage - Relatórios -
context-origin/.well-known/private-aggregation/report-shared-storage
Depois que os relatórios forem coletados, você poderá testar usando a ferramenta de teste local ou configurar o ambiente de execução confiável para o serviço de agregação e receber os relatórios agregados.
Envie feedback
Compartilhe seu feedback sobre as APIs e a documentação no GitHub.