⏱️ Lectura: 10 min
When you take a screenshot of a post on Bluesky, the butterfly that is the Bluesky logo appears in the top right corner. But if you look at that same screen inside the app, that space is occupied by the Follow button. No one warns you: the change happens at the exact instant the system generates the image.
📑 En este artículo
The finding was published on August 16, 2026 by a developer who goes by mt, in a post on his personal blog, after noticing that the butterfly never bothered him inside the app but appeared in every screenshot he saved. The explanation was in Bluesky’s open source code: a file called GrowthHack.tsx that repurposes an iOS feature originally meant to hide passwords.
TL;DR
- Bluesky’s iOS app replaces the Follow button with the Bluesky logo when it detects a screenshot.
- The mechanism lives in GrowthHack.tsx, added in January 2026 by developer mozzius.
- The expo-privacy-sensitive library creates a UITextField with isSecureTextEntry and draws the button inside its layer.
- iOS clears the layer of a secure text field when capturing a screenshot, revealing the logo that was behind it.
- The trick doesn’t work when switching apps: iOS captures that preview without triggering the secure field’s clearing.
- On Android and web, expo-privacy-sensitive renders the normal content, without hiding anything.
- Telegram and Signal use the same secure UITextField mechanism to protect secret chats from screenshots.
- The thread where the team discussed the change got locked after community criticism.
What happened with the Bluesky logo in screenshots
mt ran a simple test: he captured a post he liked to forward it to a group of friends. In the final image, the Bluesky logo appeared where a Follow button had been before. He reopened the app and there, on the actual screen, the button was still there: never the logo.
His first hypothesis was that the app detected the screenshot key combination and changed the view before the system took the picture. mt tried something else: swiping up to switch apps mid-gesture, without completing the screenshot. In that case, the preview iOS generates did show the Follow button, not the logo.
That difference was the key clue. If the change depended on a key combination, it should look the same in both cases. Since it didn’t, the mechanism had to depend on a function of the operating system itself, not app code reacting to a gesture.
Context and history: an old trick with a new use
iOS has included, for over a decade, a protection meant for password fields: if you mark a UITextField with the isSecureTextEntry property set to true, the system automatically hides its content when it detects a screenshot or when it generates the app switcher thumbnail. That’s the same reason your password never shows up in the multitasking preview.
Encrypted messaging apps have been reusing that same protection for years, for all kinds of content, not just passwords. Telegram applies it in its secret chats, and Signal does something equivalent to shield an entire conversation’s content from unauthorized screenshots. In both cases the logic is defensive: hide sensitive information.
Bluesky turned that logic around in January 2026. The developer who goes by mozzius added the GrowthHack.tsx file to the app, built on a proprietary library called expo-privacy-sensitive. The goal was no longer to hide something sensitive, but to show something: the Bluesky logo, which up to that point had been covered by the Follow button on every profile.
This kind of decision falls under what the industry calls growth hacking: small product changes, often invisible to the end user, designed to increase a brand’s organic exposure without spending on advertising. The file’s own name, GrowthHack.tsx, makes that explicit.
💭 Key point: the Bluesky logo doesn’t appear in the screenshot by magic: it was there the whole time, drawn behind the Follow button, waiting for the system to clear the field covering it.
Technical details: how a password field draws a logo
The expo-privacy-sensitive package doesn’t draw a new icon when it detects a screenshot. It does something more subtle: it creates an invisible UITextField, sets isSecureTextEntry = true on it, and renders the actual content, in this case the Follow button, inside that field’s layer (.layer).
A simplified Swift example of the core idea, without the Expo wrapper, would look like this:
let secureField = UITextField()
secureField.isSecureTextEntry = true
secureField.isUserInteractionEnabled = false
let followButton = UIButton(type: .system)
followButton.setTitle("Follow", for: .normal)
secureField.layer.addSublayer(followButton.layer)
view.addSubview(secureField)
When the user takes a screenshot, iOS automatically clears the layer of any secure UITextField visible at that moment. The Follow button disappears from the resulting image and, since it was drawn on top of the logo, that logo is left exposed.
On the React Native side, using the package is much simpler: you wrap the sensitive component in a wrapper that handles that work underneath.
import { PrivacySensitiveView } from "expo-privacy-sensitive";
export function FollowButtonOverlay() {
return (
<privacysensitiveview>
<followbutton></followbutton>
</privacysensitiveview>
);
}
The question that remains is why the trick doesn’t trigger when switching apps with the swipe gesture. mt offers a reasonable explanation, though he notes he isn’t an iOS developer: the system captures that app switcher preview at the start of the gesture, before a live instance of the UITextField exists to react. The screenshot, on the other hand, does find an active secure field to clear.
Why the multitasking preview fails to trigger it
Put another way: the isSecureTextEntry protection depends on the field existing on screen at the exact moment the system decides to clear it. A screenshot triggers that clearing live. The app switcher snapshot, on the other hand, seems to be generated from an already frozen instant, without that trigger.
sequenceDiagram
participant U as User
participant App as Bluesky App
participant iOS as iOS System
App->>iOS: draws the Follow button inside the layer of a secure UITextField
U->>iOS: takes a screenshot
iOS-->>App: clears the secure field's layer
Note over U,iOS: the Bluesky logo that was behind it becomes visible in the final image
How to try it yourself
mt’s experiment can be repeated with any Bluesky account on an iPhone. Only three steps are needed:
- Open any profile in the official Bluesky app for iOS and locate the Follow button in the top right corner.
- Take a normal screenshot (side button plus volume up, or the equivalent gesture on your model).
- Compare: in the app, the Follow button is still there; in the saved image, the Bluesky logo appears.
If you also want to reproduce the mechanism in your own project, expo-privacy-sensitive can be installed like any npm package inside an Expo project:
# Windows (PowerShell), macOS, and Linux use the same command
npx create-expo-app my-app
cd my-app
npm install expo-privacy-sensitive
Installing the package is identical on Windows, macOS, and Linux because it runs on Node.js. The difference comes up at build time: generating an iOS build requires Xcode, which only runs on macOS, or Expo’s cloud service EAS Build if you’re working from Windows or Linux.
⚠️ Heads up: the effect only shows up in a native iOS build, not in Expo Go or the web preview. You need to compile the actual app for isSecureTextEntry to take effect.
Impact and analysis: somewhere between clever and misuse
The reaction in the internal thread where the Bluesky team discussed adding this behavior was mostly negative, according to mt: several developers flagged it as questionable use of an API meant to protect privacy, not to force brand visibility. The thread ended up locked.
mt himself, however, describes it as endearing rather than abusive: no one loses data, there’s no hidden tracking, and the result is visually clean. The underlying debate is whether reusing a security protection for a growth objective sets an uncomfortable precedent for other apps.
| App or platform | What it hides | When it triggers | Mechanism |
|---|---|---|---|
| Bluesky (iOS) | Follow button, reveals the Bluesky logo | Screenshot | Secure UITextField + layer |
| Telegram (secret chats) | Chat content | Screenshot | Same iOS mechanism |
| Signal | Conversation content | Screenshot | Same iOS mechanism |
| Bluesky (Android/web) | Nothing | Not applicable | expo-privacy-sensitive renders normally |
What’s next
mt writes that he dug a bit further and found the trick has been known in the messaging app ecosystem for a while, so he doesn’t expect Apple to block it soon: blocking isSecureTextEntry would break password protection in thousands of apps, including the system’s own.
Other apps under growth pressure will likely copy the idea to slip their branding into every screenshot a user shares outside the app. It’s a way to gain presence on social media and messaging groups without asking the user for anything.
📖 Summary on Telegram: View summary
Try it yourself: install expo-privacy-sensitive in a new Expo project and compare how your component looks inside the app versus in an actual screenshot.
Frequently Asked Questions
Why does the Follow button disappear in Bluesky screenshots?
Because it’s drawn inside the layer of a UITextField marked as secure. iOS automatically clears that layer every time it detects a screenshot, and the Bluesky logo behind it becomes visible.
Does this trick work on Android or Bluesky’s web version?
No. According to the code analysis, on those platforms expo-privacy-sensitive simply renders the content as-is, with no hiding of any kind.
Is this misuse of an Apple privacy feature?
Depends on who you ask. Within the Bluesky team itself, the majority opinion was critical; the researcher who documented it sees it as a clever use rather than a harmful one, because it doesn’t hide or leak any user data.
What other apps use a similar mechanism?
Telegram applies it in its secret chats, and Signal uses it to protect an entire conversation’s content this way. The difference with Bluesky is the goal: in those cases it’s privacy, in Bluesky’s it’s brand identity.
Can I apply this in my own React Native or Expo app?
Yes, by installing expo-privacy-sensitive and wrapping the component you want hidden in screenshots. The effect only shows up in a native iOS build compiled with Xcode or EAS Build.
Will Apple block this behavior?
There’s no sign of that. The underlying mechanism has spent years underpinning password protection and the encrypted content of Telegram and Signal, so blocking it would carry a high cost for the platform.
References
- timmarinin.net: original post where mt documents and explains the Bluesky logo screenshot mechanism.
- github.com/bluesky-social/social-app: Bluesky app’s open source repository where the GrowthHack.tsx file lives.
- developer.apple.com: Apple’s official documentation on UITextField and the isSecureTextEntry property.
- npmjs.com: page for the expo-privacy-sensitive package used by Bluesky to implement the effect.
📱 Enjoying this content? Follow @programacion on Telegram for daily tech content in Spanish: quick summaries, fresh content every day. @programacion
Imagen destacada: Foto de Tom The Photographer en Unsplash
0 Comments