Working with custom facts
Store and share custom facts on your user's device

Self Core Facts are useful for general purpose, but the process of adding new core facts is slow and not flexible enough to support app custom facts.

Custom facts will allow you to:

  • Create custom facts.
  • Store facts on the user’s device.
  • Consume custom facts.
  • Share custom facts with other apps.
  • Interact with other apps on the Self ecosystem.

All this is basically accomplished by using the user’s device as secure storage for critical information.

Issuing facts


Facts are presented to the user in groups. Groups have name and icon properties.

nameThe name of the group as it will be displayed to the user.true
iconThe icon to be displayed close to the group namefalse

Self App supports all material UI icons, you can search all available icons on google fonts.

This is how we can create a group.

my_group =
    "Trip to Venice", 
g := fact.FactGroup{
	Name: "Trip to Shangai",
	Icon: "airplanemode_active",
let group = new Group("group name", "plane")


Facts are composed of a key, a value and a source.

keyis the id for the fact, it will allow other apps to request your facts by id.true
valueIt’s stored as a string by defaulttrue
sourceit groups facts from the same source, it allows other apps to use it as filters.true
groupif group is not provided facts will end under on the ungrouped section on the user’s devicefalse
typeit defines how the fact has to be processed by other clients, it defaults to string, but can also be set as password or delegation_certificatefalse
my_fact =
    group: my_group)
f := fact.FactToIssue{
		Key:    "BCN-SIN-cc",
		Value:  "CD128763",
		Source: source,
		Group:  &g,
let fact = new FactToIssue("foo", "bar", source, {
  group: group

Issuing facts

Once you have your fact defined, it’s time to send it to your user’s device. You can do this by calling issue method on the facts service.

userthe user you’re signing and sending facts totrue
factsan array with the facts you want to issuetrue
viewersan array of app identifiers related to apps apps that can consume this factsfalse
                 viewers: [appID1, appID2])
client.FactService().Issue(selfid, []fact.FactToIssue{f}, []string{})
await sdk.facts().issue(selfID, [fact])

Retrieving facts

Retrieving facts is pretty much the same as we do for accessing core facts, the only difference is we must specify what issuers are we going to be accepting on our request, let’s see an example.

                       fact: my_fact.key, 
                       issuers: [myAppID] 
                    }]) do |res|
    if res.status == "rejected"
        puts 'Information request rejected'
    k = my_fact.key.to_sym
    a = res.attestation_values_for(k)
    puts "Your stored fact is #{a.first}!"
resp, err := client.FactService().Request(&fact.FactRequest{
	SelfID:      selfid,
	Description: "We need access to your flight confirmation codes to reschedule your flights",
	Facts: []fact.Fact{
			Fact:    f[0].Key,
			Sources: []string{source},
			Issuers: []string{appID},
	Expiry: time.Minute * 5,
let res = await sdk.facts().request(selfID, [{ fact: fact.key, issuers: [ appID ] }])

Scope and facts

Custom facts scope is configurable by the developer by using viewers and issuers parameters to facts.issue and facts.request. This makes it possible to create private, protected and public custom facts.


By specifying yourself as the only viewers on a facts.issue you will be creating facts you’re the only one able to consume.


Specifying multiple app ids as viewers you’ll make those facts available only to a subset of apps.


When viewers parameter is not provided, issued facts become public.