-
Notifications
You must be signed in to change notification settings - Fork 77
/
index.bs
1334 lines (1027 loc) · 63.1 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<pre class="metadata">
Title: User-Agent Client Hints
Status: CG-DRAFT
Group: WICG
ED: https://wicg.github.io/ua-client-hints/
Repository: wicg/ua-client-hints
Shortname: ua-client-hints
Level: None
Editor: Mike Taylor 90704, Google LLC, [email protected]
Editor: Yoav Weiss 58673, Google LLC, [email protected]
Former Editor: Mike West 56384, Google LLC, [email protected]
Abstract:
This document defines a set of Client Hints that aim to provide developers with the ability to
perform agent-based content negotiation when necessary, while avoiding the historical baggage and
[=passive fingerprinting=] surface exposed by the venerable <code>User-Agent</code> header.
Indent: 4
Include MDN Panels: no
Default Biblio Status: current
Markup Shorthands: css off, markdown on
Boilerplate: omit feedback-header
!Participate: <a href="https://github.com/WICG/ua-client-hints/issues/new">File an issue</a> (<a href="https://github.com/WICG/ua-client-hints/issues">open issues</a>)
</pre>
<pre class="link-defaults">
spec:fetch; type:dfn; for:/; text:request
spec:webidl; type:dfn; text:resolve
spec:infra; type:dfn; text:user agent
spec:infra; type:dfn; for:/; text:list
</pre>
<pre class="anchors">
urlPrefix: https://tools.ietf.org/html/rfc8941; spec: rfc8941
type: dfn
text: structured header; url: #
for: structured header
type: dfn
text: token; url: #section-3.3.4
text: boolean; url: #section-3.3.6
text: string; url: #section-3.3.3
text: list; url: #section-3.1
text: serializing a list; url: #section-4.1.1
type: abstract-op
text: serialize Structured Header; url: #section-4.1
urlPrefix: https://tc39.es/ecma262/
type: dfn
text: current realm; url: #current-realm
urlPrefix: https://w3c.github.io/permissions/
type: dfn
text: permission task source; url: #dfn-permissions-task-source
urlPrefix: https://w3c.github.io/fingerprinting-guidance/
type: dfn
text: passive fingerprinting; url: #dfn-passive-fingerprinting
text: active fingerprinting; url: #dfn-active-fingerprinting
text: Best Practice 1; url: #avoid-passive-increases
</pre>
<pre class="biblio">
{
"FacebookYearClass": {
"href": "https://engineering.fb.com/android/year-class-a-classification-system-for-android/",
"title": "Year class: A classification system for Android",
"authors": [ "Chris Marra", "Daniel Weaver" ]
},
"I-D.ietf-tls-grease": {
"href": "https://tools.ietf.org/html/draft-ietf-tls-grease",
"title": "Applying GREASE to TLS Extensibility",
"authors": [ "David Benjamin" ],
"status": "ID",
"publisher": "IETF"
},
"Janc2014": {
"href": "https://dev.chromium.org/Home/chromium-security/client-identification-mechanisms#TOC-Browser-level-fingerprints",
"title": "Technical analysis of client identification mechanisms",
"authors": [ "Artur Janc", "Michal Zalweski" ]
},
"Rossi2015": {
"href": "https://channel9.msdn.com/Events/WebPlatformSummit/2015/The-Microsoft-Edge-Rendering-Engine-that-makes-the-Web-just-work#time=9m45s",
"title": "The Microsoft Edge Rendering Engine that makes the Web just work",
"author": [ "Jacob Rossi" ]
}
}
</pre>
Introduction {#intro}
============
*This section is non-normative*.
Today, user agents generally identify themselves to servers by sending a `User-Agent` HTTP request
header field along with each request (defined in Section 5.5.3 of [[rfc9110]]). Ideally, this header
would give servers the ability to perform content negotiation, sending down exactly those bits that
best represent the requested resource in a given user agent, optimizing both bandwidth and user
experience. In practice, however, this header's value exposes far more information about the user's
device than seems appropriate as a default, on the one hand, and intentionally obscures the true
user agent in order to bypass misguided server-side heuristics, on the other.
For example, a recent version of Chrome on iOS identifies itself as:
``` http
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X)
AppleWebKit/605.1.15 (KHTML, like Gecko)
CriOS/69.0.3497.105 Mobile/15E148 Safari/605.1
```
While a recent version of Edge identifies itself as:
``` http
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.2704.79
Safari/537.36 Edge/18.014
```
There's quite a bit of information packed into those strings (along with a fair number of lies).
Version numbers, platform details, model information, etc. are all broadcast along with every
request, and form the basis for fingerprinting schemes of all sorts. Individual vendors have taken
stabs at altering their user agent strings, and have run into a few categories of feedback from
developers that have stymied historical approaches:
1. Brand and version information (e.g. "Chrome 69") allows websites to work around known bugs in
specific releases that aren't otherwise detectable. For example, implementations of Content
Security Policy have varied wildly between vendors, and it's difficult to know what policy to
send in an HTTP response without knowing what browser is responsible for its parsing and
execution.
2. Developers will often negotiate what content to send based on the user agent and platform. Some
application frameworks, for instance, will style an application on iOS differently from the same
application on Android in order to match each platform's aesthetic and design patterns.
3. Similarly to #1, OS revisions and architecture can be responsible for specific bugs which can
be worked around in website's code, and narrowly useful for things like selecting appropriate
executables for download (32 vs 64 bit, ARM vs Intel, etc).
4. Sophisticated developers use model/make to tailor their sites to the capabilities of the
device (e.g. [[FacebookYearClass]]) and to pinpoint performance bugs and regressions which
sometimes are specific to model/make.
This document proposes a mechanism which might allow user agents to be a bit more aggressive about
removing entropy from the `User-Agent` string generally by giving servers that really need some
specific details about the client the ability to opt-into receiving them. It introduces a number of
new Client Hints ([[!RFC8942]]) that can provide the client's branding and version
information, the underlying operating system's branding and major version, as well as details about
the underlying device. Rather than broadcasting this data to everyone, all the time, user agents can
make reasonable decisions about how to respond to given sites' requests for more granular data,
reducing the [=passive fingerprinting=] surface area exposed to the network (see [=Best Practice 1=]
in [[FINGERPRINTING-GUIDANCE]]).
Examples {#examples}
--------
*This section is non-normative*.
A user navigates to `https://example.com/` for the first time using the latest version of the
"Examplary Browser". Their user agent sends the following headers along with the HTTP request:
``` http
Sec-CH-UA: "Examplary Browser"; v="73", ";Not?A.Brand"; v="27"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "Windows"
```
The server is interested in rendering content consistent with the user's underlying platform version,
and asks for a little more information by sending an `Accept-CH` header (Section 2.2.1 of
[[!RFC8942]]) along with the initial response:
``` http
Accept-CH: Sec-CH-UA-Platform-Version
```
In response, the user agent includes the platform version information in the next request:
``` http
Sec-CH-UA: "Examplary Browser"; v="73", ";Not?A.Brand"; v="27"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "Windows"
Sec-CH-UA-Platform-Version: "14.0.0"
```
## Use Cases ## {#use-cases}
*This section is non-normative*.
This section attempts to document the current uses for the `User-Agent` string,
and how similar functionality could be enabled using User-Agent Client Hints (UA-CH).
### Differential serving ### {#differential-serving-use-case}
#### Based on browser features #### {#based-on-browser-features-use-case}
This use case enables services like [polyfill.io](https://polyfill.io) to serve custom-tailored
polyfills to their users, without bloating up the experience of modern browser users.
Similarly, when serving Javascript to users, one can avoid transpilation (which can result in bloat
and inefficient code) for browsers that support the latest ES features that were used. Finally, when
serving images, some browsers don't update their `Accept` request headers, while in other cases the
MIME type is not descriptive enough to distinguish between different variants of the same format
(e.g., WebP). In those cases, knowing the browser and its version can be critical to serving the
right image variant.
For that use case to work, the server needs to be aware of the browser and its meaningful version,
and map that to a list of available features. That enables it to know which polyfill or code variant
to serve.
Services that wish to do that using UA-CH will need to inspect the `Sec-CH-UA`
header, that is sent by default on every request, and modify their response
based on that.
#### Browser bug workaround #### {#browser-bug-workaround-use-case}
Some browser versions have well-known bugs which require content to workaround them. Triggering
those bugs can result in browser crashes, content breakage and other issues, and those bugs are by
definition not something that can be feature detected. Therefore, content needs to avoid them
altogether for affected browser versions.
For that use case, servers need to be aware of the browser and its meaningful version, be aware of
browser bugs that impact them, and apply workarounds if the current browser version is impacted.
Services that wish to do that using UA-CH will need to inspect the `Sec-CH-UA` header, sent by
default on every request, and use it to modify their response.
### Market Share Analytics ### {#marketshare-analytics-use-case}
A browser's market share can be extremely important. Having visibility into a browser's usage can
encourage developers to test in that particular browser, ensuring fewer compatibility issues for
its users. On top of that, a browser's market share can have a direct impact on the browser vendors'
business goals, ensuring future development of the browser.
For market share analytics to work, a server needs to be aware of one or more of the following:
user agent name and its meaningful version, operating system and its version, and device model. It
can then register them and find their relative market shares.
Sites that wish to provide market share analytics using UA-CH will need to inspect the `Sec-CH-UA`
header, that is sent by default on every request, and keep a record of it. Additional UA client
hints may also be requested depending on the use case (e.g., mobile device model analytics).
By design, looking at individual entries in the brands list makes it hard to distinguish between a
less-popular browser's truthful brand name and a more-popular browser's arbitrary GREASE. Since the
less-popular browser may include several popular brand names for compatibility purposes, its users
will likely be bucketed as using the more-popular one if this approach is taken, leading to
distorted views of usage share that favour already-popular browsers and with less-popular browsers
possibly never gaining any visibility.
Hence, for analytics purposes, it is better to treat the brands list as a unit, and compare it to
known lists of brands sent by the various (browser, version) pairs that are to be distinguished.
This will necessitate regular updates to the list of known lists of brands when new browser versions
are released or new browsers become popular, or else everything will get bucketed as an unknown
browser. However, as this doesn't break sites for users, failing closed for unknown browsers is
acceptable in this context.
Such a list of known lists of brands could be maintained centrally and used by many sites (as, e.g.,
browser feature support is maintained by caniuse and MDN, and consumed by many webmasters).
The specification recommends that browsers fix the brands list they send per version to make
counting usage shares simpler (and also to help with caching), so the known lists of brands can be a
simple list mapping from a set of brands to a (browser, version) pair.
### Content adaptation ### {#content-adaptation-use-case}
Content adaptation is ensuring that users get content that's tailored to their needs. There are
[many dimensions to content adaptation](https://blog.yoav.ws/adapting_without_assumptions/) beyond
the UA string:
[viewport dimensions](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/client-hints),
[device memory](https://w3c.github.io/device-memory/),
[user preferences](https://wicg.github.io/savedata/) and more. This sub-section covers content
adaptation needs that rely on information that is part of the current `User-Agent` string.
#### Browser based adaptation #### {#browser-based-adaptation-use-case}
Some sites choose to serve slightly different content to different browsers. The reasons for that
vary. Some reasons are legitimate (e.g. wanting to serve different experiences to different browsers
due to their feature support). Other reasons are slightly less legitimate (e.g. warning users that
the site's developers haven't tested in their browser). And then there are reasons which are
outright wrong (e.g. Willingness to block certain browsers' users from accessing the site).
As browsers, we want to enable the former, while discouraging the latter.
#### Mobile specific site #### {#mobile-specific-site-use-case}
Many site owners serve different content between mobile and desktop sites. While responsive web
design has made it possible to serve multiple form factors using a single code base, there are still
cases where serving a mobile-specific version can be better adapted.
For those cases, serving mobile-specific sites to users on mobile devices can be helpful. For that
to work, the server needs to be aware, at HTML serving time, whether the user is on a mobile device
or not.
Sites that wish to serve mobile-specific sites using UA-CH can do that using the `Sec-CH-UA-Mobile`
headers that are sent by default on every request.
#### Low-powered devices #### {#low-powered-devices-use-case}
Some sites serve different content to low powered devices that cannot deal with CPU intensive tasks,
large video and images, etc. Such content adaptation typically uses the device model information
that's integrated in the current `User-Agent` string for that purpose, relying on server-side
databases to convert device models into memory, CPU power, and other categories on which they want
to split their content.
If the dimension on which the split is made is memory, the Device-Memory Client Hint can be used to
make that distinction. Otherwise, with UA-CH, sites can still retrieve the device model by opting
in to the `Sec-CH-UA-Model` hint.
Both of these hints are not sent by default, so require some extra work.
Top-level origins will need to send `Accept-CH: Device-Memory, Sec-CH-UA-Model` headers with their
responses to opt-in to receiving those hints. In cases where they absolutely need to perform that
adaptation on every navigation request, a redirect would be required here in the case where the
hints are not present in a browser that supports them. Alternatively, they might use Critical-CH to
have the client handle the additional request/response roundtrip.
Third-party origins that need to perform such adaptation would need
[delegation](https://github.com/WICG/client-hints-infrastructure#cross-origin-hint-delegation) from
the top-level origin. The top-level origin would need to opt-in using `Accept-CH`, as well as add
`Permissions-Policy` headers that delegate those hints to the third-party origin.
#### OS specific styles #### {#os-specific-styles-use-case}
Some sites may wish to tailor their interfaces to match the user's OS. While progressive enhancement
is likely to be a better path here (e.g. through the application of different button styles using
script), there may be cases where folks would wish to deliver tailored inline styles based on the
platform and platform version.
Those cases are very similar to the case discussed above (in "Low-powered devices"), only with the
`Sec-CH-UA-Platform` and `Sec-CH-UA-Platform-Version` hints.
#### OS integration #### {#os-integration-use-case}
Similarly, some sites would want to change links to OS specific ones (e.g. [Android intent
links](https://developer.chrome.com/multidevice/android/intents)). While, again, progressive
enhancement can be used to modify those links using script, rather than bake them into the HTML,
some sites may prefer server-side adaptation.
Again, like the "OS specific styles" case, they'd need to use the `Sec-CH-UA-Platform` and
`Sec-CH-UA-Platform-Version` hints to do so.
#### Browser and OS specific experiments #### {#browser-os-experiments-use-case}
Some servers may like to limit their multi variant experimentation to specific browsers, specific
platforms or specific versions of any of the above. For experiments that are limited to browser
and version, those sites can use the `Sec-CH-UA` values sent by default on requests. If they
require the platform and its version, they could use the default `Sec-CH-UA-Platform` hint but
would have to request the `Sec-CH-UA-Platform-Version` hint, or use client-side scripts to control
the experimentation.
### User login notification ### {#user-login-notification-use-case}
Many sites, especially security sensitive ones, like to notify their users when a log-in from a new
device happens. That enables users to be aware of those logins, and take action in case it's not a
login that's done by them or on their behalf.
For those notifications to be meaningful, sites need to recognize and communicate the commercial
brand of the browser to the user. These messages often also include the platform and its version in
order to make sure the user knows which device is in question.
Since such messaging doesn't require any server-side adaptation, it's better for this case to use
the `userAgentData.getHighEntropyData()` method in order to retrieve the required information.
### Download of appropriate binary executables ### {#binary-executable-downloads}
Some sites are used to download binary executables of native applications, and need to be able to
propose the right binary to the user by default. The right binary executable for the current user
depends on a few factors: their operating system, its version, its bitness, as well as their CPU
architecture.
In order to tackle that use case, download sites can opt-in to receive the `Sec-CH-UA-Platform`,
`Sec-CH-UA-Platform-Version`, `Sec-CH-UA-Architecture`, and `Sec-CH-UA-Bitness` hints (or query
them through the API), in order to ensure the right binary is offered to the user by default.
### Conversion modeling ### {#conversion-modeling-use-case}
Some machine learning models use various details from the `User-Agent` string in order to estimate
various things about users of those user agents. Similar modeling would still be possible, but will
require explicit opt-in to collect the required bits of information.
### Vulnerability filtering ### {#vulnerability-filtering-use-case}
In some environments, proxy servers may be used to verify that the different users accessing
information are not doing so from obsolete devices that are potentially vulnerable to security
issues. While the browser and version information available from `Sec-CH-UA` can provide some
information, the browser and OS full version are often useful for that kind of analysis.
Such proxies would have to add a redirect step, or use one of the two
[Client Hint reliability mechanisms](https://github.com/WICG/client-hints-infrastructure/blob/main/reliability.md#client-hint-reliability)
that opts-in to getting the browser full version and the platform version in order to continue to
get access to those hints.
### Logs and debugging ### {#logs-debugging-use-case}
Many services log the `User-Agent` string today and can use it in various ways when analyzing past
traffic or when trying to debug errors related to their service. Those services will have to use
the lower entropy values available through `Sec-CH-UA` for logging purposes, or opt-in to receive
higher-entropy hints. The latter doesn't seem like something services should do just for forensic
purposes. On the other hand, when specific issues are encountered, it may make sense for those
services to opt-in to receive more details on the user agent, or use the
`userAgentData.getHighEntropyData()` API for that purpose.
### Fingerprinting ### {#fingerprinting-use-case}
User fingerprinting is the practice of gathering multiple bits of user information from multiple
sources and intersecting them together to create a unique signature of the user, that would enable
to recognize them to be recognized later on, even if they clear state from their browsers (e.g. by
deleting cookies).
For those cases, the origin needs to gather as much entropy as possible, so it is likely to collect
all the hints.
#### Spam filtering and bot detection #### {#spam-filtering-bots-use-case}
This is a case of fingerprinting that is not user-hostile, and therefore one we would like to
preserve. With UA-CH this will be initially enabled by active collection of the various hints.
We hope that alternative methods or APIs will exist to address the spam filtering and bot detection
use cases in the future, as browsers may decide to intervene on behalf of their users by limiting
the collection of user-identifying entropy (e.g., the
[Privacy Budget](https://github.com/bslassey/privacy-budget) proposal).
#### Persistent user tracking #### {#persistent-user-tracking}
This is a case of fingerprinting that this proposal *explicitly tries to make harder*. Like the
case of "spam filtering", it would still be feasible to actively collect all the hints about the
user as bits of entropy. Unlike the above case, this is something that proposals such as the Privacy
Budget aim to prevent, without providing any alternative mechanisms for persistent user tracking.
#### Blocking known bots and crawlers #### {#blocking-known-bots-crawlers-use-case}
Currently, the `User-Agent` string is often used as a brute-force way to block
known bots and crawlers. There's a concern that moving "normal" traffic to
expose less entropy by default will also make it easier for bots to hide in the
crowd. While there's some truth to that, that's not enough reason for making the crowd
be more personally identifiable.
Similar to the spam filtering case, there's hope that alternative methods would
be able to replace `User-Agent` string matching for this use case.
Infrastructure {#infrastructure}
==============
This specification depends on Client Hints Infrastructure, HTTP Client Hints, Infra
Standard, and Permissions Policy.
[[!CLIENT-HINTS-INFRASTRUCTURE]]
[[!RFC8942]]
[[!INFRA]]
[[!permissions-policy-1]]
Some of the terms used in this specification are defined in <cite>Structured Field Values for
HTTP</cite>.
[[!RFC8941]]
User Agent Hints {#http-ua-hints}
================
The following sections define a number of HTTP request header fields that expose detail about a
given [=user agent=], which servers can opt-into receiving via the Client Hints infrastructure
defined in [[!RFC8942]]. The definitions below assume that each [=user agent=]
has defined a number of properties for itself:
* <dfn for="user agent" export>brand</dfn> - The [=user agent=]'s commercial name (e.g.,
"cURL", "Edge", "The World's Best Web Browser"), which MUST be shorter than 32 [=ASCII alpha=]
characters.
* <dfn for="user agent" export>form-factors</dfn> - The form-factors of a device, historically
represented as a <[=deviceCompat=]> token in the User-Agent string (e.g., "Tablet", "VR",
etc.)
* <dfn for="user agent" export>full version</dfn> - The build version (e.g.,
"72.0.3245.12", "3.14159", or "297.70E04154A") that corresponds to the [=user agent=], or any
of the brands in its [=brands=] list.
* <dfn for="user agent" export>model</dfn> - The [=user agent=]'s device model (e.g., "", or
"Pixel 2 XL")
* <dfn for="user agent" export>mobileness</dfn> - A boolean indicating if the [=user agent=]'s
device is a mobile device. (e.g., ?0 or ?1)
* <dfn for="user agent" export>platform brand</dfn> - The [=user agent=]'s operating system's
commercial name. (e.g., "Windows", "iOS", or "AmazingOS")
* <dfn for="user agent" export>platform version</dfn> - The [=user agent=]'s operating system's
version. (e.g., "NT 6.0", "15", or "17G")
* <dfn for="user agent" export>platform architecture</dfn> - The [=user agent=]'s underlying CPU
architecture (e.g., "ARM", or "x86")
* <dfn for="user agent" export>platform bitness</dfn> - The [=user agent=]'s underlying CPU
architecture bitness (e.g., "32" or "64")
* <dfn for="user agent" export>significant version</dfn> - The marketing version which includes
distinguishable web-exposed features (e.g., "72", "3", or "12.1"), corresponding to the
[=user agent=], or any of the brands in its [=brands=] list (e.g., rendering engine or
any other [=equivalence classes=] full version).
* <dfn for="user agent" export>wow64-ness</dfn> - A boolean indicating if the [=user agent=]'s binary is running in 32-bit mode on 64-bit Windows. (e.g., ?0 or ?1)
[=User agents=] SHOULD keep these strings short and to the point, but servers MUST accept arbitrary
values for each, as they are all values constructed at the [=user agent=]'s whim.
[=User agents=] MUST map higher-entropy [=platform architecture=] values to the following buckets:
* x86 CPU architectures => "x86"
* ARM CPU architectures => "arm"
Other CPU architectures could be mapped into one of these values in case that makes sense, or be
mapped to the empty string.
[=User agents=] SHOULD return the empty string or a fictitious value for [=platform architecture=]
or [=platform bitness=] unless the user's platform is one where both the following conditions apply:
* Binary download of executables is likely.
* Different CPU architectures are likely to require different binary executable resources, and
different binary executable resources are likely to be available.
[=User Agents=] MUST return the empty string for [=model=] if [=mobileness=] is false. [=User
Agents=] MUST return the empty string for [=model=] even if [=mobileness=] is true, except on
platforms where the model is typically exposed.
[=User agents=] MAY return the empty string for hints of type `sf-string`,
`false` for hints of type `sf-boolean`, or any other fictitious value, for
privacy, compatibility, or other reasons, given a request for any the following hints:
[=full version=], [=platform architecture=], [=platform bitness=], [=wow64-ness=] or [=model=].
The 'Sec-CH-UA' Header Field {#sec-ch-ua}
----------------------------
The <dfn http-header>`Sec-CH-UA`</dfn> request header field gives a server information about a
[=user agent=]'s [=user agent/branding=] and [=user agent/significant version=]. It is a
[=Structured Header=] whose value MUST be a [=structured header/list=] [[!RFC8941]]. The list's
items MUST be [=structured header/string=]. The value of each item SHOULD include a "v" parameter,
indicating the [=user agent=]'s version.
The header's ABNF is:
``` abnf
Sec-CH-UA = sf-list
```
To <dfn abstract-op>return the `Sec-CH-UA` value for a request</dfn>, perform the following steps:
1. Let |brands| be the result of running [=create brands=] with "significant version".
1. Let |list| be the result of <a lt="create a brand-version list">creating a brand-version list</a>,
with |brands| and "significant version".
1. Return the output of running [=serializing a list=] with |list|.
Note: Unlike most Client Hints, since it's included in the [=low entropy hint table=],
the `Sec-CH-UA` header will be sent by default, whether or not the server opted-into
receiving the header via an `Accept-CH` header (although it can still be controlled by it's
[=policy-controlled client hints feature=].
It is considered low entropy because it includes only the [=user agent=]'s branding information,
and the significant version number (both of which are fairly clearly sniffable by "examining the
structure of other headers and by testing for the availability and semantics of the features
introduced or modified between releases of a particular browser" [[Janc2014]]).
Note: <a http-header>`Sec-CH-UA`</a> reveals the major version for each brand in the [=brands=]
list. For use cases requiring the [=user agent/full version=], see
<a http-header>`Sec-CH-UA-Full-Version-List`</a>.
The 'Sec-CH-UA-Arch' Header Field {#sec-ch-ua-arch}
------------------------------
The <dfn http-header>`Sec-CH-UA-Arch`</dfn> request header field gives a server information about
the architecture of the platform on which a given [=user agent=] is executing. It is a
[=Structured Header=] whose value MUST be a [=structured header/string=]
[[!RFC8941]].
The header's ABNF is:
~~~ abnf
Sec-CH-UA-Arch = sf-string
~~~
The 'Sec-CH-UA-Bitness' Header Field {#sec-ch-ua-bitness}
------------------------------
The <dfn http-header>`Sec-CH-UA-Bitness`</dfn> request header field gives a server information about
the [=platform bitness=] of the architecture of the platform on which a given [=user agent=] is
executing. It is a [=Structured Header=] whose value MUST be a [=structured header/string=]
[[!RFC8941]].
The header's ABNF is:
~~~ abnf
Sec-CH-UA-Bitness = sf-string
~~~
The 'Sec-CH-UA-Form-Factors' Header Field {#sec-ch-ua-form-factors}
------------------------------
The <dfn http-header>`Sec-CH-UA-Form-Factors`</dfn> request header field gives a
server information about the [=user agent=]'s [=form-factors=]. It is a
[=Structured Header=] whose value MUST be a [=structured header/list=]
[[!RFC8941]]. In order to avoid providing additional fingerprinting entropy,
the header's values MUST be given in lexical order, and values are
case-sensitive.
The header SHOULD describe the form-factors of the device using one or more of
the following common form-factor values: "Desktop", "Automotive", "Mobile",
"Tablet", "XR", "EInk", or "Watch". All applicable form-factor values SHOULD be
included.
<div class="note" heading="">
The form-factors of a user-agent describe how the user interacts with the
user-agent. The meanings of the allowed values are:
* "Desktop" refers to a user-agent running on a personal computer.
* "Automotive" refers to a user-agent embedded in a vehicle, where the user
may be responsible for operating the vehicle and unable to attend to small
details.
* "Mobile" refers to small, touch-oriented device typically carried on a
user's person.
* "Tablet" refers to a touch-oriented device larger than "Mobile" and not
typically carried on a user's person.
* "XR" refers to immersive devices that augment or replace the environment
around the user.
* "EInk" refers to a device characterized by slow screen updates and limited
or no color resolution.
* "Watch" refers to a mobile device with a tiny screen (typically less than 2
[[css-values-4#absolute-lengths|in]]), carried in such a way that the user
can glance at it quickly.
A new value should be proposed and added to the specification when there is a
new form-factor that users interact with in a meaningfully different way; a
compelling use-case where sites would like to change how they interact with
users on that device; and no reliable way to identify that new form-factor
using existing hints.
</div>
The header's ABNF is:
~~~ abnf
Sec-CH-UA-Form-Factors = sf-list
~~~
The 'Sec-CH-UA-Full-Version' Header Field {#sec-ch-ua-full-version}
--------------------------------
Advisement: `Sec-CH-UA-Full-Version` is deprecated and will be removed in the future. Developers
should use <a href="#sec-ch-ua-full-version-list">`Sec-CH-UA-Full-Version-List`</a> instead.
The <dfn http-header>`Sec-CH-UA-Full-Version`</dfn> request header field gives a server information
about the user agent's [=user agent/full version=]. It is a [=Structured Header=]
whose value MUST be a [=structured header/string=] [[!RFC8941]].
The header's ABNF is:
``` abnf
Sec-CH-UA-Full-Version = sf-string
```
The 'Sec-CH-UA-Full-Version-List' Header Field {#sec-ch-ua-full-version-list}
--------------------------------
The <dfn http-header>`Sec-CH-UA-Full-Version-List`</dfn> request header field gives a server
information about the [=user agent/full version=] for each brand in its [=brands=] list. It is a
[=Structured Header=] whose value MUST be a [=structured header/list=] [[!RFC8941]].
The header's ABNF is:
``` abnf
Sec-CH-UA-Full-Version-List = sf-list
```
To <dfn abstract-op>return the `Sec-CH-UA-Full-Version-List` value for a request</dfn>, perform the
following steps:
1. Let |brands| be the result of running [=create brands=] with "full version".
1. Let |list| be the result of [=creating a brand-version list|create a brand-version list=], with
|brands| and "full version".
1. Return the output of running [=serializing a list=] with |list| as input.
The 'Sec-CH-UA-Mobile' Header Field {#sec-ch-ua-mobile}
--------------------------------
The <dfn http-header>`Sec-CH-UA-Mobile`</dfn> request header field gives a server information about
whether or not a [=user agent=] prefers a "mobile" user experience. It is a [=Structured Header=]
whose value MUST be a [=structured header/boolean=] [[!RFC8941]].
The header's ABNF is:
``` abnf
Sec-CH-UA-Mobile = sf-boolean
```
Note: Like `Sec-CH-UA` above, since it's included in the [=low entropy hint table=],
the `Sec-CH-UA-Mobile` header will be sent by default, whether or not the server opted-into
receiving the header via an `Accept-CH` header (although it can still be controlled by its
[=policy-controlled client hints feature=]). It is considered low entropy because it is a single
bit of information directly controllable by the user.
The 'Sec-CH-UA-Model' Header Field {#sec-ch-ua-model}
-------------------------------
The <dfn http-header>`Sec-CH-UA-Model`</dfn> request header field gives a server information about
the device on which a given [=user agent=] is executing. It is a [=Structured Header=] whose value
MUST be a [=structured header/string=] [[!RFC8941]].
The header's ABNF is:
``` abnf
Sec-CH-UA-Model = sf-string
```
The 'Sec-CH-UA-Platform' Header Field {#sec-ch-ua-platform}
----------------------------------
The <dfn http-header>`Sec-CH-UA-Platform`</dfn> request header field gives a server information
about the platform on which a given [=user agent=] is executing. It is a [=Structured Header=]
whose value MUST be a [=structured header/string=] [[!RFC8941]]. Its value SHOULD match one of the
following common platform values: "Android", "Chrome OS", "Fuchsia", "iOS", "Linux", "macOS",
"Windows", or "Unknown".
The header's ABNF is:
``` abnf
Sec-CH-UA-Platform = sf-string
```
Note: Like `Sec-CH-UA` above, since it's included in the [=low entropy hint table=], the
`Sec-CH-UA-Platform` header will be sent by default, whether or not the server opted-into receiving
the header via an `Accept-CH` header (although it can still be controlled by its
[=policy-controlled client hints feature=]).
The 'Sec-CH-UA-Platform-Version' Header Field {#sec-ch-ua-platform-version}
----------------------------------
The <dfn http-header>`Sec-CH-UA-Platform-Version`</dfn> request header field gives a server
information about the [=user agent/platform version=] on which a given [=user agent=] is executing.
It is a [=Structured Header=] whose value MUST be a [=structured header/string=][[!RFC8941]]. Its
value is the result of [=getting the platform version=] with [=user agent/platform brand=].
To <dfn>get the platform version</dfn>, given a string |platform|, run the following steps:
1. If |platform| is "Linux":
1. Return the empty string.
1. If |platform| is "Android":
1. Let |platformReturnedVersionString| be the result of querying the OS's
`android.os.Build.VERSION.RELEASE` string.
1. Return the result of [=creating a unified platform version string=] with
|platformReturnedVersionString|.
1. If |platform| is "iOS":
1. Let |platformReturnedVersionString| be the result of querying the `UIDevice` object
returned by `currentDevice` and reading its `systemVersion`.
1. Return the result of [=creating a unified platform version string=] with
|platformReturnedVersionString|.
1. If |platform| is "Windows":
1. If available (i.e., on Windows 10 or higher), let |platformReturnedVersionString| be
the result of querying the `Windows.Foundation.UniversalApiContract` integer version
and converting it to a string. Otherwise, let |platformReturnedVersionString| be the
result of [=getting the legacy Windows version number=].
1. Return the result of [=creating a unified platform version string=] with
|platformReturnedVersionString|.
1. Let |platformVersionComponentList| be a [=list=].
1. If |platform| is "macOS":
1. Let |macOSVersion| be the `operatingSystemVersion` property of the `NSProcessInfo` object
returned by getting the `processInfo` information agent.
2. [=list/Append=] |macOSVersion|'s `majorVersion`, `minorVersion`, and `patchVersion`
components (in that order) to |platformVersionComponentList|.
1. If |platform| is some other value:
1. [=list/Append=] one to three version parts based on the format most likely to lead to
interoperability with other browsers running on |platform| to
|platformVersionComponentList|.
2. While |platformVersionComponentList|'s length is less than 3, [=list/append=] "0" to
|platformVersionComponentList|.
1. Return the result of the [=concatenation=] of |platformVersionComponentList| with a U+002E
FULL STOP (`.`) separator.
To <dfn>get the legacy Windows version number</dfn>, run the following steps:
1. Let |major| be the value of `OSVERSIONINFO`'s `dwMajorVersion` member returned from the
Win32 `GetVersionEx` API.
1. Let |minor| be the value of `OSVERSIONINFO`'s `dwMinorVersion` member returned from the
Win32 `GetVersionEx` API.
1. If |major| is `6` and |minor| is `3` (i.e., Windows 8.1), return "0.3".
1. If |major| is `6` and |minor| is `2` (i.e., Windows 8), return "0.2".
1. If |major| is `6` and |minor| is `1` (i.e., Windows 7), return "0.1".
1. Otherwise, return "0".
To <dfn>create a unified platform version string</dfn>, given a string |input|, run the following
steps:
1. Let |platformVersionComponentList| be a [=list=] and |index| be 0.
1. Let |platformVersionUnprocessedTokenList| be the [=list=] returned by
[=strictly split a string|strictly splitting=] |input| on the U+002E FULL STOP character (`.`):
1. While |index| is less than 3:
1. If |index| is less than the length of |platformVersionUnprocessedTokenList|:
1. If |platformVersionUnprocessedTokenList|[|index|] is an unsigned integer, convert it
to a string and [=list/append=] it to |platformVersionComponentList|.
1. Otherwise, [=list/append=] "0" to |platformVersionComponentList|.
1. Otherwise, if |index| is greater than or equal to the length of
|platformVersionUnprocessedTokenList|:
1. [=list/Append=] "0" to |platformVersionComponentList|.
1. Increment |index| by 1.
1. Return the result of the [=concatenation=] of |platformVersionComponentList| with a U+002E
FULL STOP (`.`) separator.
The header's ABNF is:
``` abnf
Sec-CH-UA-Platform-Version = sf-string
```
The 'Sec-CH-UA-WoW64' Header Field {#sec-ch-ua-wow64}
--------------------------------
The <dfn http-header>`Sec-CH-UA-WoW64`</dfn> request header field gives a server information about
whether or not a [=user agent=] binary is running in 32-bit mode on 64-bit Windows.
It is a [=Structured Header=] whose value MUST be a [=structured header/boolean=] [[!RFC8941]].
The header's ABNF is:
``` abnf
Sec-CH-UA-WoW64 = sf-boolean
```
Note: These client hints can be evoked with the following set of [=client hints tokens=]:
`Sec-CH-UA`, `Sec-CH-UA-Arch`, `Sec-CH-UA-Bitness`, `Sec-CH-UA-Form-Factors`,
`Sec-CH-UA-Full-Version`, `Sec-CH-UA-Full-Version-List`, `Sec-CH-UA-Mobile`, `Sec-CH-UA-Model`,
`Sec-CH-UA-Platform`, `Sec-CH-UA-Platform-Version`, `Sec-CH-UA-WoW64`
Interface {#interface}
=================
<pre class="idl">
dictionary NavigatorUABrandVersion {
DOMString brand;
DOMString version;
};
dictionary UADataValues {
DOMString architecture;
DOMString bitness;
sequence<NavigatorUABrandVersion> brands;
sequence<DOMString> formFactors;
sequence<NavigatorUABrandVersion> fullVersionList;
DOMString model;
boolean mobile;
DOMString platform;
DOMString platformVersion;
DOMString uaFullVersion; // deprecated in favor of fullVersionList
boolean wow64;
};
dictionary UALowEntropyJSON {
sequence<NavigatorUABrandVersion> brands;
boolean mobile;
DOMString platform;
};
[Exposed=(Window,Worker)]
interface NavigatorUAData {
readonly attribute FrozenArray<NavigatorUABrandVersion> brands;
readonly attribute boolean mobile;
readonly attribute DOMString platform;
Promise<UADataValues> getHighEntropyValues(sequence<DOMString> hints);
UALowEntropyJSON toJSON();
};
interface mixin NavigatorUA {
[SecureContext] readonly attribute NavigatorUAData userAgentData;
};
Navigator includes NavigatorUA;
WorkerNavigator includes NavigatorUA;
</pre>
Note: The high-entropy portions of the user agent information are retrieved through a {{Promise}}, in order to give [=user agents=] the opportunity to gate their exposure behind potentially time-consuming checks (e.g. by asking the user for their permission).
Processing model {#processing}
--------------
<h4 id="monkeypatch-html-windoworworkerglobalscope"><code>WindowOrWorkerGlobalScope</code></h4>
Each [=user agent=] has an associated <dfn for="user agent">brands</dfn>, which is a [=/list=]
created by running [=create brands=] with [=user agent/significant version=].
Every {{WindowOrWorkerGlobalScope}} object has an associated
<dfn for="WindowOrWorkerGlobalScope">brands frozen array</dfn>, which is a
<code><a interface>FrozenArray</a><<a dictionary>NavigatorUABrandVersion</a>></code>. It is
initially the result of [=create a frozen array|creating a frozen array=] from the [=user agent=]'s
[=brands=].
Additionally, every {{WindowOrWorkerGlobalScope}} object has an associated
<dfn for="WindowOrWorkerGlobalScope">full version list frozen array</dfn>, which is a
<code><a interface>FrozenArray</a><<a dictionary>NavigatorUABrandVersion</a>></code>. It is
the result of [=create a frozen array|creating a frozen array=] from running [=create brands=] with
[=user agent/full version=].
<h4 algorithm="to create brands" id="create-ua-list-section">Create brands</h4>
When asked to <dfn>create brands</dfn> with |version type|, run the following steps:
1. Let |list| be a [=/list=].
1. [=Assert=] |version type| is either "full version" or "significant version".
1. For each [=user agent/brand=] that represents the [=user agent=]—or an [=equivalence class=]—as
|brand|:
1. Let |version| be a [=/string=], initialized accordingly:
1. If |version type| is "full version", set |version| to a string that corresponds to the
[=user agent/full version=].
1. If |version type| is "significant version", set |version| to a string that corresponds to
the [=user agent/significant version=].
1. Let |dict| be a new {{NavigatorUABrandVersion}} dictionary, with
{{NavigatorUABrandVersion/brand}} set to |brand| and
{{NavigatorUABrandVersion/version}} set to |version|.
1. [=list/Append=] |dict| to |list|.
1. The [=user agent=] SHOULD execute the following steps:
1. [=list/Append=] one additional [=list/item=] to |list| containing a
{{NavigatorUABrandVersion}} dictionary, initialized with {{NavigatorUABrandVersion/brand}}
set to <a lt="create an arbitrary brand">arbitrary brand</a> and set
{{NavigatorUABrandVersion/version}} to the result of
[=creating an arbitrary version|create an arbitrary version=] with |version type|.
1. Randomize the order of the [=list/items=] in |list|.
Note: One approach to minimize caching variance when generating these random components could be to
determine them at build time, and keep them identical throughout the lifetime of the [=user agent=]'s significant
version.
Note: See [[#grease]] for more details on when and why these randomization steps might be appropriate.
1. Return |list|.
An <dfn for="user agent" export>equivalence class</dfn> represents a group of browsers believed to be compatible with
each other. A shared rendering engine may form an [=equivalence class=], for example.
<h4 id="create-arbitrary-brands-section"
algorithm="to create arbitrary brand and version values">Create arbitrary brand and version values</h4>
To <dfn>create an arbitrary brand</dfn>, the [=user agent=] MUST run these steps:
1. Let |arbitraryBrand| be a [=/string=] composed of [=ASCII alpha=] and 0x20 (SP).
|arbitraryBrand| MUST contain one or more 0x20 (SP) bytes and be no longer than twenty
[=ASCII bytes=], and MUST not start or end with 0x20 (SP).
1. Let |arbitraryBrandList| be the result of <a lt="split on ASCII whitespace">splitting
|arbitraryBrand| on ASCII whitespace</a>.
1. Let |greaseyStack| be a [=stack=].
1. Let |greaseyChars| be the [=list=] of [=ASCII bytes=] « 0x20 (SP), 0x28 (left parenthesis),
0x29 (right parenthesis), 0x2D (-), 0x2E (.), 0x2F (/), 0x3A (:), 0x3B (;), 0x3D (=), 0x3F
(?), 0x5F (_) ».
1. Let |index| be 0.
1. While |index| is less than the [=list/size=] of |arbitraryBrandList| minus one:
1. [=stack/Push=] a randomly selected [=list/item=] from |greaseyChars| onto |greaseyStack|.
1. Increment |index| by 1.
1. Let |greaseyBrandList| be a [=list=] and set |index| to 0.
1. While |greaseyStack| [=stack/is not empty=]:
1. [=list/Append=] |arbitraryBrandList|[|index|] to |greaseyBrandList|.
1. Let |item| be the result of [=popping=] from |greaseyStack|.
1. [=list/Append=] |item| to |greaseyBrandList|.
1. Increment |index| by 1.
1. [=list/Append=] |arbitraryBrandList|[|index|] to |greaseyBrandList|.
1. Return the result of <a lt="strip leading and trailing ASCII whitespace"> stripping leading
and trailing ASCII whitespace</a> from the [=concatenation=] of |greaseyBrandList| (with no
separator).
<div class="note">
This algorithm should result in an arbitrary brand without leading or trailing |greaseyChars|, as
implementation experience has shown these are not web-compatible.
In addition, despite
[=Structured Headers=] allowing for escaped 0x22 (\") and 0x5C (\\) inside a
[=structured header/string=], these characters have also created compatibility issues with
firewalls.
</div>
To <dfn>create an arbitrary version</dfn> given |version type|, run the following steps:
1. [=Assert=] |version type| is either "full version" or "significant version".
1. Let |arbitrary version| be a [=/string=], initialized accordingly:
1. If |version type| is "full version", set |arbitrary version| to a string that matches the
format of the [=user agent/full version=], but not the value.
1. If |version type| is "significant version", set |arbitrary version| to a string that
matches the format of [=user agent/significant version=], but not the value.
1. Return |arbitrary version|.
Note: User Agents may decide to send arbitrarily low versions to ensure proper version checking, and should vary them
over time.
<h4 id="create-brand-version-list"
algorithm="to create a brand-version list">Create a brand-version list</h4>
To <dfn>create a brand-version list</dfn> given |brands| and |version type|, perform the following
steps:
1. Let |list| be a [=/list=], initially empty.
1. [=Assert=] |version type| is either "full version" or "significant version".
1. For each |brand| in |brands|:
1. Let |version| be a string, initialized accordingly:
1. If |version type| is "full version", set |version| to a string that corresponds to
the [=user agent/full version=].
1. If |version type| is "significant version", set |version| to a string that
corresponds to the [=user agent/significant version=].
1. Let |parameter| be a [=dictionary=], initially empty.
1. Set |parameter|["param_key"] to "v".
1. Set |parameter|["param_value"] to |version|.
1. Let |pair| be a tuple comprised of |brand|'s {{NavigatorUABrandVersion/brand}} and
|parameter|.
1. [=list/Append=] |pair| to |list|.
1. Return |list|.
<h4 id="getters">Getters</h4>
On getting, the {{NavigatorUAData/brands}} attribute MUST return [=this=]'s [=relevant global object=]'s [=WindowOrWorkerGlobalScope/brands frozen array=].
On getting, the {{NavigatorUAData/mobile}} attribute must return the [=user agent=]'s [=user agent/mobileness=].
On getting, the {{NavigatorUAData/platform}} attribute must return the [=user agent=]'s [=user agent/platform brand=].
<h4 id="getHighEntropyValues"><code>getHighEntropyValues</code> method</h4>
The <dfn method for="NavigatorUA"><code>getHighEntropyValues(|hints|)</code></dfn> method MUST run these steps:
1. Let |p| be a [=a new promise=] created in the [=current realm=].
2. If the [=user agent=] decides one or more values in |hints| should not be returned, then [=reject=] and return |p| with a "{{NotAllowedError}}".
ISSUE(wicg/ua-client-hints): We can improve upon when and why a UA decides to refuse a hint once [Issue #151](https://github.com/WICG/ua-client-hints/issues/151) is resolved.
3. Otherwise, run the following steps [=in parallel=]:
1. Let |uaData| be a new {{UADataValues}}.
1. set |uaData|["{{UADataValues/brands}}"] to [=this=]'s [=relevant global object=]'s
[=WindowOrWorkerGlobalScope/brands frozen array=].
1. set |uaData|["{{UADataValues/mobile}}"] to the [=user agent=]'s [=user agent/mobileness=].
1. set |uaData|["{{UADataValues/platform}}"] to the [=user agent=]'s [=user agent/platform brand=].
1. If |hints| [=list/contains=] "architecture", set |uaData|["{{UADataValues/architecture}}"] to
the [=user agent=]'s [=user agent/platform architecture=].
1. If |hints| [=list/contains=] "bitness", set |uaData|["{{UADataValues/bitness}}"] to
the [=user agent=]'s [=user agent/platform bitness=].
1. If |hints| [=list/contains=] "formFactors", set |uaData|["{{UADataValues/formFactors}}"] to
the [=user agent=]'s [=user agent/form-factors=].
1. If |hints| [=list/contains=] "fullVersionList", set |uaData|["{{UADataValues/fullVersionList}}"]
to [=this=]'s [=relevant global object=]'s
[=WindowOrWorkerGlobalScope/full version list frozen array=].
1. If |hints| [=list/contains=] "model", set |uaData|["{{UADataValues/model}}"] to the
[=user agent=]'s [=user agent/model=].
1. If |hints| [=list/contains=] "platformVersion", set |uaData|["{{UADataValues/platformVersion}}"]