Note: Read about past updates to this technology in other blog posts about Intelligent Tracking Prevention, the Storage Access API, and ITP Debug Mode.

Intelligent Tracking Prevention (ITP) version 2.3 is included in Safari on iOS 13, the iPadOS beta, and Safari 13 on macOS for Catalina, Mojave, and High Sierra.

Enhanced Prevention of Tracking Via Link Decoration

Our previous release, ITP 2.2, focused specifically on the abuse of so-called link decoration for the purposes of cross-site tracking. With ITP 2.2, when a webpage is navigated to from a domain classified by ITP and the landing URL has a query string or fragment, the expiry of persistent client-side cookies created on that page is 24 hours.

Unfortunately, we see continued abuse of link decoration, so ITP 2.3 takes two new steps to combat this.

Capped Lifetime For All Script-Writeable Website Data

Since ITP 2.2, several trackers have announced their move from first-party cookies to alternate first-party storage such as LocalStorage. ITP 2.3 counteracts this in the following way:

website.example will be marked for non-cookie website data deletion if the user is navigated from a domain classified with cross-site tracking capabilities to a final URL with a query string and/or a fragment identifier, such as website.example?clickID=0123456789 . After seven days of Safari use without the user interacting with a webpage on website.example, all of website.example’s non-cookie website data is deleted.

Together with ITP’s capped expiry of client-side cookies, this change removes trackers’ ability to use link decoration combined with long-term first-party website data storage to track users. Put differently, ITP 2.3 caps the lifetime of all script-writeable website data after a navigation with link decoration from a classified domain.

The reason why we cap the lifetime of script-writable storage is simple. Site owners have been convinced to deploy third-party scripts on their websites for years. Now those scripts are being repurposed to circumvent browsers’ protections against third-party tracking. By limiting the ability to use any script-writeable storage for cross-site tracking purposes, ITP 2.3 makes sure that third-party scripts cannot leverage the storage powers they have gained over all these websites.

document.referrer Downgraded To eTLD+1

Our research has found that trackers, instead of decorating the link of the destination page, decorate their own referrer URL and read the tracking ID through document.referrer on the destination page.

ITP 2.3 counteracts this by downgrading document.referrer to the referrer’s eTLD+1 if the referrer has link decoration and the user was navigated from a classified domain. Say the user is navigated from social.example to website.example and the referrer is https://sub.social.example/some/path/?clickID=0123456789 . When social.example’s script on website.example reads document.referrer to retrieve and store the click ID, ITP will make sure only https://social.example is returned.

For further reading on misuse of the referrer and changes coming to browsers in general, see the WHATWG Fetch issue Limit the length of the Referer header.

Updates To the Storage Access API

Developer Enhancement Requests

Developers have asked us for two changes to the Storage Access API, and we’re happy to provide them in Safari on iOS 13 beta, iPadOS beta, and macOS Catalina beta:

Only consume the user gesture (tap or click) when the user explicitly denies access , i.e. when the user is prompted and picks “Don’t allow.” Previously the gesture was also consumed when the promise was rejected without a user prompt, i.e. when the requesting domain was classified by ITP and had not received user interaction as first-party website the last 30 days of Safari use. This meant the user had to tap or click again to be shown a popup to log in to the third-party service.

, i.e. when the user is prompted and picks “Don’t allow.” Previously the gesture was also consumed when the promise was rejected without a user prompt, i.e. when the requesting domain was classified by ITP and had not received user interaction as first-party website the last 30 days of Safari use. This meant the user had to tap or click again to be shown a popup to log in to the third-party service. Make document.hasStorageAccess() return true when ITP is off. Developers were confused when document.hasStorageAccess() returned false but ITP was off. Now it returns true in that case. Note that a returned true does not guarantee that the third-party can set cookies since Safari’s default cookie policy is to deny cookies for third-parties if they don’t already have cookies.

User Enhancement Request

Users have asked us to cap the number of times they can get asked for storage access by a specific piece of embedded web content.

Some services are requesting storage access on every click or tap, regardless of previous interactions with the user. To counter such repeated prompting, WebKit’s implementation of the Storage Access API will now automatically reject the request for storage access for documents where the user has picked “Don’t Allow” in the prompt twice. The reason why we don’t cap it to a single prompt is that the user may change their mind when they see the result of picking “Don’t Allow” the first time.

We will restrict the API further if we get reports of continued over prompting.

ITP Debug Mode In Safari on macOS Catalina

Safari 13 on macOS includes ITP Debug Mode. It’s been available in Safari Technology Preview for quite some time but now it’s available in regular Safari too so that you can debug your websites with the same Safari your customers are using.

Below is a step-by-step guide on how to use ITP Debug Mode. Note that both menu placement and naming has changed from the earlier experimental feature.

If you prefer to use Console:

Launch the Console app. Click the Action menu → Include Info Messages. Filter on “ITPDebug” without the quotes.

If you prefer to use Terminal:

log stream -info | grep ITPDebug

Now you’re ready to enable ITP Debug Mode and see log output.

Enable the Develop menu through Safari Preferences → Advanced → “Show Develop menu in menu bar.” Click “Intelligent Tracking Prevention Debug Mode” in the Develop menu. When you’re done, disable ITP Debug Mode through the same Develop menu item or by quitting Safari. Don’t leave ITP Debug Mode on when you’re not using it since it logs potentially sensitive information about your browsing. (Logging is done on the ephemeral INFO level.)

With ITP Debug Mode enabled, you will see ITP messages in the log as you browse the web. Whenever ITP decides to schedule deletion of website data it will indicate in the log “all data” or “all but cookies” to tell you whether it’s a regular deletion of all website data or the new capped lifetime of all non-cookie website data as explained above.

The domain 3rdpartytestwebkit.org is permanently classified with tracking capabilities in ITP Debug Mode, so at minimum you should see that domain show up in your log.

Classifying A Custom Domain For Testing

With ITP Debug Mode and User Defaults, you can manually set a custom domain as permanently classified with tracking capabilities. Here’s how you achieve this for a domain called website.example:

Open System Preferences, click Security & Privacy, and unlock the padlock to be able to make changes. Pick the Full Disk Access category to the left. Use the + button to add the Terminal application to the list and make sure its checkbox is ticked. Open Terminal and execute the following command: defaults write com.apple.Safari ITPManualPrevalentResource website.example Go back to Security & Privacy in System Preferences and untick the checkbox for Terminal to not allow it permanent full disk access.

A Note On HttpOnly Cookies

Our blog post on ITP 2.1 provided guidance on how to protect cookies. We specifically encourage the use of Secure and HttpOnly cookies.

Since publishing that post, we’ve seen some confusion regarding the term HttpOnly cookie, sometimes mistakingly shortened to just “HTTP cookie.” Some say any cookie set by a server is an HttpOnly cookie. That is incorrect. The server needs to add the HttpOnly attribute in the Set-Cookie response header to make a cookie be HttpOnly, like so:

Set-Cookie: ExampleSessionID=a66e30012cc49846; path=/; HttpOnly

Adding the HttpOnly attribute provides these two security and privacy protections: