diff --git a/src/components/LoggedOutCTA.tsx b/src/components/LoggedOutCTA.tsx
new file mode 100644
index 0000000000..7ec8c2264d
--- /dev/null
+++ b/src/components/LoggedOutCTA.tsx
@@ -0,0 +1,80 @@
+import {View, type ViewStyle} from 'react-native'
+import {Trans} from '@lingui/macro'
+
+import {type Gate} from '#/lib/statsig/gates'
+import {useGate} from '#/lib/statsig/statsig'
+import {isWeb} from '#/platform/detection'
+import {useSession} from '#/state/session'
+import {useLoggedOutViewControls} from '#/state/shell/logged-out'
+import {Logo} from '#/view/icons/Logo'
+import {atoms as a, useTheme} from '#/alf'
+import {Button, ButtonText} from '#/components/Button'
+import {Text} from '#/components/Typography'
+
+interface LoggedOutCTAProps {
+ style?: ViewStyle
+ gateName: Gate
+}
+
+export function LoggedOutCTA({style, gateName}: LoggedOutCTAProps) {
+ const {hasSession} = useSession()
+ const {requestSwitchToAccount} = useLoggedOutViewControls()
+ const gate = useGate()
+ const t = useTheme()
+
+ // Only show for logged-out users on web
+ if (hasSession || !isWeb) {
+ return null
+ }
+
+ // Check gate at the last possible moment to avoid counting users as exposed when they won't see the element
+ if (!gate(gateName)) {
+ return null
+ }
+
+ return (
+
+
+
+
+
+
+ Join Bluesky
+
+
+ The open social network.
+
+
+
+
+
+
+ )
+}
diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts
index 66134a4629..f5a613b2ca 100644
--- a/src/lib/statsig/gates.ts
+++ b/src/lib/statsig/gates.ts
@@ -1,6 +1,8 @@
export type Gate =
// Keep this alphabetic please.
| 'alt_share_icon'
+ | 'cta_above_post_heading'
+ | 'cta_above_post_replies'
| 'debug_show_feedcontext'
| 'debug_subscriptions'
| 'disable_onboarding_policy_update_notice'
diff --git a/src/screens/PostThread/components/ThreadItemAnchor.tsx b/src/screens/PostThread/components/ThreadItemAnchor.tsx
index 39e84d383a..ceae5ad5f4 100644
--- a/src/screens/PostThread/components/ThreadItemAnchor.tsx
+++ b/src/screens/PostThread/components/ThreadItemAnchor.tsx
@@ -40,12 +40,13 @@ import {
OUTER_SPACE,
REPLY_LINE_WIDTH,
} from '#/screens/PostThread/const'
-import {atoms as a, useTheme} from '#/alf'
+import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {colors} from '#/components/Admonition'
import {Button} from '#/components/Button'
import {CalendarClock_Stroke2_Corner0_Rounded as CalendarClockIcon} from '#/components/icons/CalendarClock'
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
import {InlineLinkText, Link} from '#/components/Link'
+import {LoggedOutCTA} from '#/components/LoggedOutCTA'
import {ContentHider} from '#/components/moderation/ContentHider'
import {LabelsOnMyPost} from '#/components/moderation/LabelsOnMe'
import {PostAlerts} from '#/components/moderation/PostAlerts'
@@ -178,6 +179,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
const {_, i18n} = useLingui()
const {openComposer} = useOpenComposer()
const {currentAccount, hasSession} = useSession()
+ const {gtTablet} = useBreakpoints()
const feedFeedback = useFeedFeedback(postSource?.feed, hasSession)
const post = postShadow
@@ -310,6 +312,8 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
},
isRoot && [a.pt_lg],
]}>
+ {/* Show CTA for logged-out visitors - hide on desktop and check gate */}
+ {!gtTablet && }
+ {/* Show CTA for logged-out visitors */}
+
)
} else {