Vibes DIY
Vibes DIY / Docs
creator docs · concepts · privacy

Privacy: what a follow actually shares

Two systems get tangled together all the time, and keeping them apart is the whole design:

  1. The follow graph decides who follows whom. It is platform-wide and works the same in every app.
  2. Per-app visibility decides what a follow actually yields inside one app.

Nothing an app declares ever changes whether a follow happens — only what it shows. A private diary app can't stop you from following someone; it only decides whether following you shows that person anything from that app.

1 · The follow edge is platform-level

Follows live on the platform graph, keyed by handle. The only gate on how an edge forms is the target's own handle privacy setting (Settings → Social): a public handle is followed instantly, a private one turns the follow into a request to approve or decline. Your app's privacy posture is never consulted here.

@alice taps Follow in any app, or in the Vibes chrome Is @bob’s handle set to private? no (default) yes Edge: active alice now follows bob Edge: requested bob approves or removes
Handle privacy is per handle, not per account: someone with two handles sets each one separately, so making one private leaves the others publicly followable. Apps can offer Follow, Unfollow, Approve, Remove-follower and Block buttons through useSocial() — but every action runs as the signed-in person, on their own edges, never on someone else’s. Blocks outrank all of this: if either person has blocked the other, the edge doesn’t form at all — the question in the middle is never reached.

2 · What a follower sees: the visibility resolution

