Click Fraud Prevention and Attribution Sent to Advertiser

Earlier this year, Safari was the first browser to ship a proposed web standard for measuring advertising in a privacy-preserving way – Private Click Measurement, or PCM. Today we’re happy to announce three major updates to PCM, available in our iOS/iPadOS 15 and macOS Monterey betas:

  • Attribution reports also sent to click destination.
  • Click fraud prevention with unlinkable tokens.
  • IP address protection for attribution reports.

All of it is covered in Kate’s WWDC session. There are also two minor updates to naming and data types so look out for those below.

Let’s jump in.

Quick PCM Refresher

PCM allows for measurement of clicks which navigate the user from one website to another or from an iOS app to a website. The website or app where the click happens is called the click source, and the website the user is navigated to is called the click destination.

Attribution Reports Also Sent to Click Destination

We’ve designed PCM’s attribution reports to ensure they make sense to both the click source and the click destination, i.e. no opaque IDs that can only be understood or decoded by one party. PCM now sends the resulting attribution report to both click source and destination to help advertisers validate data and be in control of their ad measurement. The two reports are sent independently with a 24-48 hour delay (each report gets its own delay within those 24-48 hours). Since PCM reports already contain information about both click source and destination, there is no new privacy risk involved in sending it to both places (they could have already shared this information).

PCM’s Debug Mode (see “Testing and Debugging” in our previous blog post) sends them independently too but with the shorter 10 second delay, i.e. one after 10 seconds and one after 10+10=20 seconds.

Click Fraud Prevention With Unlinkable Tokens

We mentioned in our introductory blog post on PCM that fraud prevention is a top request for the feature and we’re super excited to announce that optional unlinkable tokens for click fraud prevention are now supported. The cryptographic operations required for blinding and unblinding the tokens are only available on iOS/iPadOS 15 and macOS Monterey so no such tokens will be provided by clients on older operating systems. However, PCM will still work and send attribution reports if you opt-in to tokens in a Safari version that doesn’t support them. Also, unlinkable tokens for click fraud prevention are only available in PCM web-to-web for now.

An unlinkable token provides a privacy-preserving proof, generated by the click-source and the client, of a unique click event on the attributed link. Unlinkable tokens are implemented using RSA blind signatures, a well-studied cryptographic construction that guarantees unlinkability between the moment the token is getting signed and the verification of the resulting signature, through blinding and unblinding operations that are performed on the client side. In contrast with some other cryptographic token constructions, blind signatures provide public verifiability, allowing both the click source and click destination to verify the authenticity of the click event on the click’s source website.

This is how you as a developer of the click source website opt in to click fraud prevention with unlinkable tokens:

Step 1: Generate an RSA Key Pair

Unlinkable tokens require a public key for token generation and validation, and a corresponding private key for signing. PCM supports three different RSA key sizes: 2048, 3072 and 4096 bits. The expected encoding of the public key is a Base64-encoded SPKI with the RSA-PSS OID and the parameters corresponding to the RSABSSA IETF draft.

Step 2: Add the New Link Attribute attributionsourcenonce

Add a nonce on the click source side:

<a href="https://shop.example/productABC.html" attributionsourceid=3 attributiondestination="https://shop.example" attributionsourcenonce="ABCDEFabcdef0123456789"></a>

The attributionsourcenonce is only in place to help the click source server know the context for which it’s signing an unlinkable token. The click source is intended to uniquely and ephemerally identify a specific click event in the eyes of the server. When the server is asked to sign an unlinkable token it’ll get the attributionsourcenonce and can make a decision as to whether the click event was trustworthy or not.

The attributionsourcenonce needs to be a Base64URL encoded 128-bit/16-byte value. Any smaller or larger value will cancel the issuance flow of the fraud-prevention signature. Any non Base64URL encoded value will also cancel the token transaction. Web Inspector will log a warning if the attributionsourcenonce is malformed.

Step 3: Respond to a Request for Your Public Key

The browser and any validating party needs to be able to fetch your public key at any point in time from this well-known location: https://clicksource.example/.well-known/private-click-measurement/get-token-public-key/.

