diff --git a/keyserver/src/fetchers/community-fetchers.js b/keyserver/src/fetchers/community-fetchers.js
--- a/keyserver/src/fetchers/community-fetchers.js
+++ b/keyserver/src/fetchers/community-fetchers.js
@@ -44,4 +44,25 @@
   return communityInfos;
 }
 
-export { fetchCommunityInfos };
+async function checkIfCommunityHasFarcasterChannelTag(
+  viewer: Viewer,
+  communityID: string,
+): Promise<boolean> {
+  if (!viewer.loggedIn) {
+    return false;
+  }
+
+  const query = SQL`
+    SELECT c.farcaster_channel_id as farcasterChannelID
+    FROM communities c
+    WHERE c.id = ${communityID}
+  `;
+
+  const [result] = await dbQuery(query);
+
+  const communityInfo = result[0];
+
+  return !!communityInfo?.farcasterChannelID;
+}
+
+export { fetchCommunityInfos, checkIfCommunityHasFarcasterChannelTag };
diff --git a/keyserver/src/responders/thread-responders.js b/keyserver/src/responders/thread-responders.js
--- a/keyserver/src/responders/thread-responders.js
+++ b/keyserver/src/responders/thread-responders.js
@@ -3,6 +3,7 @@
 import t from 'tcomb';
 import type { TInterface, TUnion } from 'tcomb';
 
+import { threadSubscriptionValidator } from 'lib/types/subscription-types.js';
 import { userSurfacedPermissionValidator } from 'lib/types/thread-permission-types.js';
 import { threadTypes } from 'lib/types/thread-types-enum.js';
 import {
@@ -179,6 +180,7 @@
     threadID: tID,
     calendarQuery: t.maybe(entryQueryInputValidator),
     inviteLinkSecret: t.maybe(t.String),
+    defaultSubscription: t.maybe(threadSubscriptionValidator),
   });
 
 async function threadJoinResponder(
diff --git a/keyserver/src/updaters/thread-updaters.js b/keyserver/src/updaters/thread-updaters.js
--- a/keyserver/src/updaters/thread-updaters.js
+++ b/keyserver/src/updaters/thread-updaters.js
@@ -45,6 +45,7 @@
 import createMessages from '../creators/message-creator.js';
 import { createUpdates } from '../creators/update-creator.js';
 import { dbQuery, SQL } from '../database/database.js';
+import { checkIfCommunityHasFarcasterChannelTag } from '../fetchers/community-fetchers.js';
 import { checkIfInviteLinkIsValid } from '../fetchers/link-fetchers.js';
 import { fetchMessageInfoByID } from '../fetchers/message-fetchers.js';
 import {
@@ -816,16 +817,35 @@
     throw new ServerError('not_logged_in');
   }
 
-  const permissionCheck = request.inviteLinkSecret
-    ? checkIfInviteLinkIsValid(request.inviteLinkSecret, request.threadID)
-    : checkThreadPermission(
-        viewer,
+  const permissionPromise = (async () => {
+    if (request.inviteLinkSecret) {
+      return await checkIfInviteLinkIsValid(
+        request.inviteLinkSecret,
         request.threadID,
-        threadPermissions.JOIN_THREAD,
       );
+    }
+
+    const threadPermissionPromise = checkThreadPermission(
+      viewer,
+      request.threadID,
+      threadPermissions.JOIN_THREAD,
+    );
+
+    const communityFarcasterChannelTagPromise =
+      checkIfCommunityHasFarcasterChannelTag(viewer, request.threadID);
+
+    const [threadPermission, hasCommunityFarcasterChannelTag] =
+      await Promise.all([
+        threadPermissionPromise,
+        communityFarcasterChannelTagPromise,
+      ]);
+
+    return threadPermission || hasCommunityFarcasterChannelTag;
+  })();
+
   const [isMember, hasPermission] = await Promise.all([
     fetchViewerIsMember(viewer, request.threadID),
-    permissionCheck,
+    permissionPromise,
   ]);
   if (!hasPermission) {
     throw new ServerError('invalid_parameters');
@@ -855,7 +875,9 @@
     }
   }
 
-  const changeset = await changeRole(request.threadID, [viewer.userID], null);
+  const changeset = await changeRole(request.threadID, [viewer.userID], null, {
+    defaultSubscription: request.defaultSubscription,
+  });
 
   const membershipResult = await commitMembershipChangeset(viewer, changeset, {
     calendarQuery,
diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js
--- a/lib/shared/thread-utils.js
+++ b/lib/shared/thread-utils.js
@@ -54,6 +54,7 @@
   minimallyEncodeThreadCurrentUserInfo,
 } from '../types/minimally-encoded-thread-permissions-types.js';
 import { userRelationshipStatus } from '../types/relationship-types.js';
+import { defaultThreadSubscription } from '../types/subscription-types.js';
 import {
   threadPermissionPropagationPrefixes,
   threadPermissions,
@@ -429,11 +430,6 @@
   +sourceMessageID?: string,
 };
 
-const defaultSubscription = {
-  pushNotifs: false,
-  home: false,
-};
-
 function createPendingThread({
   viewerID,
   threadType,
@@ -497,7 +493,7 @@
           role: role.id,
           permissions: membershipPermissions,
           isSender: false,
-          subscription: defaultSubscription,
+          subscription: defaultThreadSubscription,
         }),
       ),
       roles: {
@@ -506,7 +502,7 @@
       currentUser: minimallyEncodeThreadCurrentUserInfo({
         role: role.id,
         permissions: membershipPermissions,
-        subscription: defaultSubscription,
+        subscription: defaultThreadSubscription,
         unread: false,
       }),
       repliesCount: 0,
@@ -543,7 +539,7 @@
       currentUser: minimallyEncodeThreadCurrentUserInfo({
         role: role.id,
         permissions: membershipPermissions,
-        subscription: defaultSubscription,
+        subscription: defaultThreadSubscription,
         unread: false,
       }),
       repliesCount: 0,
@@ -805,7 +801,7 @@
     currentUser = {
       role: null,
       permissions: currentUserPermissions,
-      subscription: defaultSubscription,
+      subscription: defaultThreadSubscription,
       unread: null,
     };
   }
diff --git a/lib/types/subscription-types.js b/lib/types/subscription-types.js
--- a/lib/types/subscription-types.js
+++ b/lib/types/subscription-types.js
@@ -5,7 +5,7 @@
 
 import { tShape } from '../utils/validation-utils.js';
 
-export const threadSubscriptions = Object.freeze({
+const threadSubscriptions = Object.freeze({
   home: 'home',
   pushNotifs: 'pushNotifs',
 });
@@ -31,3 +31,10 @@
   threadID: string,
   subscription: ThreadSubscription,
 };
+
+const defaultThreadSubscription: ThreadSubscription = {
+  home: false,
+  pushNotifs: false,
+};
+
+export { defaultThreadSubscription, threadSubscriptions };
diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js
--- a/lib/types/thread-types.js
+++ b/lib/types/thread-types.js
@@ -340,11 +340,13 @@
   +threadID: string,
   +calendarQuery?: ?CalendarQuery,
   +inviteLinkSecret?: string,
+  +defaultSubscription?: ThreadSubscription,
 };
 export type ClientThreadJoinRequest = {
   +threadID: string,
   +calendarQuery: CalendarQuery,
   +inviteLinkSecret?: string,
+  +defaultSubscription?: ThreadSubscription,
 };
 export type ThreadJoinResult = {
   +updatesResult: {
diff --git a/native/components/auto-join-community-handler.react.js b/native/components/auto-join-community-handler.react.js
--- a/native/components/auto-join-community-handler.react.js
+++ b/native/components/auto-join-community-handler.react.js
@@ -14,6 +14,7 @@
 import { farcasterChannelTagBlobHash } from 'lib/shared/community-utils.js';
 import type { AuthMetadata } from 'lib/shared/identity-client-context.js';
 import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
+import { defaultThreadSubscription } from 'lib/types/subscription-types.js';
 import { authoritativeKeyserverID } from 'lib/utils/authoritative-keyserver.js';
 import { getBlobFetchableURL } from 'lib/utils/blob-service.js';
 import { useCurrentUserFID } from 'lib/utils/farcaster-utils.js';
@@ -68,6 +69,7 @@
             { type: 'threads', threadIDs: [communityID] },
           ],
         },
+        defaultSubscription: defaultThreadSubscription,
       });
     },
     [calendarQuery, joinThread],