summaryrefslogtreecommitdiff
path: root/docs/html/training/articles/user-data-ids.jd
blob: 91021669b6494777ed054d9b4087df1b77aa9c4a (plain)
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
page.title=Best Practices for Unique Identifiers
page.metaDescription=How to manage unique identifiers the right way for users.
page.tags=ids, user data
meta.tags="ids", "user data"
page.image=images/cards/card-user-ids_2x.png

page.article=true
@jd:body

<div id="tb-wrapper">
<div id="tb">
    <h2>In this document</h2>
    <ol>
      <li><a href="#tenets_of_working_with_android_identifiers">Tenets of Working with
      Android Identifiers</a></li>
      <li><a href="#version_specific_details_identifiers_in_m">Identifiers in Android 6.0+</a></li>
      <li><a href="#working_with_advertising_ids">Working with Advertising IDs</a></li>
      <li><a href="#working_with_instance_ids_&_guids">Working with Instance IDs and GUIDs</a></li>
      <li><a href="#understand_identifier_characteristics">Understanding Identifier
      Characteristics</a>
      <ol>
        <li><a href="#scope">Scope</a></li>
        <li><a href="#resettability_&_persistence">Resettability &amp; persistence</a></li>
        <li><a href="#uniqueness">Uniqueness</h3>
        <li><a href="#integrity_protection_and_non-repudiability">Integrity protection and
        non-repudiability</a></li>
      </ol>
      </li>
      <li><a href="#use_appropriate_identifiers">Common Use Cases and the Identifier to Use</a>
      <ol>
        <li><a href="#a_track_signed-out_user_preferences">Tracking signed-out user
        preferences</a></li>
        <li><a href="#b_track_signed-out_user_behavior">Tracking signed-out user behavior</a></li>
        <li><a href="#c_generate_signed-out_anonymous_user_analytics">Generating
        signed-out/anonymous user analytics</a></li>
        <li><a href="#d_track_signed-out_user_conversion">Tracking signed-out user
        conversion</a></li>
        <li><a href="#e_handle_multiple_installations">Handling multiple installations</a></li>
        <li><a href="#f_anti-fraud_enforcing_free_content_limits_detecting_sybil_attacks">Anti-fraud:
        Enforcing free content limits / detecting Sybil attacks</a></li>
        <li><a href="#g_manage_telephony_&_carrier_functionality">Managing telephony and carrier
        functionality</a></li>
        <li><a href="#h_abuse_detection_identifying_bots_and_ddos_attacks">Abuse detection:
        Identifying bots and DDoS attacks</a></li>
        <li><a href="#i_abuse_detection_detecting_high_value_stolen_credentials">Abuse detection:
        Detecting high value stolen credentials</a></li>
      </ol>
      </li>
    </ol>
  </div>
</div>

<p>
  While there are valid reasons why your application may need to identify a
  device rather than an instance of the application or an authenticated user on
  the device, for the vast majority of applications, the ultimate goal is to
  identify a particular <em>installation</em> of your app (not the actual
  physical device).
</p>

<p>
  Fortunately, identifying an installation on Android is straightforward using
  an Instance ID or by creating your own GUID at install time. This document
  provides guidance for selecting appropriate identifiers for your application,
  based on your use-case.
</p>

<p>
  For a general look at Android permissions, please see <a href=
  "{@docRoot}training/articles/user-data-overview.html">Permissions
  and User Data</a>. For specific best practices for
  working with Android permissions, please see <a href=
  "{@docRoot}training/articles/user-data-permissions.html">Best Practices for
  App Permissions</a>.
</p>


<h2 id="tenets_of_working_with_android_identifiers">Tenets of Working with Android Identifiers</h2>

<p>
  We recommend that you follow these tenets when working with Android
  identifiers:
</p>

<p>
  <em><strong>#1: Avoid using hardware identifiers.</strong></em> Hardware
  identifiers such as SSAID (Android ID) and IMEI can be avoided in most
  use-cases without limiting required functionality.
</p>

<p>
  <em><strong>#2: Only use Advertising ID for user profiling or ads
  use-cases.</strong></em> When using an <a href=
  "https://support.google.com/googleplay/android-developer/answer/6048248?hl=en">
  Advertising ID</a>, always respect the <a href=
  "https://play.google.com/about/developer-content-policy.html#ADID">Limit Ad
  Tracking</a> flag, ensure the identifier cannot be connected to personally
  identifiable information (PII) and avoid bridging Advertising ID resets.
