Some suggestions for improvements to the TPE, to help increase transparency and make implementation easier. This is based on building the Chrome and Firefox browser extension Bouncer, which implements the full Javascript API, together with experience creating user consent systems based on the API on European ePrivacy compliant websites.
Sites and third-party servers are not likely to implement DNT (either the W3C TCS or the EFF flavour) unless there is a scalable way to override the DNT general preference on particular domains i.e. to whitelist them. Moreover, the TCS scope section specifically requires browser support for the JavaScript Exceptions or Consent API. The API has proven to be implementable in browsers and browser extensions, but there has been no use of it by a high profile site such as a publisher or third-party advertiser. Until the API is more widely supported the out-of-band mechanism is the only way for domains to be white-listed, but it suffers from a lack of verifiability and transparency.
There have been a few implementations of the Tracking Status Resource or the Tk
response.
Moreover there also been very few declarations by sites of one of the valid EFF DNT policies at /.well-known/dnt-policy.txt
Some sites such as www.w3.org, pixel.piwik.org and gchq.gov.uk have the Tk response header, but with an incorrect value. This could partly to do with lack of clarity, but also hints at the problems for server side code detecting (in a scalable way) out-of-band consent using cookies. Server side code capable of changing HTTP headers is often maintained by a different team, even a different company, than the team responsible for the logic of a web application. A way for the application team to declare the header using a "meta tag" approach could help here, as it has for other recommendations such as the Content-Security-Policy header.
The GDPR and the principles laid out in the EU-US Privacy Shield arrangements both call for increased transparency. Embedded third-parties now have to be identified and declare their legal basis and purpose for personal data processing. This requirement is a good fit with facilities in browsers, or browser extensions, to present information clearly, which in turn relies on it being available in a standardised machine readable way. The Tracking Status Resource is perfect mechanism for that, but it would help if this could be deployed more flexibly. Giving sites the option to vary the location of the TSR, and to declare it within an HTML document using meta tags would make it easier for sites to deploy it.
This suggested changes are an attempt to address these issues:
__DNT
for this.
This will allow the user to override their general preference not to be tracked in a standardised and verifiable way.
Although this would be simple method to replace the web-wide API,
it would not be easy to use it for site-specific consent due to the lack of support for double-keyed cookies.
confirmTrackingException
and enhanced storeSiteSpecificTrackingException
MAY return a Promise with a fulfilment value of TrackingStatusObject
.
This helps the API be more in line with the asynchronous nature of client side JavaScript, and creates callback functionality so web applications can respond dynamically in cases
where the user agent confirms Consent with the user before granting DNT:0.
useSameDomain
property which, if set true
, will signal the user agent that a particular Consent Grant should also apply to the domains referred to by the same-party
TSR array property. The user-agent MAY check that the targeted domains contain TSRs that refer back to the host domain of the calling origin.
Organisations sometimes have to manage several, perhaps thousands, of websites, often developed and maintained by marketing agencies and other contracted parties. Logistically it can be difficult to manage the multiple servers run by these disparate parties in a coordinated way.
An example of where this is required is delivering a Tk response header, especially when the out-of-band consent (OOBC) mechanism must be used. If a user's browser does not support the DNT Exception (Consent) API then the server must determine from the request if tracking consent has been given by that user, before inserting the correct Tk response header. This will in most cases involve looking up the value of an authentication cookie in an external database, and the code to do this would have to reside in the server, and it, or its underlying logic, would have to be shared among the different parties.
Another example is the delivery and maintenance of the Tracking Status Resource at the "well known" location.
Every origin would have to contain a reference (at /.well-known/dnt
) to the current resource, which may have to be maintained by the company's
legal or data protection function.
While it is possible in the current TPE to target any URI as the declared Tracking Status Resource using a chain of HTTP Redirects, getting all a company's servers to initiate the correct server-side redirection code can be difficult.
Both of these issues could be addressed by explicitly allowing the delivery of Tk responses within the returned HTML content, and communicating an alternative TSR URI within the response. It is relatively easy to supply a JavaScript library reference to be inserted in every HTML head-section, and this is a well understood industry practice.
This mechanism would only take effect in situations where an origin server did not return a Tk header,
and where it did not already return a well formed JSON resource to a GET to /.well-known/dnt
.
This proposal calls for the ability to specify the Tracking Status Resource within the value of the Tk
response header,
and be able to declare any Tk
response header in an HTML head
section using a meta
tag with
the standard http-equiv
attribute.
In future there is likely to be a standardised policy resource for an entire origin (e.g web site) where security and policy oriented headers can be declared. The motivation for this is managing the "header bloat" issue arising from new recommendations such as Content-Security-Policy. It would make sense to append the Tracking Status Resource to this, and incorporating a reference inside a header is a natural way to do it. If every site must have a set of cached origin-wide resources it would be best to combine their functionality so only one extra round-trip was needed, and to minimise the size of the cache.
A valid URI after a "%" character in the Tk
header will be construed as a valid Tracking Status Resource, unless a valid resource is also located at {origin server domain}/.well-known/dnt
,
in whch case that resource is taken as the only valid one.
If a Tk
response header exists the meta
tag is ignored. If a Tracking Status Resource exists at {origin server domain}/.well-known/dnt
then any "%" component of any Tk
response , in a header or in the HTML, is ignored.
The new Tk response header is defined formally by the following ABNF
Tk-field-name = "TK" Tk-field-value = TSV [ ";" status-id] [ "%" URI-reference] status-id = 1*id-char id-char = ALPHA / DIGIT / "_" / "-" / "+" / "=" / "/" URI-reference is defined as per [[RFC3986]]
The server MAY supply a Tk response via an HTML meta
elements
with http-equiv
attributes that are an
ASCII case-insensitive
match
for the string "Tk
". For
example:
<meta http-equiv="Tk" content="N">
<meta http-equiv="Tk" content="C%https://corporate-site.com/.well-known/dnt">
Add the following entry to the pragma directives for the meta
element:
http-equiv="Tk"
)
Authors are strongly encouraged to place meta
elements as early
in the document as possible, because policies in meta
elements are not
applied to content which precedes them.
Note: Modifications to the content
attribute of a meta
element
after the element has been parsed will be ignored.
If a user agent does not support the JavaScript API i.e. if navigator.confirmWebWideTrackingException
is undefined
,
and so cannot indicate a DNT exception by sending DNT: 0
to the appropriate origin server,
then there should be an alternative method to indicate user consent,
i.e. that DNT: 1
has been overridden, by arranging for the user agent to send a cookie with a "well known" name.
It is envisioned that a JavaScript library could be installed on a page to be activated if the required functionality is not implemented by a particular user agent.
For transparency and verifiability the cookie should have a standard name __DNT0
, MUST have the Secure
flag, and must only be placed if
the user has given their affirmative consent for web-wide tracking by the origin server, i.e. as the result of the appropriate call to the JavaScript DNT Exception API.
If the server recognises the consent indication it MUST respond with a Tk: C header,
or an HTML response containing a in the
head
section.
The recognition of web-wide consent for origin server is straight forward using this method, as the cookie would be present in every request.
For site-specific consent the data needed could be encoded in the cookie's value, perhaps to be matched against the domain specified in a Referer
header.
If the recognition requires servers held in the server linked by singling-out via a UID this should be encoded here,
and in that case the qualifier
TSR property MUST include the i
code.
Cookie:__DNT0=1a5b43ea7
The tracking status representation can have the following additional or amendedproperties, as illustrated by the following Orderly schema [Orderly]:
object { string tracking; // as per the Orderly schema in the TPE array { string; } compliance?; // '' string qualifiers?; // amended below array { string; } controller?; // as per the Orderly schema in the TPE array { string; } same-party?; // '' array { string; } audit?; // '' string policy?; // '' string config?; // '' array { object { string name; string uri} } controllerDescription; // Legal name of the data controller and a URI of a page providing the user with information about it; object { long overall_retention?; // A positive number of seconds indicating the overall maximum lifetime of the client storage. array object { string type ["C","L","I"]; // storage type C = a cookie, L = localStorage item, I = indexdedDB table, "E" = cache item e.g. ETag string match; // a regular expression used to match an item of storage when applied to the item name or cookie name and value pair array { string ["n","t","i","f","a","u","O","!f","!l","!s","!d"]* purpose;}; array { string sharedWith; }; // the main domains names managed by the entities the data may be shared with. long retention?; // A positive number of seconds indicating the maximum lifetime of the storage item. } } storageUse; // matches any client data item e.g. a cookie, item in localStorage etc., used by the origin server string deleteDataUri?; // URI of resource that causes all tracking data on this origin to be deleted string optInUri?; // URI of resource that causes the origin server or its JavaScript browsing context to register tracking consent string optOutUri?; // URI of resource that causes the origin server or its JavaScript browsing context to revoke any tracking consent string dataHeldUri; // URI of resource that will return HTML content identifying tracking data held by the origin server, // giving the user the ability to access, amend or delete it. object {integer {,48} bitLength?; integer maxAge}} trackingIdConstraint?; // declared tracking identifier entropy and expiry array { string; } currentAudienceSelector?; // array of audience categories derived from the current DNT-identifier }*;
An origin server MAY send a property named controllerDescription
containing an array of objects representing one or more Data Controllers responsible for an origin.
Each object contains a string name
indicating the unique name of the Data Controller entity along with a string url
containing the URI of a human readable web page describing the entity.
If the controller TSR property is present the url
property need not be. If the url
property is present it overrides the value of any TSR controller property.
This contains a set of characters corresponding to explanations or limitations on tracking.
The meaning of each character is explained by one or more of the regimes listed in the compliance
property.
For example the codes referred to in the default W3C compliance document are:
qualifier | permitted use |
---|---|
c | frequency capping |
f | financial logging |
s | security |
d | debugging |
t | transferred |
Additional codes for use in implementing site-specific consent in the absence of support for the JavaScript Consent API (and to help comply with Recital 66 of the European ePrivacy directive) could be:
qualifier | purpose | description |
---|---|---|
n | strictly necessary | strictly necessary to fulfil a service requested by the user, e.g. authentication |
T | transmission | solely used for the purpose of carrying out the transmission of a communication |
L | first-party login | solely used for registering an authenticated user. If the cookie accessible to an embedded third-party then the duration MUST be limited to no more than 24 hours |
i | site-specific consent | tracking solely for the purpose of detecting whether site-specific consent had been given |
o | other | tracking for any other purpose for which informed consent has been given |
This is an object representing user agent storage employed by the origin server for tracking or other purposes.
This gives the origin server the ability to transparently describe in a standardised way the overall retention time for client storage
and the purpose and retention period for each storage item. User agents MAY present this information
to the user, and privacy regulators, audit services etc. will be able use website scanning tools to verify it.
In addition Privacy Enhancing Technology components, such as TrackingBlocker or AdBlocker extensions,
can make intelligent decisions regarding content blocking or storage removal when enforcing a user's privacy preferences.
The object contains a long integer overall_retention
a positive number of seconds indicating the maximum lifetime of all the declared data.
and an array of objects describing individual storage items controlled by the origin server.
Each of these contains a selector
string used to match the name or name-value pair of a particular item ,
a string type
representing the class of storage used where "C" is an HTTP cookie, "L" is local HTML5 storage and "I" is indexedDB.
The selector
string MAY contains a =
character to demarcate between Regex match strings for the name and value of a name-value pair.
The purposes for each item is encoded in the purpose
array of strings. If this is present it MUST contain one or more of the following purpose identifiers.
N.B. Need to specify Qualifiers.
Code | Purpose | Definition |
---|---|---|
n | Necessary | Strictly necessary to fulfil a service requested by the user. |
t | Transmission | Solely used for the purpose of carrying out the transmission of a communication. |
i | Site-Specific Consent | Solely for the purpose of detecting whether site-specific consent had been given when the user agent does not support JavaScript Exception API. |
f | Functional | Retains information in the user agent solely used to retain state between HTTP transactions without a unique user identifier. Any data retained is generic in nature and will not be used to profile the user. |
a | Analytics | Used to collect anonymous statistical information about visitors to a web site. No attempt will be made to single-out the user for profiling purposes. Any unique identifier used will not be shared with any other party. |
u | Tracking |
Used to single-out or track a user, i.e. a unique user identifier.
If this is shared with another party their domain MUST be indicated in the sharedWith attribute below.
|
O | Opt-out |
This identifies an HTTP cookie used by some non-standard systems to indicate that a user has opted-out from tracking.
If the same cookie name is also used as a UID tracking identifier then the selector must uniquely identify the opt-out case e.g.
UID=opted-out . A properly identified opt-out cookie MUST not be deleted by a user agent when other storage is deleted,
for example when the overall_retention period expires.
|
!f | Permitted capping | Used for frequency capping, i.e.to limit the number of times that a user sees a particular advertisement, often called frequency capping, as long as the data retained do not reveal the user’s browsing history. |
!l | Permitted logging | Used for financial logging, i.e. for billing and auditing related to the current network interaction and concurrent transactions. This may include counting ad impressions to unique visitors, verifying positioning and quality of ad impressions and auditing compliance with this specification and other standards. |
!s | Permitted security | Used for security, i.e. to the extent reasonably necessary to detect security incidents, protect the service against malicious, deceptive, fraudulent, or illegal activity, and prosecute those responsible for such activity, provided that such data is not used for operational behaviour beyond what is reasonably necessary to protect the service or institute a graduated response. |
!d | Permitted debugging | Used for debugging, i.e. solely collected, retained or used for debugging purposes to identify and repair errors that impair existing intended functionality. |
retention
contains a positive number of seconds indicating the maximum lifetime of the storage item.
The optional array of strings sharedWith
represents the main domains of any entities that any data is shared with.
An origin server MAY send a property named deleteDataUri
indicating the URI (relative to the origin domain) of a resource
that will delete any personal data held in the user agent such as identifiers used for non-permitted tracking.
The URI of a resource to communicate a user opt-in (explicit consent) to an origin server. When a user opts-in using a user agent based UI, an HTTP GET MAY be sent to this URI to communicate the change in consent
The URI of a resource to communicate a user opt-out (revoked consent) to a server. When a user opts-out using a user agent based UI, or the user agent detects that the Consent Grant has expired, an HTTP GET MAY be sent to this URI to communicate the change in consent.
The URI of resource that will return HTML content identifying tracking data held by the origin server, giving the user the ability to access, amend or delete it.
dntapi
client property information
Many browsers have yet to support the JavaScript API and this makes it difficult for servers who want to register user consent to decide on whether to support the API or fall back to the out-of-band mechanism.
It is for server side code to insert the Tk
header and this is a necessity if OOBC must b used.
JavaScript can be used to detect the shortfall, but this creates the necessity for another round-trip to communicate the result.
At this time even this is problematic in the case of the Microsoft Edge browser because navigator.confirmSiteSpecificTrackingException
exists,
and it is not until a call to storeSiteSpecificTrackingException
is made, which throws an Access is denied
exception, that the client
code can detect that the API is not supported.
We propose that Browsers or browser extensions that support the API should indicate this to servers by including the string dntapi
in the User-Agent request header.
Servers or client code can easily detect this string and immediately implement the appropriate procedures.
The [[tracking-dnt]]] JavaScript API is enhanced in the following ways:
userSameParty
boolean is true
then an exception will also be requested for any domains specified
in the origin server's [TSR] same-party
property, as long as the reciprocal same-party
also references the origin server requesting the exception.
The domain
property will then no longer be necessary.
confirmTrackingException
function to replace confirmSiteSpecificTrackingException
and confirmWebWideTrackingException
. This will return a promise resolving to an object indicating more information about the
exception, e.g. whether it was WebWide or SiteSpecfic, the version level of the API, whether the user has been prompted for confirmation etc.
partial interface Navigator { Promise<TrackingStatusObject> storeSiteSpecificTrackingException (TrackingPermission properties); Promise<TrackingStatusObject> confirmTrackingException(TrackingPermission properties); }; dictionary TrackingStatusObject { DomString Status; // string value indicating "OK" for success or any other value for failure DOMString GrantId; // a unique value registered for this granted exception, // or consent receipt. // This can be communicated to a server so the grant can be matched to one stored // within the user agent for proof-of-consent purposes. }; dictionary StoreExceptionPropertyBag { DOMString? domain; DOMString? siteName; DOMString? explanationString; DOMString? detailURI; DOMString? expires; long? maxAge; }; dictionary TrackingPermission : StoreExceptionPropertyBag { boolean? useSameParty; // true to specify UGE is also for same-parties boolean? resetTargets; // clears any pre-existing arrayOfDomainNames property from a previous granted exception DOMString? DNTVal; // the DNT field-name to be sent in future requests to this origin server, optionally its same-parties, and any targets. // if the property is present the first character must be either "0" or "1" // The user agent will strip any characters after the field value which defaults to "0". DOMString? optIn; // the URI of a resource to communicate a user opt-in (explicit consent) to a server. When a user opts-in using a user agent // based UI, an HTTP GET MAY be sent to this URI. DOMString? optOut; // the URI of a resource to communicate a user opt-out (revoked consent) to a server. When a user opts-out using a user agent // based UI, or the user agent detects that the Consent Grant has expired, an HTTP GET MAY be sent to this URI. };