{
"path": "/3ma5ozmwfns2l",
"site": "at://did:plc:2cxgdrgtsmrbqnjkwyplmp43/site.standard.publication/3lxsr74rnk22h",
"tags": [
"atproto",
"Bluesky",
"private set intersection"
],
"$type": "site.standard.document",
"title": "Bluesky's Find Friends Contact Import",
"content": {
"$type": "pub.leaflet.content",
"pages": [
{
"id": "019b2a2c-6295-7771-b38b-6ffd835b7ff1",
"$type": "pub.leaflet.pages.linearDocument",
"blocks": [
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "The Bluesky team added a privacy preserving, opt in \"find friends\" feature that imports your contacts."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "There was an initial \"Request for Comments\" (RFC) on the technical, privacy preserving options of this design."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"src": "https://docs.bsky.app/blog/contact-import-rfc",
"$type": "pub.leaflet.blocks.website",
"title": "Request For Comments: A secure contact import scheme for social networks | Bluesky",
"description": "This article outlines plans for a future Bluesky feature \\- it doesn’t exist yet\\! By sharing our ideas early, we hope to solicit feedback from the community.",
"previewImage": {
"$type": "blob",
"ref": {
"$link": "bafkreibqfeqfynscevbgr7bcfvhor5txe2wce7nbusgx6v4a7onvtn2wea"
},
"mimeType": "image/png",
"size": 41364
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "The feature is available in the native mobile apps only, I believe, because of how this has to be done securely."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "I've pasted in screenshots of the flow below on iOS. If anyone has Android screenshots, please share."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "You may see this \"new feature pop-up\" advertising it when you get the updated app:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.image",
"image": {
"$type": "blob",
"ref": {
"$link": "bafkreiask6fbp7za3jxzv2lpes75hwhg66tnsljq22rk4fjndndg2ptkne"
},
"mimeType": "image/jpeg",
"size": 156379
},
"aspectRatio": {
"width": 1206,
"height": 1426
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "This leads you to first verify your phone number."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"alt": "Screenshot\n\nWe need to verify your number before we can look for your friends. A verification code will be sent to this number.\n\n(Phone number input)\n\nHow we use your number:\n• Sent to our phone number verification provider Plivo\n• Deleted by Plivo after verification\n• Held by Bluesky for 7 days to prevent abuse, then deleted\n• Stored as part of a secure code for matching with others\nBy continuing, you consent to this use. You may change your mind any time by visiting settings. (link: Learn more)",
"$type": "pub.leaflet.blocks.image",
"image": {
"$type": "blob",
"ref": {
"$link": "bafkreierbjt6yt6rrudp4awx2dfazekfartsx6dp4tpr2kcor7urikdyty"
},
"mimeType": "image/jpeg",
"size": 206493
},
"aspectRatio": {
"width": 1206,
"height": 1398
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "You'll get a text message you need to paste into a verification screen, and then it will move on with some more information."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"alt": "Screenshot: Share your contacts to find friends.\n\nSee next text block for rest of text.",
"$type": "pub.leaflet.blocks.image",
"image": {
"$type": "blob",
"ref": {
"$link": "bafkreigrdhubh6pyzaiick4u4nzyyytwn4qmak73gt6qdns44idvkv2wqi"
},
"mimeType": "image/jpeg",
"size": 294689
},
"aspectRatio": {
"width": 1206,
"height": 2436
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "I'll include the text from the screenshot here, Bluesky is trying hard to explain this technical, privacy preserving technique."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Bluesky helps friends find each other by creating an encoded digital fingerprint, called a \"hash\", and then looking for matching hashes."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "We never keep plain phone numbers"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "We delete hashes after matches are made"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "We only suggest follows if both people consent"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "You can always opt out and delete your data"
},
"children": []
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "We apply the highest privacy standards, and never share or sell your contact information."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "(the next text is at the bottom of the screen above a button that says \"Find my friends\" or \"Cancel\")"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "I consent to Bluesky using my contacts for mutual friend discovery and to retain hashed data for matching until l opt out."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "This next part is the iOS contact picker. It prompts to either share some contacts or all. I've cropped this screen to just the bottom messaging."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.image",
"image": {
"$type": "blob",
"ref": {
"$link": "bafkreia2jbwls44vpgik3kthlxe6vdhkj4vftmfxsik27ipjfjnkgb4aqu"
},
"mimeType": "image/jpeg",
"size": 156871
},
"aspectRatio": {
"width": 1206,
"height": 1121
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Once imported, it shows a scrollable list of all the contacts, with an invite button next to them."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.image",
"image": {
"$type": "blob",
"ref": {
"$link": "bafkreibwfg52gqigxui7vwfr5ngbbf7te6jaeormmdknnm3f6ptgtqwwcq"
},
"mimeType": "image/jpeg",
"size": 139180
},
"aspectRatio": {
"width": 1206,
"height": 2079
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Oh look, I found myself! OK great, I can test this."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.image",
"image": {
"$type": "blob",
"ref": {
"$link": "bafkreighjvpn7em4gj7drmhp7q4ukvkhwjcij666u4i3uyjoa2p4xll2uy"
},
"mimeType": "image/jpeg",
"size": 80507
},
"aspectRatio": {
"width": 1206,
"height": 1219
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Hitting invite opens a new text message:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.image",
"image": {
"$type": "blob",
"ref": {
"$link": "bafkreiglxod3fg5mz5wz2tk5sxwp4whkt2mn7hvmgj7cwjlquq2futhowu"
},
"mimeType": "image/jpeg",
"size": 91594
},
"aspectRatio": {
"width": 1206,
"height": 1389
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 36,
"byteStart": 28
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 79,
"byteStart": 54
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "It says: \"I'm on Bluesky as bmann.ca - come find me! https://bsky.app/download\""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "I did send it, and found that this probably needs some improvement."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.image",
"image": {
"$type": "blob",
"ref": {
"$link": "bafkreic3cev2ga7rkerngk6pybwko4ika7ll34tlpfqam25cajbyrs6cey"
},
"mimeType": "image/jpeg",
"size": 125421
},
"aspectRatio": {
"width": 1206,
"height": 1107
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 25,
"byteStart": 17
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "You can see that bmann.ca is now highlighted, and iOS Messages turns it into a clickable http link.... which doesn't go to my bsky profile, but instead to my out of date landing page:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"src": "https://bmann.ca",
"$type": "pub.leaflet.blocks.website",
"title": "@bmann.ca • Boris Mann",
"description": "A profile page and links to other places online of Boris Mann",
"previewImage": {
"$type": "blob",
"ref": {
"$link": "bafkreid6blwalio5lukizxkluhqrti73p663qlyct4a5er3m6d5tjeisgy"
},
"mimeType": "image/png",
"size": 20016
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 66,
"byteStart": 41
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "I shared this with Alex, suggesting that bsky.app/profile/bmann.ca would be a better link to include."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.bskyPost",
"postRef": {
"cid": "bafyreibovqehhlotn2wftwisiytq42flj2wd2cmagyh6td5piz2jiej6me",
"uri": "at://did:plc:2cxgdrgtsmrbqnjkwyplmp43/app.bsky.feed.post/3ma5kibebkk25"
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Along with another request for Bluesky app user docs so I don't have to do screenshot essays 😜"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 73,
"byteStart": 49
},
"features": [
{
"uri": "https://docs.bsky.app/blog/contact-import-rfc",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "This is a technically sound implementation, I'll re-link the Dev Blog RFC for those that want to dive into the details. "
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 130,
"byteStart": 113
},
"features": [
{
"did": "did:plc:6ynekzrjhn3r24y5oqhfsp43",
"$type": "pub.leaflet.richtext.facet#didMention"
}
]
}
],
"plaintext": "I have had several other discussions around private set intersection like this for related use cases today. Ping @kobi.bsky.social if you have some other thoughts on this. "
}
}
]
}
]
},
"bskyPostRef": {
"cid": "bafyreibr7667evjs7iqnpxc3wbgp7aqopdzcak6r4y7j64zbngu2ps5tkm",
"uri": "at://did:plc:2cxgdrgtsmrbqnjkwyplmp43/app.bsky.feed.post/3ma5oztdads2l",
"commit": {
"cid": "bafyreiagi6mjn4wgkv4qqgzj3w32wjjthsup4a65asf2zscj6f3cfj2ghe",
"rev": "3ma5oztfq5x2t"
},
"validationStatus": "valid"
},
"description": "Screenshot step-by-step on iOS",
"publishedAt": "2025-12-17T03:14:48.250Z"
}