Signed in user tracking and privacy
It is possible to track the activity of a signed-in user, in association with their hashed user ID (HID). This means it is possible to associate activity across multiple sessions and devices to the same user account.
Note though that there are various measures in place to protect the privacy of users, while getting the best possible data.
Because of the differences between web and mobile, Echo manages this quite differently on each platform.
Table of contents
- Echo JS
- Echo iOS/Android
Echo JS
Browsers are identified using the atuserid cookie (domain=.bbc.co.uk). This cookie is set by the ATI library within Echo (or Reverb). If this cookie is deleted for any reason then a new cookie, with a new ID, is generated.
Alternatively this can be overridden using the idclient parameter of the request to ATI. This is set by Echo when a custom device ID has been provided. This is appropriate where you are working in an environment that does not use cookies, for example a desktop app or smart TV.
If neither of these identifiers are available/provided then ATI will infer the device from a combination of IP address and User Agent.
BBC Cookie preferences
Users can opt out of performance cookies, but not cookies classed as “strictly necessary”, as explained here on the Cookie Settings page.
Analytics cookies are classed as strictly necessary, so there is no way to opt out of them.
In order to be anonymously tracked, a user can turn off personalisation on the Privacy and cookies page
If this option is toggled, their atuserid
cookie will be reset, and if they are signed in they will be recorded as “unidentified-user” rather than using their hashed ID (see below).
BBC ID
When used in an Orbit page Echo will automatically detect if the user is logged in and has a hashed ID (HID) by using the idcta javascript module.
For a signed in user:
- with a hashed ID (personalisation enabled): report the
at
value with the user’s hased ID - without a hashed ID: report the
at
value asunidentified-user
It is also possible, in a non-Orbit context only, to indicate that a user is logged in manually using the setLoggedInToBBCId()
method:
// Indicate user is logged to BBC iD with a hashed Id
// sets bbc_identity=1 and bbc_hid=users-hashed-id
echo.setLoggedInToBBCId("users-hashed-id");
// Indicate user is logged to BBC iD without a hashed Id
// sets bbc_identity=1
// removes bbc_hid property
echo.setLoggedInToBBCId();
// Indicate user is logged out of BBC iD
// removes bbc_identify and bbc_hid properties
echo.setLoggedOutOfBBCId();
Echo iOS/Android
Clearly there are no cookies in a native environment (with the exception of webviews, see below), so device ID is always sent as the idclient
parameter.
Echo iOS and Android support the IDv5 User Promise. The effects of this are described below. Note that this used to be optional but is not anymore. If you do not enable IDv5 then user tracking will be disabled.
Enabling Webview Cookies
If your application uses webviews, then Echo will automatically take care of generating a device ID for you and ensure that the device ID is kept up-to-date according to user state changes. Echo stores the device ID in a cookie called ckns_echo_device_id
on both ‘.bbc.co.uk’ and ‘.bbc.com’ domains.
Reverb (the analytics tracker that is present on Orb-enabled web pages) will pick up the ckns_echo_device_id
cookie value and use it in preference to the value generated by ATI. This makes it possible to associate the web page views with the same device/session.
To enable Webview Cookies on a given platform, follow the instructions below.
Android
Set EchoConfigKeys.WEBVIEW_COOKIES_ENABLED
to true
in the config HashMap
passed to the Echo constructor.
iOS (Swift)
Set config[.webviewCookiesEnabled]
to "true"
in the config Dictionary
passed to the Echo constructor.
Informing Echo About User State
Are you using the BBC Auth Toolkit? If your application supports authentication using BBC ID you should be using the Mobile Platforms Auth Toolkit.
The Auth Toolkit is able to automatically inform Echo about changes to user state and this is the expected pattern for integration. You should not need to create BBCUser objects within your application etc as the toolkit will take care of this. See Auth Tookit iOS and Auth Toolkit Android for more information.
The BBCUser
object (see below) is used to:
- encapsulate the state of a user (sign-in state, etc.)
- provide an ID token refresh timestamp
When Echo detects a change in user state, e.g. signed in to signed out, a new device ID will be generated. During normal operation, where a user is likely to stay signed in or out indefinitely, Echo should not see any change to user state and should use a single device ID across multiple application sessions.
Applications using Echo are expected to:
-
Inform Echo about the initial user state - Pass a
BBCUser
object to theEchoClient
constructor that represents the last known user state. This will probably happen when your application starts up. The user state should represent the state of the user when the application was last used, even if the user’s ID token has expired. -
Inform Echo of any changes to user state - While your application is running a user may sign in, sign out or toggle personalisation. If this happens you must inform Echo by passing a new BBCUser object to the
EchoClient.setBBCUser
method. -
Inform Echo whenever the ID token has been refreshed - In order to remain authenticated it is necessary for an ID token to be refreshed periodically. Echo should be informed when the token is refreshed by creating a new
BBCUser
object with an appropriate value for thetokenRefreshTimestamp
property and then passing the user to theEchoClient.setBBCUser
method.
BBCUser
Both the iOS and Android versions of Echo can now be provided with a BBCUser
object that represents the current state of a user. It is possible to create a user with the following states:
State | Personalisation enabled |
---|---|
Logged out | No |
Logged in | No (inferred from a null hashed ID) |
Logged in | Yes (inferred from a non-null hashed ID) |
If no user is provided to Echo, by passing nil
/null
(or on iOS Swift, a new user with no arguments: BBCUser()
) to the Echo constructor, the library defaults to a user object that is logged out with personalisation disabled.
When creating a user that’s logged in with personalisation enabled it is also necessary to provide a date object with the time that the user’s login token was last refreshed. Every time a user’s login token is refreshed, a new user should be created and passed to Echo with an updated token refresh timestamp. This will be used to determine when a user’s token has expired (24 hours after creation) and stop transmitting data until a new BBCUser
object with a valid timestamp is provided (see the token expiration section section below).
Access and Identity Tokens
New in Echo starting from version 18.0.0 <=
on Android and 5.8.0 <=
on iOS, you can provide a user’s access token and identity token. See the examples below for details. These are JWT tokens, and set as string values in the BBCUser, if you are using Authtoolkit these will be provided to Echo from there.
If these tokens are not provided, they will be set to null
/nil
, and this may cause problems for certain reporting eg via BAG (for Appsflyer or UAS).
Passing a BBCUser to Echo
Providing a hashed ID
Please note that ATI will use the first hashed ID they receive, for the entire session. So updating a user as shown below will not be reflected in reports.
It is important to set the hashed ID of a signed in user at initialisation, or the ID of “unidentified-user” will be seen for the entire session.
If in doubt contact us!
Please ensure you have read “Are you using the BBC Auth Toolkit?” above.
// Create user - all parameters except signedIn are optional
let user = BBCUser(signedIn: true, hashedId: "hashed_id", accessToken: "access_token", identityToken: "identity_token", tokenRefreshTimestamp: Date())
// Pass user into Echo constructor
let echo = EchoClient(
appName: "MyApp",
appType: .mobileApp,
startCounterName: "bbc.start.page",
config: config,
bbcUser: user
)
// Update user on Echo client
echo.setBBCUser(user)
// Example: not signed in
user = BBCUser(signedIn: false)
echo.setBBCUser(user)
// Example: signed in without a BBC hashed ID (personalisation disabled, not old enough etc)
user = BBCUser(signedIn: true, hashedID: nil, tokenRefreshTimestamp: Date())
echo.setBBCUser(user)
// Example: signed in with a BBC hashed ID and token strings
user = BBCUser(signedIn: true, hashedId: "hashed_id", accessToken: "access_token", identityToken: "identity_token", tokenRefreshTimestamp: Date())
echo.setBBCUser(user)
// Create user
BBCUser user = new BBCUser(true, "hashed_id", "access_token", "identity_token", new Date());
// Pass user into Echo constructor
EchoClient echo = new EchoClient(
"MyApp",
ApplicationType.MOBILE_APP,
"bbc.start.page",
getApplicationContext(),
config,
user,
this
);
// Update user on Echo client
echo.setBBCUser(user);
// Example: not signed in
user = new BBCUser(false, null, null, null, null);
echo.setBBCUser(user);
// Example: signed in without a BBC hashed ID (personalisation disabled, not old enough etc)
user = new BBCUser(true, null, null, null, new Date());
echo.setBBCUser(user);
// Example: signed in with a BBC hashed ID and token strings
user = new BBCUser(true, "hashed_id", "access_token", "identity_token", new Date());
echo.setBBCUser(user);
Token Expiration and User State Changes
Based on the refresh timestamp provided (Echo considers the token to be valid for 24 hours), a user’s token will expire, and Echo will transition to an expired token state, unless a new valid token refresh timestamp has been provided before this time (in which case normal service will continue uninterrupted).
When a token is allowed to lapse (perhaps because of a network interruption or unavailability of the ID service), Echo will begin to cache all events and will not transmit them until the same BBCUser
is provided with a new valid token refresh timestamp, at which point the cached data will be immediately transmitted and normal transmission will resume.
Disabling transmission when user state changes
For further user privacy protection, there is an option to disable transmission when a user’s state changes.
In the event that a BBCUser
is provided with a different ID — or personalisation state is changed (whether in an expired token state or not) — Echo will disable transmission, the cached data will be discarded (to prevent it being associated with the wrong user), and transmission will not resume until the next cold start of the app. A user_state_change
event will be sent with details of why this has happened, at the next available opportunity.
In this case, data will not be collected or transmitted during this time, or cached for future transmission. Data from this session will be lost. This is necessary to prevent persistent identifiers linking the two users’ activities and breaching the “user promise”.
To enable this feature:
Android
Set EchoConfigKeys.RESET_DATA_ON_USER_STATE_CHANGE
to true
in the config HashMap
passed to the Echo constructor.
iOS (Swift)
Set config[.resetDataOnUserStateChange]
to "true"
in the config Dictionary
passed to the Echo constructor.
Local Storage
To enable IDv5 functionality, Echo stores some data on the device’s local storage.
- Android - Echo uses its own
SharedPreferences
store. - iOS - Echo uses
NSUserDefaults
. All keys used by the library are prefixed withEcho
.
Here’s a description of what data Echo stores locally:
Key | Example Value | Description |
---|---|---|
EchoDeviceID | 2fcc7a0e-89c6-47d7-b672-811e9a4f8064 | The device ID that Echo uses for reporting |
EchoHashedID | f0ff23827982af083f1f160cfd0b791f | The hashed ID of the last user provided to Echo |
EchoDeviceIDCreationDate | 1483971631859 | A unix timestamp representing the time the user’s token was last refreshed |
EchoSignedIn | true | Signed in state of the last user provided to Echo |
EchoHardwareID | 8af8770a27cfd184 | Hardware identifier used by Echo (never transmitted) |
Device ID
Echo uses an auto-generated device ID for reporting. Echo uses an RFC 4122 v4 compliant UUID as a device ID, e.g. 2fcc7a0e-89c6-47d7-b672-811e9a4f8064
. The device ID is reported as idclient
to ATI.
A new device ID is generated each time there is a change in the state of the user. The possible states are detailed in the table above.
Device ID reset
The device ID will be reset when a user without a hashed ID (ie under 13 or personalisation disabled) signs in, signs out or toggles EP.
Initial State | New State | Reset ID | Example |
---|---|---|---|
Signed Out | Signed in with HID | No | Register, VSI, MSI |
Signed Out | Signed in without HID | Yes | Sign in u13, sign in with EP=OFF |
Signed In with HID | Signed out | Yes | Sign out with EP=ON (this is to force a new ATI visit) |
Signed In with HID | Signed In without HID | Yes | Toggle EP to OFF |
Signed In without HID | Signed out | Yes | Sign out u13, Sign out with EP=OFF |
Signed In without HID | Signed In with HID | Yes | Toggle EP to ON |
Echo will send one of two events to ATI in relation to user state changes and the generation of new device ID values:
User state change
This event is sent whenever there is a user state change. In some cases a new device ID will be generated.
Property | Values |
---|---|
action_type | user_state_change |
action_name | sign_in, sign_out, enable_personalisation, disable_personalisation |
The device_id_reset property is only sent when a new device ID is generated.
Echo device ID
Sent when Echo generates a device ID due to a first install or Echo update (e.g. not due to a user state change).
Property | Values |
---|---|
action_type | echo_device_id |
action_name | first_install, echo_upgrade, hardware_id_changed, device_id_expired |
The action_name=echo_upgrade event is only sent when an application upgrades from a pre-IDv5 version of Echo to an IDv5 version i.e. change from Echo with IDV5_ENABLED=false to Echo with IDV5_ENABLED=true. A general Echo upgrade where IDV5_ENABLED=true for both versions will not trigger the event.
The device_id_reset property is only sent when a new device ID is generated.
iOS device ID reset when using ad-hoc distribution (e.g. hockey app)
Echo uses the iOS identifier for vendor (IDFV) to determine if an app is being used on a new hardware device. A change to the IDFV value:
- will result in a new device ID being generated
- will result in Echo sending an event with: action_type=echo_device_id, action_name=hardware_id_changed, device_id_reset=1
Where an app update is installed using ad-hoc distribution Echo will receive a new value when reading the IDFV value, this will trigger a device ID reset. This includes installation using hockey app. This will not happen in production where an app update is installed using an app store distribution as the IDFV value will not change.