Your server’s response should look like this, with its key Base64URL-encoded:

  "token_public_key": "MIICUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAg8AMIICCgKCAgEAoGhU5Mgsbb51ZbJVPHSgf8c93TJdtkxeKfyxQ5fCpwE2Fe9xJ7tByExdGKj4XO+HFi7npmtEPzR4cRXdsAL7YcH5UXNbVhXmVcbFCBXks+Ih+jqLwfNac0wPLG5K1Zzhf1gZ++JBzVjw87zvqpWrzzxviuV//0sn/u7f01E1OdaD83110fhfiXp/Ex62Q2uhcek0hqbqEvyKlLVBOjlJFJc2FLyw+l8+9xd7GcX1ZRyPx4lITvYG7KIbSMrFTfuQNOyJf4DlO97qq08R6Utl249AnBfLe3ZDbWBnl0fDOwkJgBmbaa7EnRlQ3p6Ir2SY1hNTnzW+p2ceytIMYwTMSES7+j21oeTUC+OmcC/5g05AgxROzUJPZdyY33m4Q7lqkHkLAYtdN2TVCP79MuswS+fJJQOD/dDCqq/hk0MySLCbnUGe5lyFBoO5vBMH5k38LjSQuN6jfP7quYA6cOONzmn842eLT61tIjRoX2czeUJrSmx89SfY8WnFE2fhk9G52cXp6L2Vzr5IV7rOws3ZPw+RnjKnZZaejs0bKGOXC1+jl+u4A5ip55ohlUjm7lvDtKFAeJ7gajJBtiNnq3s3m/IMkv7ztCQpv0pBxst6MmvNOO0jOQvYkzQbGooI1/qjeDup0BYY67xxyNRaA9V4CKEJ7j/hznrAmjSiz0LSqTkCAwEAAQ=="

Step 4: Receive Token Signing Request, Sign, and Respond

After the browser has requested your public key, it will send your server a signing request with an unlinkable token to this well-known location: https://clicksource.example/.well-known/private-click-measurement/sign-unlinkable-token/.

The request body looks like this:

  "source_engagement_type": "click",
  "source_nonce": "ABCDEFabcdef0123456789",
  "source_unlinkable_token": "BC16WmucFh4u8pnfKX+3oRLyu2Bkc39UhMDt8ncOHQsd1Joo5ZslNVNdYajMQaNcOdlCpb6weGOE0R9nHtMjzMyUyJWx1T6ADsJsuFwfHvaVGY6v4fOHRc5P0WReOaiBgkGnDwOdG38rQcKk9lAWHCrcSSCsPTuA6L2W81C9/+0fUED+HY8Dqh1q7AkK/dJbsH0oA1nkYPHhPwghdp4QHZzTPSIHtQt/kNUXjT6Z2UPPEUelZNuEYKHUYyKrsKHZhP/2SJmJzJRrV3wb8chKxOpLmQPRkuDBRLIjqe+o7d2IHe4/5Gt1S3m/jrNSggUb8hekHD9C6WLcZ2tVI2A4ALV4clkJAOMtOH819KEd7fQgCT2kRjvz5EkhVto7WHhToCAbLSFCUjucMWqG7o8iRjy6BGvz09GdSNYBSeALwKm+QjOtsuh+sHMh/H0ngqRbT6RgRa8a+4ejsMCeoqZ52H9X6B+yJywT9eLqcKjDnAk2CJR+EOt4Q6FeMqkfUz5SJtGkjGv1PMnXw3PqT3SzuL3B6d3nW7DySkWkR1xMcZnIC0vW7gMgj9O5+Jq3WQh1XlNqkCraPZIbDFGeCIs4LHMRfTA8yzWFEL1CwdrMDjrmpqtzENHGxFHRr/TKozc3v/vGKc2rE9EfhWSAATFSIjeyUUByUCySR3rCzBssaR0=",
  "version": 2

The source_nonce is the attributionsourcenonce that was provided in the link and the source_unlinkable_token is the Base64URL-encoded token to sign.

