diff --git a/native/chat/inner-text-message.react.js b/native/chat/inner-text-message.react.js
--- a/native/chat/inner-text-message.react.js
+++ b/native/chat/inner-text-message.react.js
@@ -5,6 +5,7 @@
 import { View, StyleSheet, TouchableWithoutFeedback } from 'react-native';
 import Animated from 'react-native-reanimated';
 
+import { messageKey } from 'lib/shared/message-utils';
 import { colorIsDark } from 'lib/shared/thread-utils';
 
 import GestureTouchableOpacity from '../components/gesture-touchable-opacity.react';
@@ -13,6 +14,7 @@
 import { useColors, colors } from '../themes/colors';
 import type { ChatTextMessageInfoItemWithHeight } from '../types/chat-types';
 import { useComposedMessageMaxWidth } from './composed-message-width';
+import { MessageContext } from './message-context.react';
 import { MessageListContext } from './message-list-types';
 import {
   allCorners,
@@ -101,6 +103,16 @@
     return [styles.text, textStyle];
   }, [darkColor]);
 
+  // We use a MessageContext to allow MarkdownLink and MarkdownSpoiler
+  // to access the messageKey so it is 'self-aware'
+  const key = messageKey(item.messageInfo);
+  const messageContextValue = React.useMemo(
+    () => ({
+      messageKey: key,
+    }),
+    [key],
+  );
+
   const message = (
     <TouchableWithoutFeedback>
       <View>
@@ -111,9 +123,11 @@
           style={[styles.message, cornerStyle]}
           animatedStyle={messageStyle}
         >
-          <Markdown style={markdownStyles} rules={rules}>
-            {text}
-          </Markdown>
+          <MessageContext.Provider value={messageContextValue}>
+            <Markdown style={markdownStyles} rules={rules}>
+              {text}
+            </Markdown>
+          </MessageContext.Provider>
         </GestureTouchableOpacity>
       </View>
     </TouchableWithoutFeedback>
diff --git a/native/chat/message-context.react.js b/native/chat/message-context.react.js
new file mode 100644
--- /dev/null
+++ b/native/chat/message-context.react.js
@@ -0,0 +1,15 @@
+// @flow
+
+import * as React from 'react';
+
+export type MessageContextType = {
+  +messageKey: string,
+};
+
+const MessageContext: React.Context<MessageContextType> = React.createContext<MessageContextType>(
+  {
+    messageKey: '',
+  },
+);
+
+export { MessageContext };
diff --git a/native/chat/text-message.react.js b/native/chat/text-message.react.js
--- a/native/chat/text-message.react.js
+++ b/native/chat/text-message.react.js
@@ -46,7 +46,7 @@
   // ChatContext
   +chatContext: ?ChatContextType,
   // MarkdownContext
-  +linkModalActive: boolean,
+  +isLinkModalActive: boolean,
   +linkIsBlockingPresses: boolean,
 };
 class TextMessage extends React.PureComponent<Props> {
@@ -62,7 +62,7 @@
       verticalBounds,
       overlayContext,
       chatContext,
-      linkModalActive,
+      isLinkModalActive,
       linkIsBlockingPresses,
       canCreateSidebarFromMessage,
       ...viewProps
@@ -71,7 +71,7 @@
     let swipeOptions = 'none';
     const canReply = this.canReply();
     const canNavigateToSidebar = this.canNavigateToSidebar();
-    if (linkModalActive) {
+    if (isLinkModalActive) {
       swipeOptions = 'none';
     } else if (canReply && canNavigateToSidebar) {
       swipeOptions = 'both';
@@ -147,6 +147,7 @@
       message,
       props: { verticalBounds, linkIsBlockingPresses },
     } = this;
+
     if (!message || !verticalBounds || linkIsBlockingPresses) {
       return;
     }
@@ -208,33 +209,41 @@
   function ConnectedTextMessage(props: BaseProps) {
     const overlayContext = React.useContext(OverlayContext);
     const chatContext = React.useContext(ChatContext);
+    const markdownContext = React.useContext(MarkdownContext);
+    invariant(markdownContext, 'markdownContext should be set');
+
+    const {
+      linkModalActive,
+      linkPressActive,
+      clearMarkdownContextData,
+    } = markdownContext;
+
+    const key = messageKey(props.item.messageInfo);
+
+    // We check if there is an ID in the respective objects - if not, we
+    // default to false. The likely situation where the former statement
+    // evaluates to null is when the thread is opened for the first time.
+    const linkIsBlockingPresses =
+      (linkModalActive[key] || linkPressActive[key]) ?? false;
+
+    const isLinkModalActive = linkModalActive[key] ?? false;
 
-    const [linkModalActive, setLinkModalActive] = React.useState(false);
-    const [linkPressActive, setLinkPressActive] = React.useState(false);
-    const markdownContext = React.useMemo(
-      () => ({
-        setLinkModalActive,
-        setLinkPressActive,
-      }),
-      [setLinkModalActive, setLinkPressActive],
-    );
     const canCreateSidebarFromMessage = useCanCreateSidebarFromMessage(
       props.item.threadInfo,
       props.item.messageInfo,
     );
 
-    const linkIsBlockingPresses = linkModalActive || linkPressActive;
+    React.useEffect(() => clearMarkdownContextData, [clearMarkdownContextData]);
+
     return (
-      <MarkdownContext.Provider value={markdownContext}>
-        <TextMessage
-          {...props}
-          canCreateSidebarFromMessage={canCreateSidebarFromMessage}
-          overlayContext={overlayContext}
-          chatContext={chatContext}
-          linkModalActive={linkModalActive}
-          linkIsBlockingPresses={linkIsBlockingPresses}
-        />
-      </MarkdownContext.Provider>
+      <TextMessage
+        {...props}
+        canCreateSidebarFromMessage={canCreateSidebarFromMessage}
+        overlayContext={overlayContext}
+        chatContext={chatContext}
+        isLinkModalActive={isLinkModalActive}
+        linkIsBlockingPresses={linkIsBlockingPresses}
+      />
     );
   },
 );
diff --git a/native/markdown/markdown-context-provider.react.js b/native/markdown/markdown-context-provider.react.js
new file mode 100644
--- /dev/null
+++ b/native/markdown/markdown-context-provider.react.js
@@ -0,0 +1,48 @@
+// @flow
+
+import * as React from 'react';
+
+import { MarkdownContext } from './markdown-context.js';
+
+type Props = {
+  +children: React.Node,
+};
+
+function MarkdownContextProvider(props: Props): React.Node {
+  const [linkModalActive, setLinkModalActive] = React.useState<{
+    [key: string]: boolean,
+  }>({});
+  const [linkPressActive, setLinkPressActive] = React.useState<{
+    [key: string]: boolean,
+  }>({});
+
+  const clearMarkdownContextData = React.useCallback(() => {
+    setLinkModalActive({});
+    setLinkPressActive({});
+  }, []);
+
+  const contextValue = React.useMemo(
+    () => ({
+      setLinkModalActive,
+      linkModalActive,
+      setLinkPressActive,
+      linkPressActive,
+      clearMarkdownContextData,
+    }),
+    [
+      setLinkModalActive,
+      linkModalActive,
+      setLinkPressActive,
+      linkPressActive,
+      clearMarkdownContextData,
+    ],
+  );
+
+  return (
+    <MarkdownContext.Provider value={contextValue}>
+      {props.children}
+    </MarkdownContext.Provider>
+  );
+}
+
+export default MarkdownContextProvider;
diff --git a/native/markdown/markdown-context.js b/native/markdown/markdown-context.js
--- a/native/markdown/markdown-context.js
+++ b/native/markdown/markdown-context.js
@@ -2,9 +2,14 @@
 
 import * as React from 'react';
 
+import type { SetState } from 'lib/types/hook-types';
+
 export type MarkdownContextType = {
-  +setLinkModalActive: boolean => void,
-  +setLinkPressActive: boolean => void,
+  +setLinkModalActive: SetState<{ [key: string]: boolean }>,
+  +linkModalActive: { [key: string]: boolean },
+  +setLinkPressActive: SetState<{ [key: string]: boolean }>,
+  +linkPressActive: { [key: string]: boolean },
+  +clearMarkdownContextData: () => void,
 };
 
 const MarkdownContext: React.Context<?MarkdownContextType> = React.createContext<?MarkdownContextType>(
diff --git a/native/markdown/markdown-link.react.js b/native/markdown/markdown-link.react.js
--- a/native/markdown/markdown-link.react.js
+++ b/native/markdown/markdown-link.react.js
@@ -5,16 +5,21 @@
 
 import { normalizeURL } from 'lib/utils/url-utils';
 
+import { MessageContext } from '../chat/message-context.react';
 import { MarkdownContext, type MarkdownContextType } from './markdown-context';
 
 function useDisplayLinkPrompt(
   inputURL: string,
   markdownContext: ?MarkdownContextType,
+  messageKey: string,
 ) {
   const setLinkModalActive = markdownContext?.setLinkModalActive;
+  const linkModalActive = markdownContext?.linkModalActive;
   const onDismiss = React.useCallback(() => {
-    setLinkModalActive?.(false);
-  }, [setLinkModalActive]);
+    if (linkModalActive) {
+      setLinkModalActive?.({ ...linkModalActive, [messageKey]: false });
+    }
+  }, [setLinkModalActive, linkModalActive, messageKey]);
 
   const url = normalizeURL(inputURL);
   const onConfirm = React.useCallback(() => {
@@ -27,7 +32,9 @@
     displayURL += '…';
   }
   return React.useCallback(() => {
-    setLinkModalActive && setLinkModalActive(true);
+    setLinkModalActive &&
+      linkModalActive &&
+      setLinkModalActive({ ...linkModalActive, [messageKey]: true });
     Alert.alert(
       'External link',
       `You sure you want to open this link?\n\n${displayURL}`,
@@ -37,7 +44,14 @@
       ],
       { cancelable: true, onDismiss },
     );
-  }, [setLinkModalActive, displayURL, onConfirm, onDismiss]);
+  }, [
+    setLinkModalActive,
+    linkModalActive,
+    messageKey,
+    displayURL,
+    onConfirm,
+    onDismiss,
+  ]);
 }
 
 type TextProps = React.ElementConfig<typeof Text>;
@@ -48,15 +62,22 @@
 };
 function MarkdownLink(props: Props): React.Node {
   const markdownContext = React.useContext(MarkdownContext);
+  const messageContext = React.useContext(MessageContext);
+
+  const messageKey = messageContext?.messageKey;
 
   const { target, ...rest } = props;
-  const onPressLink = useDisplayLinkPrompt(target, markdownContext);
+  const onPressLink = useDisplayLinkPrompt(target, markdownContext, messageKey);
 
   const setLinkPressActive = markdownContext?.setLinkPressActive;
+  const linkPressActive = markdownContext?.linkPressActive;
+
   const androidOnStartShouldSetResponderCapture = React.useCallback(() => {
-    setLinkPressActive?.(true);
+    if (linkPressActive) {
+      setLinkPressActive?.({ ...linkPressActive, [messageKey]: true });
+    }
     return true;
-  }, [setLinkPressActive]);
+  }, [setLinkPressActive, linkPressActive, messageKey]);
 
   const activePressHasMoved = React.useRef(false);
   const androidOnResponderMove = React.useCallback(() => {
@@ -68,8 +89,10 @@
       onPressLink();
     }
     activePressHasMoved.current = false;
-    setLinkPressActive?.(false);
-  }, [onPressLink, setLinkPressActive]);
+    if (linkPressActive) {
+      setLinkPressActive?.({ ...linkPressActive, [messageKey]: false });
+    }
+  }, [onPressLink, setLinkPressActive, linkPressActive, messageKey]);
 
   if (Platform.OS !== 'android') {
     return <Text onPress={onPressLink} {...rest} />;
diff --git a/native/root.react.js b/native/root.react.js
--- a/native/root.react.js
+++ b/native/root.react.js
@@ -27,6 +27,7 @@
 import ErrorBoundary from './error-boundary.react';
 import InputStateContainer from './input/input-state-container.react';
 import LifecycleHandler from './lifecycle/lifecycle-handler.react';
+import MarkdownContextProvider from './markdown/markdown-context-provider.react';
 import { defaultNavigationState } from './navigation/default-state';
 import DisconnectedBarVisibilityHandler from './navigation/disconnected-bar-visibility-handler.react';
 import { setGlobalNavContext } from './navigation/icky-global';
@@ -248,23 +249,25 @@
               <InputStateContainer>
                 <SafeAreaProvider initialMetrics={initialWindowMetrics}>
                   <ActionSheetProvider>
-                    <ChatContextProvider>
-                      <SQLiteContextProvider>
-                        <ConnectedStatusBar />
-                        <ReduxPersistGate persistor={getPersistor()}>
-                          {gated}
-                        </ReduxPersistGate>
-                        <PersistedStateGate>
-                          <Socket
-                            detectUnsupervisedBackgroundRef={
-                              detectUnsupervisedBackgroundRef
-                            }
-                          />
-                        </PersistedStateGate>
-                        {navigation}
-                        <NavigationHandler />
-                      </SQLiteContextProvider>
-                    </ChatContextProvider>
+                    <MarkdownContextProvider>
+                      <ChatContextProvider>
+                        <SQLiteContextProvider>
+                          <ConnectedStatusBar />
+                          <ReduxPersistGate persistor={getPersistor()}>
+                            {gated}
+                          </ReduxPersistGate>
+                          <PersistedStateGate>
+                            <Socket
+                              detectUnsupervisedBackgroundRef={
+                                detectUnsupervisedBackgroundRef
+                              }
+                            />
+                          </PersistedStateGate>
+                          {navigation}
+                          <NavigationHandler />
+                        </SQLiteContextProvider>
+                      </ChatContextProvider>
+                    </MarkdownContextProvider>
                   </ActionSheetProvider>
                 </SafeAreaProvider>
               </InputStateContainer>