</p>

<p>
  <em><strong>#3: Use an Instance ID or a privately stored GUID whenever
  possible for all other use-cases except payment fraud prevention and
  telephony.</strong></em> For the vast majority of non-ads use-cases, an
  instance ID or GUID should be sufficient.
</p>

<p>
  <em><strong>#4: Use APIs that are appropriate to your use-case to minimize
  privacy risk.</strong></em> Use the
  <a href="http://source.android.com/devices/drm.html">DRM
  API</a> API for high value content
  protection and the <a href="{@docRoot}training/safetynet/index.html">SafetyNet
  API</a> for abuse prevention. The Safetynet API is
  the easiest way to determine whether a device is genuine without incurring
  privacy risk.
</p>

<p>
  The remaining sections of this guide elaborate on these rules in the context
  of developing Android applications.
</p>

<h2 id="version_specific_details_identifiers_in_m">Identifiers in Android 6.0+</h2>

<p>
  MAC addresses are globally unique, not user-resettable and survive factory
  reset. It is generally not recommended to use MAC address for any form of
  user identification. As a result, as of Android M, local device MAC addresses
  (for example, Wifi and Bluetooth) <em><strong>are not available via third party
  APIs</strong></em>. The {@link android.net.wifi.WifiInfo#getMacAddress WifiInfo.getMacAddress()}
  method and the {@link android.bluetooth.BluetoothAdapter#getAddress
  BluetoothAdapter.getDefaultAdapter().getAddress()} method will
  both return <code>02:00:00:00:00:00</code>..
</p>

<p>
  Additionally, you must hold the following permissions to access MAC addresses
  of nearby external devices available via Bluetooth and Wifi scans:
</p>

<table>
 <tr>
    <th><strong>Method/Property</strong></td>
    <th><strong>Permissions Required</strong></td>
 </tr>
 <tr>
    <td>
      <code><a href="{@docRoot}reference/android/net/wifi/WifiManager.html#getScanResults()">WifiManager.getScanResults()</a></code>
    </td>
    <td>
      <code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code>
    </td>
 </tr>
 <tr>
    <td>
      <code><a href="{@docRoot}reference/android/bluetooth/BluetoothDevice.html#ACTION_FOUND">BluetoothDevice.ACTION_FOUND</a></code>
    </td>
    <td>
      <code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code>
    </td>
 </tr>
 <tr>
    <td>
      <code><a href="{@docRoot}reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(android.bluetooth.le.ScanCallback)">BluetoothLeScanner.startScan(ScanCallback)</a></code>
    </td>
    <td>
      <code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code>
    </td>
 </tr>
</table>


<h2 id="working_with_advertising_ids">Working with Advertising IDs</h2>

<p>
  Advertising ID is a user-resettable identifier and is appropriate for Ads
  use-cases, but there are some key points to bear in mind when using it:
</p>

<p>
  <em><strong>Always respect the user’s intention in resetting the advertising
  ID</strong></em>. Do not bridge user resets by using a more persistent device
  identifier or fingerprint to link subsequent Advertising IDs together without
  the user’s consent. The <a href=
  "https://play.google.com/about/developer-content-policy.html">Google Play
  Developer Content Policy</a> states:
</p>

<div style="padding:.5em 2em;">
<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
<p>...if reset, a new advertising
  identifier must not be connected to a previous advertising identifier or data
  derived from a previous advertising identifier without the explicit consent
  of the user.</span></p>
</div>
</div>

<p>
  <em><strong>Always respect the associated Personalized Ads
  flag</strong></em>. Advertising IDs are configurable in that users can limit
  the amount of tracking associated with the ID. Always use the <code><a href=
  "https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info.html#isLimitAdTrackingEnabled()">
  AdvertisingIdClient.Info.isLimitAdTrackingEnabled()</a></code> method to
  ensure you are not circumventing your users' wishes. The <a href=
  "https://play.google.com/about/developer-content-policy.html">Google Play
  Developer Content Policy</a> states:
</p>


<div style="padding:.5em 2em;">
<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
<p>...you must abide by a user’s ‘Opt out of interest-based advertising’ or 'Opt
  out of Ads Personalization' setting. If a user has enabled this setting, you
  may not use the advertising identifier for creating user profiles for
  advertising purposes or for targeting users with personalized advertising.
  Allowed activities include contextual advertising, frequency capping,
  conversion tracking, reporting and security and fraud detection.</span></p>
</div>
</div>

<p>
  <em><strong>Be aware of any privacy or security policies associated with SDKs
  you use that are related to Advertising ID use.</strong></em> For example, if
  you are using the Google Analytics SDK
  <code><a href=
  "https://developers.google.com/android/reference/com/google/android/gms/analytics/Tracker.html#enableAdvertisingIdCollection(boolean)">mTracker.enableAdvertisingIdCollection(true)</a></code>
  method, make sure to review and adhere to all applicable <a href=
  "https://developers.google.com/analytics/devguides/collection/android/v4/policy">
  Analytics SDK policies</a>.
</p>

<p>
  Also, be aware that the <a href=
  "https://play.google.com/about/developer-content-policy.html">Google Play
  Developer Content Policy</a> requires that the Advertising ID “must not be
  connected to personally-identifiable information or associated with any
  persistent device identifier (for example: SSAID, MAC address, IMEI, etc.,)
  without the explicit consent of the user.”
</p>

<p>
  As an example, suppose you want to collect information to populate database
  tables with the following columns:
</p>

<table>
 <tr>
    <td>
      <table>
       <tr>
          <td class="tab2">
      <code>timestamp</code></td>
          <td class="tab2">
      <code>ad_id</code></td>
          <td>
      <code><strong>account_id</strong></code></td>
          <td class="tab2">
      <code>clickid</code></td>
       </tr>
      </table>

      <p>TABLE-01</p>
    </td>
    <td>
      <table>
       <tr>
          <td>
      <code><strong>account_id</strong></code></td>
          <td class="tab2">
      <code>name</code></td>
          <td class="tab2">
      <code>dob</code></td>
          <td class="tab2">
      <code>country</code></td>
       </tr>
      </table>
      <p>TABLE-02</p>
    </td>
 </tr>
</table>


<p>
  In this example, the <code>ad_id</code> column could be joined to PII via the
  <code>account_id</code> column in both tables, which would be a violation of
  the <a href=
  "https://play.google.com/about/developer-content-policy.html">Google Play
  Developer Content Policy</a>, if you did not get explicit permission from
  your users.
</p>

<p>
  Keep in mind that links between Advertiser ID and PII aren't always this
  explicit. It's possible to have “quasi-identifiers” that appear in both PII
  and Ad ID keyed tables, which also cause problems. For example, assume we
  change TABLE-01 and TABLE-02 as follows:
</p>

<table>
 <tr>
    <td><table>
 <tr>
    <td>
      <code><strong>timestamp</strong></code></td>
          <td class="tab2">
      <code>ad_id</code></td>
          <td>
      <code>clickid</code></td>
          <td>
      <code><strong>dev_model</strong></code></td>
       </tr>
      </table>

      </pre>
      <p>TABLE-01</p>
    </td>
    <td>
      <table>
       <tr>
          <td>
      <code><strong>timestamp</strong></code></td>
          <td class="tab2">
      <code>demo</code></td>
          <td class="tab2">
      <code>account_id</code></td>
          <td>
      <code><strong>dev_model</strong></code></td>
          <td class="tab2">
      <code>name</code></td>
       </tr>
      </table>
      <p>TABLE-02</p>
    </td>
 </tr>
</table>


<p>
  In this case, with sufficiently rare click events, it's still possible to
  join between the Advertiser ID TABLE-01 and the PII contained in TABLE-2
  using the timestamp of the event and the device model.
</p>

<p>
  While it is often difficult to guarantee that no such quasi-identifiers exist
  in a dataset, the most obvious join risks can be prevented by generalizing
  unique data where possible. In the example, this would mean reducing the
  accuracy of the timestamp so that multiple devices with the same model appear
  for every timestamp.
</p>

<p>
  Other solutions include:
</p>

<ul>
<li><em><strong>Not designing tables that explicitly link PII with Advertising
IDs</strong></em>. In the first example above this would mean not including the
account_id column in TABLE-01.</li>

<li><em><strong>Segregating and monitoring access control lists for users or roles
that have access to both the Advertising ID keyed data and PII</strong></em>. If the
ability to access both sources simultaneously (for example, to perform
a join between two tables) is tightly controlled and audited, it reduces the
risk of association between the Advertising ID and PII. Generally speaking,
controlling access means:

<ol>
  <li> Keeping access control lists (ACLs) for Advertiser ID keyed data and PII disjoint to
  minimize the number of individuals or roles that are in both ACLs, and</li>
  <li> Implementing access logging and auditing to detect and manage any exceptions to
  this rule.</li>
</ol>
</li>
</ul>

<p>
  For more information on working responsibly with Advertising IDs, please see
  the <a href=
  "https://support.google.com/googleplay/android-developer/answer/6048248?hl=en">
  Advertising ID</a> help center article.
</p>

<h2 id="working_with_instance_ids_&_guids">Working with Instance IDs and GUIDs</h2>

<p>
  The most straightforward solution to identifying an application instance
  running on a device is to use an Instance ID, and this is the recommended
  solution in the majority of non-ads use-cases. Only the app instance for
  which it was provisioned can access this identifier, and it's (relatively)
  easily resettable because it only persists as long as the app is installed.
</p>

<p>
  As a result, Instance IDs provide better privacy properties compared to
  non-resettable, device-scoped hardware IDs. They also come with a key-pair
  for message signing (and similar actions) and are available on Android, iOS
  and Chrome. Please see the <a href=
  "https://developers.google.com/instance-id/">What is Instance ID?</a> help
  center document for more information.
</p>

<p>
  In cases where an Instance ID isn't practical, custom globally unique IDs
  (GUIDs) can also be used to uniquely identify an app instance. The simplest
  way to do so is by generating your own GUID using the following code.
</p>

<pre>String uniqueID = UUID.randomUUID().toString();</pre>

<p>
  Because the identifier is globally unique, it can be used to identify a
  specific app instance. To avoid concerns related to linking the identifier
  across applications, GUIDs should be stored in internal storage rather than
  external (shared) storage. Please see <a href=
  "{@docRoot}guide/topics/data/data-storage.html">Storage Options</a> guide for
  more information.
</p>


<h2 id="understand_identifier_characteristics">Understanding Identifier Characteristics</h2>

<p>
  The Android Operating system offers a number of IDs with different behavior
  characteristics and which ID you should use depends on how those following
  characteristics work with your use-case. But these characteristics also come
  with privacy implications so it's important to understand how these
  characteristics play together.
</p>

<h3 id="scope">Scope</h3>

<p>
  Identifier scope explains which systems can access the identifier. Android
  identifier scope generally comes in three flavors:
</p>

<ul>
  <li> <em>Single app</em>.  the ID is internal to the app and not accessible to other apps.
  <li> <em>Group of apps</em> - the ID is accessible to a pre-defined group of related apps.
  <li> <em>Device</em> - the ID is accessible to all apps installed on the device.
</ul>

<p>
  The wider the scope granted to an identifier, the greater the risk of it
  being used for tracking purposes. Conversely, if an identifier can only be
  accessed by a single app instance, it can’t be used to track a device across
  transactions in different apps.
</p>
<h3 id="resettability_&_persistence">Resettability and persistence</h3>

<p>
  Resettability and persistence define the lifespan of the identifier and
  explain how it can be reset. Common reset triggers are: in-app resets, resets
  via System Settings, resets on launch, and resets on installation. Android
  Identifiers can have varying lifespans, but the lifespan is usually related
  to how the ID is reset:
</p>
<ul>
  <li> <em>Session-only</em> - a new ID is used every time the user restarts the app.
  <li> <em>Install-reset</em> - a new ID is used every time user uninstalls and reinstalls the app.
  <li> <em>FDR-reset</em> - a new ID is used every time the user factory-resets the device.
  <li> <em>FDR-persistent</em> - the ID survives factory reset.
</ul>

<p>
  Resettability gives users the ability to create a new ID that is
  disassociated from any existing profile information. This is important
  because the longer, and more reliably, an identifier persists (e.g. across
  factory resets etc.), the greater the risk that the user may be subjected to
  long-term tracking. If the identifier is reset upon app reinstall, this
  reduces the persistence and provides a means for the ID to be reset, even if
  there is no explicit user control to reset it from within the app or the
  System Settings.
</p>
<h3 id="uniqueness">Uniqueness</h3>

<p>
  Uniqueness establishes the likelihood that identical identifiers exist within
  the associated scope. At the highest level, a globally unique identifier will
  never have a collision - even on other devices/apps. Otherwise, the level of
  uniqueness depends on the size of the identifier and the source of randomness
  used to create it. For example, the chance of a collision is much higher for
  random identifiers seeded with the calendar date of installation (e.g.,
  2015-01-05) than for identifiers seeded with the Unix timestamp of
  installation (e.g., 1445530977).
</p>

<p>
  In general, user account identifiers can be considered unique (i.e., each
  device/account combo has a unique ID). On the other hand, the less unique
  an identifier is within a population (e.g. of devices), the greater the
  privacy protection because it's less useful for tracking an individual user.
</p>

<h3 id="integrity_protection_and_non-repudiability">Integrity protection and
non-repudiability</h3>

<p>
  An identifier that is difficult to spoof or replay can be used to prove that
  the associated device or account has certain properties (e.g. it’s not a
  virtual device used by a spammer). Difficult to spoof identifiers also
  provide <em>non-repudiability</em>. If the device signs a message with a
  secret key, it is difficult to claim someone else’s device sent the message.
  Non-repudiability could be something a user wants (e.g. authenticating a
  payment) or it could be an undesirable property (e.g. sending a message they
  regret).
</p>


<h2 id="use_appropriate_identifiers">Common Use Cases and the Identifier to Use</h2>

<p>
  This section provides alternatives to using hardware IDs such as IMEI or
  SSAID for the majority of use-cases. Relying on hardware IDs is discouraged
  because the user cannot reset them and generally has limited control over
  their collection.
</p>

<h3 id="a_track_signed-out_user_preferences">Tracking signed-out user preferences</h3>

<p>
  <em>In this case, you are saving per-device state on the server side.</em>
</p>

<p>
  <strong>We Recommend</strong>: Instance ID or a GUID.
</p>

<p>
  <strong>Why this Recommendation?</strong>
</p>

<p>
  Persisting information through reinstalls is not recommended because users
  may want to reset their preferences by reinstalling the app.
</p>

<h3 id="b_track_signed-out_user_behavior">Tracking signed-out user behavior</h3>

<p>
  <em>In this case, you have created a profile of a user based on their
  behavior across different apps/sessions on the same device.</em>
</p>

<p>
  <strong>We Recommend</strong>: Advertising ID.
</p>

<p>
  <strong>Why this Recommendation?</strong>
</p>

<p>
  Use of the Advertising ID is mandatory for Advertising use-cases per the
  <a href="https://play.google.com/about/developer-content-policy.html">Google
  Play Developer Content Policy</a> because the user can reset it.
</p>

<h3 id="c_generate_signed-out_anonymous_user_analytics">Generating signed-out/anonymous user analytics</h3>

<p>
  <em>In this case, you are measuring usage statistics and analytics for
  signed-out or anonymous users.</em>
</p>

<p>
  <strong>We Recommend</strong>: Instance ID; if an Instance ID is
  insufficient, you can also use a GUID.
</p>

<p>
  <strong>Why this Recommendation?</strong>
</p>

<p>
  An Instance ID or a GUID is scoped to the app that creates it, which prevents
  it from being used to track users across apps. It is also easily reset by
  clearing app data or reinstalling the app. Creating Instance IDs and GUIDs is
  straightforward:
</p>

<ul>
  <li> Creating an Instance ID: <code>String iid = InstanceID.getInstance(context).getId()</code>
  <li> Creating a GUID: <code>String uniqueID = UUID.randomUUID().toString</code>
</ul>

<p>
  Be aware that if you have told the user that the data you are collecting is
  anonymous, you should <em><strong>ensure you are not connecting the
  identifier to PII</strong></em> or other identifiers that may be linked to
  PII.
</p>

<p>
  You can also use Google Analytics for Mobile Apps, which offers a solution
  for per-app analytics.
</p>

<h3 id="d_track_signed-out_user_conversion">Tracking signed-out user conversion</h3>

<p>
  <em>In this case, you are tracking conversions to detect if your marketing
  strategy was successful.</em>
</p>

<p>
  <strong>We Recommend</strong>: Advertising ID.
</p>

<p>
  <strong>Why this Recommendation?</strong>
</p>

<p>
  This is an ads-related use-case which may require an ID that is available
  across different apps so using an Advertising ID is the most appropriate
  solution.
</p>

<h3 id="e_handle_multiple_installations">Handling multiple installations</h3>

<p>
  <em>In this case, you need to identify the correct instance of the app when
  it's installed on multiple devices for the same user.</em>
</p>

<p>
  <strong>We Recommend</strong>: Instance ID or GUID.
</p>

<p>
  <strong>Why this Recommendation?</strong>
</p>

<p>
  Instance ID is designed explicitly for this purpose; its scope is limited to
  the app so that it cannot be used to track users across different apps and it
  is reset upon app reinstall. In the rare cases where an Instance ID is
  insufficient, you can also use a GUID.
</p>

<h3 id="f_anti-fraud_enforcing_free_content_limits_detecting_sybil_attacks">Anti-fraud: Enforcing free content limits / detecting Sybil attacks</h3>

<p>
  <em>In this case, you want to limit the number of free content (e.g.
  articles) a user can see on a device.</em>
</p>

<p>
  <strong>We Recommend</strong>: Instance ID or GUID.
</p>

<p>
  <strong>Why this Recommendation?</strong>
</p>

<p>
  Using a GUID or Instance ID forces the user to reinstall the app in order to
  overcome the content limits, which is a sufficient burden to deter most
  people. If this is not sufficient protection, Android provides a
  <a href="http://source.android.com/devices/drm.html">DRM API</a>
  which can be used to limit access to content.
</p>

<h3 id="g_manage_telephony_&_carrier_functionality">Managing telephony and carrier functionality</h3>

<p>
  <em>In this case, your app is interacting with the device's phone and texting
  functionality.</em>
</p>

<p>
  <strong>We Recommend</strong>: IMEI, IMSI, and Line1 (requires <code>PHONE</code>
  permission group in Android 6.0 (API level 23) and higher).
</p>

<p>
  <strong>Why this Recommendation?</strong>
</p>

<p>
  Leveraging hardware identifiers is acceptable if it is required for
  telephony/carrier related functionality; for example, switching between
  cellular carriers/SIM slots or delivering SMS messages over IP (for Line1) -
  SIM-based user accounts. But it's important to note that in Android 6.0+
  these identifiers can only be used via a runtime permission and that users
  may toggle off this permission so your app should handle these exceptions
  gracefully.
</p>

<h3 id="h_abuse_detection_identifying_bots_and_ddos_attacks">Abuse detection:
Identifying bots and DDoS attacks</h3>

<p>
  <em>In this case, you are trying to detect multiple fake devices attacking
  your backend services.</em>
</p>

<p>
  <strong>We Recommend:</strong> The Safetynet API.
</p>

<p>
  <strong>Why this Recommendation?</strong>
</p>

<p>
  An identifier in isolation does little to indicate that a device is genuine.
  You can verify that a request comes from a genuine Android device (as opposed
  to an emulator or other code spoofing another device) using the Safetynet
  API's <code>SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce)</code>
  method to verify the integrity of a device making a request. For more
  detailed information, please see <a href=
  "{@docRoot}training/safetynet/index.html">Safetynet's API documentation</a>.
</p>

<h3 id="i_abuse_detection_detecting_high_value_stolen_credentials">Abuse detection:
Detecting high value stolen credentials</h3>

<p>
  <em>In this case, you are trying to detect if a single device is being used
  multiple times with high-value, stolen credentials (e.g. to make fraudulent
  payments).</em>
</p>

<p>
  <strong>We Recommend</strong>: IMEI/IMSI (requires <code>PHONE</code>
  permission group in Android 6.0 (API level 23) and higher.)
</p>

<p>
  <strong>Why this Recommendation?</strong>
</p>

<p>
  With stolen credentials, devices can be used to monetize multiple high value
  stolen credentials (such as tokenized credit cards). In these scenarios,
  software IDs can be reset to avoid detection, so hardware identifiers may be
  used.
</p>