If you deem this is a valid request, your server performs the BlindSign operation of the RSABSSA draft, which is a RSA private key operation on the browser-provided source_unlinkable_token and returns the blind signature as a Base64-encoded output labeled “unlinkable_token" in a response like this:

  "unlinkable_token": "QfvIa2RF16zPcXmsbhrsX7ZcUDAk1rtoOcrqE1XoaK7MUrsLNeolZwzNhkOUSSwJKiXPJpam4q1/teU379uiizDFTLPPaPXqxoEq7L/+QjkGmh5lrmFYSbN475Lm+hb9k1rrPT+ek4PDQ3PZpk35h/cB36iE4cf0/F72Iuf4gnn2S/gGL4oZDb4Yi9njY186TzAZ3E9/1bGKiw6qg1gFD92i7yEm//KdqlcwTrdvaMkqzZtD7KmCzkaub46bVIokLwOuDa2SCj9dDaBVRmcHIAtF174nARQjKkp3do/q8pdZh+syeEUYmnpl+qe+yG9+AlSWQXI+3zW6KZ0PbFAQ/hrmqTU9v3vDOdKFi/gr321A6XeUtL4dQxr/Anw0opLxX/lcwsa6gFiWnpMqBv7x+xnhJBFJI+0USUxq2gXVonhXBg/HVMhrW+eEbqMtrVF23JkXaYX1eaQrV9lfFf6LgHo+7GAVbHF6Y7J4IwfwuvksDfJ1/9axdO5jKQ58gCAlH0zpVgMxNmBcAgCBUv3ebZmrKNzNFSjsodBQ30FmKMPkT1l0eWlaDBz5QIG4y1Pc+ZKW9tCV0rFTg4FMoeN8aayUkTCKGpnRgmfO03uQMeQbuPOkAndjyXQyhevOTespEo9X6Z1KI+w7dVmPL/8oG8Mx+2bic6eszWprP/Kef64="

Step 5: Respond to Another Request for Your Public Key

When it’s time for the browser to send the attribution report, it will again fetch the public key from your server and make sure that it’s the same public key. This is how PCM makes sure that the server doesn’t use user-specific keys. Note that this second request for your public key may happen multiple days after the click you are measuring and that the browser will discard the attribution data if it receives a mismatching key.

There is currently no support for managed key renewal. We intend to support responses with two public keys – one current and one decommissioned. That way, the browser can compare with both and allow attribution with tokens that were signed with the private key matching the decommissioned public key.

Step 6: Receive and Validate the Attribution Report

The resulting attribution report will contain a signed secret token (source_secret_token) that your server has never seen before and that your server cannot link to its corresponding unlinkable token (source_unlinkable_token). However, the signature you created with your private key will be valid for the secret token, effectively proving to you that you deemed this a trustworthy click some time back. Make sure to validate the signature.

Since the click destination receives attribution reports too, they should validate the token as well.

The report will look like this, with the source_secret_token and source_secret_token_signature Base64URL-encoded:

  "source_engagement_type": "click",
  "source_site": "clicksource.example",
  "source_id": 201,
  "attributed_on_site": "shop.example",
  "trigger_data": 10,
  "version": 2,
  "source_secret_token": "7JgS5aIQPUm9T5DcT2a91NC1lt2xq5bLjuaJi4A/Wbg=",
  "source_secret_token_signature": "ThyNW13Z7DTVSj/U8+5oWyG73bskeB2ZtmyG+tZRbuX216mK2F7wgv8piQEFxjDC49O9fPP7DFovcJbGOx3JR7zS7fDq3pYOKz/LkF8I2DkLz9jDcgXxgddMRfFsG8ud6FyEtmESiFgF23Nfqnn4JrhC4luDb7JceOdFsNWtXTURYeVcnARhKlcQ8h8Gs0zTCTGz2LkhwOHUlRYUTnqy5Ng9DiK4Rb9XSaTTPFPK2VJ7PNDmVFtvj1uc2OSxO8AJu9FYF4pv0wQjXjBKy00BF6Qm3m7vZXIwu7pTHBbXlb7DpJ2/15OblNEZrbS0BbXUzv8gqhz6MqmstltZdDiQZHRNDXabmPX7Rm1NRiy5XBr2oF+YBcSHJ0xV3YEH3XoeGN2McBoZCQ7CLhhMcDQLGVBv0L05Wp5rwausxd6Yerf01ebedk5D7RlQmrQ0lMo6fnqm6/F9gEHil2axA8zB/xThPD4ZQ0ARHkGWQYraQzGq5Xj65CIa1yV174iDcf6ZP18Hvkj1VcQIderLg0oMI6FOFzSYYeWJR0vKSc6C+y6jAX4dPPS+1uKRMBBijdv/4H9GazAQHhXLGKxaRgbLg+mLXKG4I9YoPVgU/gc/ePeTAyXFs+EgTi5ExpTF2Klv10E8HTtYLAO76FQVjnDNB98dq+XIbFHMuVKzAaBFr7s="