An app has to label something as follower-visible before a follower can see anything at all — most of what happens in most apps is never labeled that way. (In code, that's an access function returning an audience — see The Access Model.)

This section answers the follower question: what one person following another yields inside an app. Anonymous visitors and other non-follower readers reach your data by a different path — the app's publish setting and its own sharing rules — covered in § 4.

Once a document is labeled, whether follower F actually receives subject S's data in app X resolves per (subject, app), in this order — first match wins:

Does a follower receive S’s follower-labeled docs in app X? Has S made an explicit per-app choice here? setVisibility chose sharing Shared with followers chose private Not delivered no choice yet Is app X marked privacy-sensitive? yes Off until S says yes to a fresh consent prompt no Does S’s handle-wide setting pin a level? Settings → Social pins one That setting applies e.g. private → not delivered doesn’t Platform default: shared with followers
The load-bearing nuance: in an ordinary app, follower-labeled data is shared with followers with no separate consent step — unless the person’s handle-wide setting says otherwise. That is what makes a shared list or a group picker work the moment someone opens it. Marking an app privacy-sensitive is what flips it to consent-first: sharing never turns itself on there, and neither the platform default nor a sharier handle-wide setting reaches past that carve-out. Only a fresh, explicit yes from the subject, in that app, does.

Note the order of the last two steps: the sensitivity carve-out is checked before the handle-wide setting, so a blanket "share with my followers" preference can never switch on a privacy-sensitive app. In the other direction it does reach: a handle-wide private setting turns follower sharing off across every ordinary app that has no per-app choice of its own.

A private handle is a third, separate thing again: it doesn't change what an existing follower sees, it stops new followers arriving at all until the request is approved.

3 · Who sets what: four layers, later wins

Codegen declares privacy-sensitive at creation when an app's core purpose is private-by-nature record-keeping — diaries, journals, health, mood, finance. You get this for free; the classifier is eval-gated, so a creator doesn't have to remember. It is one of three natures the builder picks: asks first (privacy-sensitive), shared with chosen people (the usual default), and open to everyone — fun, low-stakes apps like a meme wall or a bingo card, where what people make shows up for anyone with the link from the start. The owner can change it in the app's settings.

The owner can mark their own app privacy-sensitive in its settings, and can switch it back. The mark binds to people, not just to the app: everyone who opens the app while it asks first is remembered as having joined under that promise, and keeps being asked first after a switch back — their sharing stays off until they say yes, and they can't be moved to "Anyone" without choosing it. Switching back changes the default only for people who join afterwards. Marking it again protects everyone at once. A person sees the app under Settings → Social as "joined while this app asked first", with the usual reset. The app's publish setting is separate and stays as it is. An app that was marked before per-person consent existed is switched back by the Vibes team, after a look at the app — write to [email protected] — because the people who opened it back then were never recorded one by one.

The user always holds the final switch, at two ranges. A per-app choice (setVisibility) is the sharpest: it beats every layer above it, so if someone turns sharing on for one app that stands even where the app is privacy-sensitive, and if they turn it off nothing the app or its creator does turns it back on. Their handle-wide privacy setting (Settings → Social) is the standing intent behind it — it decides every ordinary app where they haven't made a per-app choice, and setting it to private is the one-switch way to stop follower sharing everywhere at once. The one thing it can't do is loosen a privacy-sensitive app.

The baseline, when none of the layers above has said anything, is shared-with-followers: in an ordinary app a brand-new person's follower-labeled docs flow to their followers — unless their handle-wide setting pins something else. There's no hidden provisioning-time default hiding underneath.

A wider Anyone rung sits above Followers, reaching everyone including signed-out visitors; § 4 covers it and why an app that asks first tops out at Followers.

4 · Beyond followers: who else can see what

Everything above is about one relationship: a person, their followers, one app. Everyone else — people who don't follow you, and visitors who aren't signed in at all — reaches an app's data by a different path. Three things decide that path: the app's nature, its publish setting, and the app's own sharing rules (its access function).

The nature: where an app starts

Every app has one of three natures. The builder picks one when it makes the app, and the owner can change it in the app's settings under How this app shares. The labels and their one-line descriptions, as the settings show them:

  • Open to everyone — "Fun and low-stakes — what people make shows up for anyone with the link, the moment they make it." The builder writes sharing rules that put what people make on an always-on public channel from the very first version, with no publish step, so signed-out visitors see it too.
  • Shared with chosen people — "People share with their followers and the friends and groups they pick. The usual default." This is § 2 at work.
  • Asks first — "Personal records — a diary, health, money. Followers see someone's data only after that person says yes, here." This is the privacy-sensitive mark from § 3.

The nature is a starting point. Moving between Open to everyone and Shared with chosen people steers the builder: it sets what the app's next sharing-rules build aims for. Both publish the same way, and the rules the app runs today keep running until you ask for a rebuild in the chat. Asks first is the one that reaches further: it is live the moment you choose it, because each person's yes is checked every time their data is read, and it changes how the app publishes (below). Ending it works the way § 3 describes.

The publish setting: who can open the app

Separately from its nature, a published app has a publish setting. You choose it on the Share tab under Who can open it: Anyone with the link or People you approve. Underneath, the platform keeps one of three settings:

Setting Who can open and read the app Who can write What the sharing panel says
Open Anyone, signed in or not Anyone signed in "Reachable by anyone; documents governed by your app's rules."
Gated Anyone, signed in or not The people you approve "Anyone can open it; the people you approve can write."
Private The people you approve The people you approve "Opens for the people you approve."

People you approve is Private. Anyone with the link is Open for an app that is Open to everyone or Shared with chosen people alike, and Gated for an app that asks first: strangers can look in, and writing takes your yes. That's the one place asking first shapes what strangers can do. You can always choose a tighter setting yourself, and the publish setting is stored on its own — switching an app out of asks first later leaves a Gated app Gated until you change it.

Opening an app is reaching the door, not reading every record behind it. Inside, the app's sharing rules still decide each record: something on a public channel is readable by everyone who can open the app, and something on a person's own channel stays theirs. On an Open app, someone who asks to join is welcomed in as an editor, and what an editor can do is again whatever the app's rules allow. Signed-out visitors read shared data live and keep what they write on their own device until they sign in.

An app opens to everyone only once it has sharing rules of its own. A new app's first publish is for the people you approve; when its sharing rules are in place it opens up by itself — unless you chose People you approve yourself, or the app asks first, in which case you open it when you're ready. Pick Anyone with the link on an app that has no rules yet and the builder is asked to write them first; the app opens on the first version that has them.

The "Anyone" rung

Each person's own reach in one app has three rungs: Anyone, Followers and Off. Anyone takes everything the app labels for that person's followers and shows it to everyone, signed-out visitors included. An app offers it through its own sharing control (in code, setVisibility("public")); your handle-wide setting in Settings → Social offers Followers can see or Never share.

On an app that asks first, the top rung is Followers. A request for Anyone there settles quietly as no change — no error, nothing to dismiss — and an Anyone chosen before the app started asking first is read as Followers. People who joined while an app asked first keep that cap after the owner switches it back, until they make a choice of their own.

Images follow their record

A generated image is visible to the people who can read the record it belongs to, plus whoever generated it. A journal entry's illustration is as private as the entry; a picture on a public wall is there for everyone who visits the wall. An app with no sharing rules of its own is readable by everyone who can open it, and so are its images. Images made in private apps before this rule are brought in line on the app's next push or publish, checked as the person who generated each one. An image whose generator's account no longer has a handle can't be checked that way, so it keeps the visibility it had before; each later push or publish tries it again.

Where each thing is set

  • The app's nature — the app's settings, How this app shares.
  • Who can open the app — the Share tab, under Share settings.
  • Your reach in one app — the app's own sharing control, and Settings → Social → Per-app decisions, where each app you've decided about (or joined while it asked first) has a Revoke or Reset.
  • Your standing default — Settings → Social → When an app asks.

Some of these take effect right away: choosing Asks first, changing Who can open it, and a per-app choice or Revoke in Settings → Social. From that moment people outside the new reach stop receiving new data. A switch between Open to everyone and Shared with chosen people waits for the next sharing-rules build, so the app shares the way it does today until you ask for that rebuild in the chat. Either way, copies already synced to someone's device stay there — § 6 has the copy rules.

5 · The sharing UX for a privacy-sensitive app

When your app is sensitive — a workout log, a journal — the recommended sharing surface is two controls, mapping to the two mechanisms above. Don't invent a third.

Two controls, two mechanisms: a switch over a list the platform owns, and a list your app owns.
  • The "Shared with followers" checkbox is the subject arm, and it's a two-way switch. Checking it is the fresh consent (requestFollowersAccess()); unchecking it must call the off verb (setVisibility("private")). One verb for both edges is an enable-only button, and that breaks the "stops receiving" promise. In a sensitive app it starts unchecked — that's the platform default doing its job, not your app being unfriendly.
  • Make "followers" a preview, not just a word. Tapping it shows the person's actual platform-wide follower list. That's the point of the affordance: people should see this is an already-established, app-independent list — which is exactly why the box isn't pre-checked. Consent is only informed if you can see who you're consenting to.
  • "Add workout buddies" is the grants lane, not the follow graph: picking individual people grants those named handles access through your access function. It's the right shape for "these three people", works whether or not they follow you, and never flips the followers checkbox.
  • Keep the two visually distinct. One is a switch over a list the platform owns; the other builds a list your app owns. Blurring them is how people end up sharing a workout log with an audience they didn't picture.

6 · Rules your app copy must respect

Vibes DIY is local-first: the server routes future delivery, but data already synced lives on people's devices. Honest copy follows from that.

Say "followers can see" — never "friends". Sharing is one-directional per edge: unfollowing stops you receiving their data; removing a follower or blocking is what cuts the other direction.

Say carefully: turning sharing off, removing a follower, or blocking means they stop receiving your data from now on. Future changes stop reaching them — though a session someone already has open may keep receiving until it reconnects, so don't write copy that promises the tap closes on the same instant. Say exactly what holds: from here on, they stop receiving.

Never say "they can no longer see it", or "your data is deleted from their view". Copies already synced to someone's device stay on that device. Don't promise remote erase — the platform can't do it and your copy shouldn't imply it. The honest promise is "stops receiving", not "unsees".

So the moment to think carefully is before sharing something you'd want back — which is exactly why privacy-sensitive apps ask for sharing rather than starting it for you.

One more copy consequence: blocked or rejected writes are quiet. If a write turns out not to be allowed — access was removed, or the app's rules don't permit it — nothing explodes. The app quietly settles back to the version the server holds. There's no error to dismiss and no rejected copy left behind, so don't write UI copy promising one.

7 · What this means when you build

  • Don't gate follows in your app. The edge is platform state; per-app posture only shapes what the follow yields. Building your own request-to-follow layer fights the platform.
  • If your app handles intimate data, make sure it's marked sensitive. Codegen usually declares it at creation, and the owner can raise it in settings. In a sensitive app, ask for sharing with an explicit useSocial().requestFollowersAccess()-style consent — it will never turn on by itself.
  • If your app is ordinary, don't promise consent you don't gate. Follower-labeled docs are follower-visible by default, unless the person's handle-wide setting says otherwise. If your UX implies "nothing is shared until you opt in", either mark the app sensitive or fix the copy.
  • Don't read the default as "always on" either. Someone whose handle-wide setting is private shares nothing from your ordinary app until they make a per-app choice, so a follower seeing nothing is not necessarily a bug in your labeling.
  • Never gate anonymous-write UI on can.create(), and remember that anonymous visitors read shared data live but write device-local until they sign in.

See also