Using Private Attributes
Evaluating feature gates, dynamic configs, segments, and experiments without logging user data to Statsig
We take privacy, and the privacy of your user data, very seriously. If you have legal requirements that prevent you from sending PII to third parties, or you are just uncomfortable sending PII to a third party service, it is still possible to use Statsig for feature gating, configs, or experiments.
How It Works
Any field you wish to evaluate on can be made private. Note that if you make the userID field private, your experience in the Statsig console will be broken (the user's tab, metrics charts, event logs, and pulse metrics will be unable to populate accurately). If you wish to hide the UserID, we recommend you use a stable, one-way hash to maintain the ability to analyze user behavior.
For example, let's say you want to use an email condition:
- Create a feature gate with a condition that passes on certain emails or domains
- Pass
email: email@domain.com
inprivateAttributes
rather than in the top levelemail
field - Test it out in the
Test Gate
console after saving changes
When evaluating rules and conditions, Statsig first checks for fields at the top level, then in the custom attributes, and finally, in the private attributes. By simply not passing email at the top level, the evaluator will keep looking in other possible places before evaluating the condition (custom
, and then privateAttributes
).
So if you want to keep the ip address and user agent private, but still use browser or IP checks in the console, simply put them in the privateAttributes
dictionary instead of at the top level of the user. The same goes for country, locale, custom fields, and so on.
Our statsig-node SDK illustrates how this works (and is exactly how we evaluate gates on our servers as well): https://github.com/statsig-io/node-js-server-sdk/blob/d1cb9431fb68b40f840254fce70363de1dc51aa5/src/Evaluator.js#L374
Do not provide a privateAttribute
key anywhere else in the user
object. The entire privateAttributes
dictionary is dropped, but any duplicate fields at the top level or in the custom object will still be logged (and evaluated against)
Client vs Server SDKs
Client/single user environment SDKs send the user object with the initialize
call to evaluate the user against every gate in your Statsig project.
privateAttributes will be sent with this call but will not be stored or logged on Statsig servers. In order to evaluate the conditions and rules for a gate, config, or experiment, Statsig servers need to know the privateAttributes field. It will be stripped from the users for any logging on Statsig servers.
Client SDKs will remove privateAttributes before any events are logged - they are only needed for gate evaluation.
Example with the @statsig/js-client
SDK: https://github.com/statsig-io/js-client-monorepo/blob/17fb70f1bea00d07e156cf6ff03b8024bbc1b197/packages/client-core/src/EventLogger.ts#L325
If this does not meet your needs, our Server SDKs are able to make a stronger guarantee - privateAttributes
will never leave your server. Statsig server SDKs
download the definition of each gate/config/experiment and evaluate them locally.
privateAttributes
stripped from event logs with the statsig-node
SDK: https://github.com/statsig-io/node-js-server-sdk/blob/d1cb9431fb68b40f840254fce70363de1dc51aa5/src/LogEvent.js#L21
Evaluation happening locally to the server on privateAttributes
in the statsig-node
SDK: https://github.com/statsig-io/node-js-server-sdk/blob/d1cb9431fb68b40f840254fce70363de1dc51aa5/src/Evaluator.js#L374
Don't just take our word for it - all of our SDKs are open source and available on github. Feel free to dive in to the implementation of privateAttributes
in the SDK you are using, or reach out to us on slack and we can point you in the right direction.
To ensure that user PII is never transmitted over the network back to Statsig during Client SDK initialization, you should use Client Boostrapping and provide the privateAttributes
as part of the user object on the server to the getClientInitializeResponse(<user object>)
call. This will generate all of the assignments locally on your server, and these assignments can then be passed as initializeValues
to the client SDK, negating the need to send any user attributes from the client device to Statsig.
Event Logging
The privateAttributes field will be stripped from the user object for any logEvent
calls on client or server SDKs. On server SDKs, you can simply not provide that field for logEvent
calls if you wish - no evaluation is happening, so they are not necessary. If you are using the same user everywhere, the SDK will handle dropping the privateAttributes
for you.