IP Address Protection for Attribution Reports

Safari 15 already hides the devices IP address from known trackers so if PCM is communicating with a known tracker, that protection is there. On top of that, PCM now protects all of the requests it makes that don’t happen very close in time to a linkable event in a first-party context, i.e. requests that don’t have a high likelihood of being matched based on time with very recent non-protected requests. The device IP address is hidden by sending requests through a two-hop relay which makes sure that Apple doesn’t get to see things like the attribution data. Learn more about this technology in the WWDC session “Get ready for iCloud Private Relay.”

PCM Debug Mode skips IP address protection so that you can test locally.

Attribute Name and Data Type Change

Our introductory blog post on PCM also mentioned that there will likely be changes to naming due to the ongoing efforts to harmonize as much as possible with Google’s alternative proposal Click Through Attribution Reporting API.

The PCM naming and data type changes in Safari 15 are:

  • The click destination is now stated in the anchor element’s attributiondestination attribute (used to be attributeon).
  • attributionsourceid is now an unsigned long, i.e. a non-negative integer (used to be a string).

This means that a PCM link now looks like this:

<a href="…" attributionsourceid=3 attributiondestination="https://shop.example"></a>

Feature Enabled and Disabled Should Be Indistinguishable

Our continued work in this space has taught us that it’s important to design ad measurement features so that websites cannot tell if the user has the feature enabled or not, at least not at page render time. The reason why is to offer users a real choice. If a webpage can tell that the user has chosen to disable ad measurement, it may pressure the user to enable it. We encourage other browser vendors in this space to think about this important aspect of user agency, especially in light of the multi year effort to make the web work well without third-party cookies (as a user setting or as the default).


Q1: My triggering event is not accepted. How should I debug?
A1: Make sure the HTTP request to https://clickSource.example/.well-known/private-click-measurement/trigger-attribution/ is done as the result of a same-site HTTP redirect, e.g. a clickSource.example to clickSource.example redirect. Otherwise it won’t be accepted as a triggering event. There are two reasons for this requirement:

  • Support for legacy tracking pixels. With a redirect, nothing needs to change on the click destination site.
  • Server-side control. By requiring a server-side redirect, we enable the domain owner to be in control of when a triggering event is fired. If it was just a HTTP request, any JavaScript on the destination site could fire triggering events. The redirect is not a fool proof system but it offers at least one checkpoint of control.

Q2: I’m not receiving attribution reports in my testing. How should I debug?
A2: Attribution reports are sent over HTTPS to the registrable domain of the click source and click destination. There needs to be a valid TLS certificate for each of those domains and the server needs to accept a request to the well-known location.

Q3: Will Apple add support for unlinkable tokens for triggering events on the destination site?
A3: Yes, that is our intention.

Q4: Will these enhancements be available in Safari 15 on older versions of macOS?
A4: Attribution reports also sent to click destination will be available in Safari 15 across the board. However, click fraud prevention with unlinkable tokens relies on cryptographic functionality that is only available starting with iOS/iPadOS 15 and macOS Monterey.