diff --git a/externs.js b/externs.js
index dc8109442b..c17400716d 100644
--- a/externs.js
+++ b/externs.js
@@ -589,6 +589,8 @@ var TopLevel = {
   "prev": function() {},
   "hasNext": function() {},
   "hasPrev": function() {},
+  "rtl": function() {},
+  "lineCount": function() {},
   "key": function() {},
   "keys": function() {},
   "values": function() {},
diff --git a/src/status_im/chat/models/input.cljs b/src/status_im/chat/models/input.cljs
index 6b7fc42a9f..de4b6c918b 100644
--- a/src/status_im/chat/models/input.cljs
+++ b/src/status_im/chat/models/input.cljs
@@ -7,6 +7,7 @@
             [status-im.chat.commands.sending :as commands.sending]
             [status-im.chat.constants :as chat.constants]
             [status-im.chat.models :as chat]
+            [status-im.chat.models.message-content :as message-content]
             [status-im.chat.models.message :as chat.message]
             [status-im.constants :as constants]
             [status-im.js-dependencies :as dependencies]
@@ -125,11 +126,15 @@
     (let [{:keys [message-id]}
           (get-in db [:chats current-chat-id :metadata :responding-to-message])
           show-name?     (get-in db [:multiaccount :show-name?])
-          preferred-name (when show-name? (get-in db [:multiaccount :preferred-name]))]
+          preferred-name (when show-name? (get-in db [:multiaccount :preferred-name]))
+          emoji? (message-content/emoji-only-content? {:text input-text
+                                                       :response-to message-id})]
       (fx/merge cofx
                 {:db (assoc-in db [:chats current-chat-id :metadata :responding-to-message] nil)}
                 (chat.message/send-message {:chat-id      current-chat-id
-                                            :content-type constants/content-type-text
+                                            :content-type (if emoji?
+                                                            constants/content-type-emoji
+                                                            constants/content-type-text)
                                             :content      (cond-> {:chat-id current-chat-id
                                                                    :text    input-text}
                                                             message-id
@@ -140,15 +145,6 @@
                 (set-chat-input-text nil)
                 (process-cooldown)))))
 
-(defn send-plain-text-message-fx
-  "no command detected, when not empty, proceed by sending text message without command processing"
-  [{:keys [db] :as cofx} message-text current-chat-id]
-  (when-not (string/blank? message-text)
-    (chat.message/send-message cofx {:chat-id      current-chat-id
-                                     :content-type constants/content-type-text
-                                     :content      (cond-> {:chat-id current-chat-id
-                                                            :text    message-text})})))
-
 (fx/defn send-sticker-fx
   [{:keys [db] :as cofx} {:keys [hash pack]} current-chat-id]
   (when-not (string/blank? hash)
diff --git a/src/status_im/chat/models/message.cljs b/src/status_im/chat/models/message.cljs
index 7cfe2eb21f..8886b7281e 100644
--- a/src/status_im/chat/models/message.cljs
+++ b/src/status_im/chat/models/message.cljs
@@ -2,6 +2,7 @@
   (:require [re-frame.core :as re-frame]
             [status-im.multiaccounts.model :as multiaccounts.model]
             [status-im.chat.commands.receiving :as commands-receiving]
+            [status-im.ethereum.json-rpc :as json-rpc]
             [status-im.chat.db :as chat.db]
             [status-im.chat.models :as chat-model]
             [status-im.chat.models.loading :as chat-loading]
@@ -37,17 +38,14 @@
 
 (defn- prepare-message
   [{:keys [content content-type] :as message} chat-id current-chat?]
-  (let [emoji? (message-content/emoji-only-content? content)]
-    ;; TODO janherich: enable the animations again once we can do them more efficiently
-    (cond-> message
-      current-chat?
-      (assoc :seen true)
+  (cond-> message
+    current-chat?
+    (assoc :seen true) (and (= constants/content-type-text content-type)
+                            (message-content/should-collapse?
+                             (:text content)
+                             (:line-count content)))
 
-      emoji?
-      (assoc :content-type constants/content-type-emoji)
-
-      (and (= constants/content-type-text content-type) (not emoji?))
-      (update :content message-content/enrich-content))))
+    (assoc :should-collapse? true)))
 
 (defn system-message? [{:keys [message-type]}]
   (= :system-message message-type))
@@ -250,24 +248,46 @@
                        :message          message
                        :current-chat?    (= (get-in cofx [:db :current-chat-id]) chat-id)})))
 
-(fx/defn upsert-and-send
-  [{:keys [now] :as cofx} {:keys [chat-id from] :as message}]
-  (let [message         (remove-icon message)
-        send-record     (protocol/map->Message (select-keys message transport-keys))
+(fx/defn prepare-message-content [cofx chat-id message]
+  {::json-rpc/call
+   [{:method "shhext_prepareContent"
+     :params [(:content message)]
+     :on-success #(re-frame/dispatch [::prepared-message chat-id message %])
+     :on-failure #(log/error "failed to prepare content" %)}]})
+
+(fx/defn prepared-message
+  {:events [::prepared-message]}
+  [{:keys [now] :as cofx} chat-id message content]
+  (let [message-with-content
+        (update message :content
+                assoc
+                :parsed-text  (:parsedText content)
+                :line-count (:lineCount content)
+                :should-collapse? (message-content/should-collapse?
+                                   (:text content)
+                                   (:lineCount content))
+                :rtl? (:rtl content))
+        send-record     (protocol/map->Message
+                         (select-keys message-with-content transport-keys))
         wrapped-record  (if (= (:message-type send-record) :group-user-message)
                           (wrap-group-message cofx chat-id send-record)
-                          send-record)
-        message (assoc message :outgoing-status :sending)]
-
+                          send-record)]
     (fx/merge cofx
               (chat-model/upsert-chat
                {:chat-id                   chat-id
                 :timestamp                 now
-                :last-message-timestamp    (:timestamp message)
-                :last-message-content      (:content message)
-                :last-message-content-type (:content-type message)
-                :last-clock-value          (:clock-value message)})
-              (send chat-id message wrapped-record))))
+                :last-message-timestamp    (:timestamp message-with-content)
+                :last-message-content      (:content message-with-content)
+                :last-message-content-type (:content-type message-with-content)
+                :last-clock-value          (:clock-value message-with-content)})
+              (send chat-id message-with-content wrapped-record))))
+
+(fx/defn upsert-and-send
+  [{:keys [now] :as cofx} {:keys [chat-id from] :as message}]
+  (let [message         (remove-icon message)
+        message (assoc message :outgoing-status :sending)]
+
+    (prepare-message-content cofx chat-id message)))
 
 (fx/defn update-message-status
   [{:keys [db] :as cofx} chat-id message-id status]
diff --git a/src/status_im/chat/models/message_content.cljs b/src/status_im/chat/models/message_content.cljs
index 20fda0f0e2..39a3658055 100644
--- a/src/status_im/chat/models/message_content.cljs
+++ b/src/status_im/chat/models/message_content.cljs
@@ -40,9 +40,9 @@
   (and (seq text)
        (re-matches constants/regx-rtl-characters (first text))))
 
-(defn- should-collapse? [text]
+(defn should-collapse? [text line-count]
   (or (<= constants/chars-collapse-threshold (count text))
-      (<= constants/lines-collapse-threshold (inc (count (query-regex #"\n" text))))))
+      (<= constants/lines-collapse-threshold (inc line-count))))
 
 (defn- sorted-ranges [{:keys [metadata text]} metadata-keys]
   (->> (if metadata-keys
@@ -81,28 +81,6 @@
        (cond-> builder
          end-record (conj end-record))))))
 
-(defn enrich-content
-  "Enriches message content with `:metadata`, `:render-recipe` and `:rtl?` information.
-  Metadata map keys can by any of the `:link`, `:tag`, `:mention` actions
-  or `:bold` and `:italic` stylings.
-  Value for each key is sequence of tuples representing ranges in original
-  `:text` content. "
-  [{:keys [text] :as content}]
-  (let [[_ metadata] (reduce (fn [[text metadata] [type regex]]
-                               (if-let [matches (query-regex regex text)]
-                                 [(clear-ranges matches text) (assoc metadata type matches)]
-                                 [text metadata]))
-                             [text {}]
-                             (if platform/desktop?
-                               (into stylings actions)
-                               actions))]
-    (cond-> content
-      (seq metadata) (as-> content
-                           (assoc content :metadata metadata)
-                       (assoc content :render-recipe (build-render-recipe content)))
-      (right-to-left-text? text) (assoc :rtl? true)
-      (should-collapse? text) (assoc :should-collapse? true))))
-
 (defn emoji-only-content?
   "Determines if text is just an emoji"
   [{:keys [text response-to]}]
diff --git a/src/status_im/ethereum/json_rpc.cljs b/src/status_im/ethereum/json_rpc.cljs
index 23d3436d31..f7a3317136 100644
--- a/src/status_im/ethereum/json_rpc.cljs
+++ b/src/status_im/ethereum/json_rpc.cljs
@@ -51,6 +51,7 @@
    "shhext_chatMessages" {}
    "shhext_saveChat" {}
    "shhext_contacts" {}
+   "shhext_prepareContent" {}
    "shhext_blockContact" {}
    ;;TODO not used anywhere?
    "shhext_deleteChat" {}
diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs
index 88e70e433b..f4f20d0d87 100644
--- a/src/status_im/events.cljs
+++ b/src/status_im/events.cljs
@@ -616,11 +616,6 @@
              {:db (assoc db :view-id view-id)}
              #(mark-messages-seen %))))
 
-(handlers/register-handler-fx
- :chat/send-plain-text-message
- (fn [{{:keys [current-chat-id]} :db :as cofx} [_ message-text]]
-   (chat.input/send-plain-text-message-fx cofx message-text current-chat-id)))
-
 (handlers/register-handler-fx
  :chat/send-sticker
  (fn [{{:keys [current-chat-id multiaccount]} :db :as cofx} [_ {:keys [hash] :as sticker}]]
diff --git a/src/status_im/group_chats/core.cljs b/src/status_im/group_chats/core.cljs
index bdb85fe124..aba7602c69 100644
--- a/src/status_im/group_chats/core.cljs
+++ b/src/status_im/group_chats/core.cljs
@@ -3,7 +3,9 @@
   (:require [clojure.set :as clojure.set]
             [clojure.spec.alpha :as spec]
             [clojure.string :as string]
+            [status-im.ethereum.json-rpc :as json-rpc]
             [re-frame.core :as re-frame]
+            [status-im.chat.models.message-content :as message-content]
             [status-im.multiaccounts.core :as multiaccounts]
             [status-im.multiaccounts.model :as multiaccounts.model]
             [status-im.utils.pairing :as pairing.utils]
@@ -463,6 +465,43 @@
        (transport.filters/upsert-group-chat-topics)
        (transport.filters/load-members members)))))
 
+(fx/defn prepared-message
+  {:events [::prepared-message]}
+  [{:keys [now] :as cofx}
+   chat-id message
+   content
+   sender-signature
+   whisper-timestamp
+   metadata]
+  (let [message-with-content
+        (update message :content
+                assoc
+                :parsed-text  (:parsedText content)
+                :line-count (:lineCount content)
+                :should-collapse? (message-content/should-collapse?
+                                   (:text content)
+                                   (:lineCount content))
+                :rtl? (:rtl content))]
+    (protocol/receive message-with-content
+                      chat-id
+                      sender-signature
+                      whisper-timestamp
+                      (assoc cofx :metadata metadata))))
+
+(fx/defn prepare-message-content
+  [cofx chat-id message sender-signature whisper-timestamp metadata]
+  {::json-rpc/call
+   [{:method "shhext_prepareContent"
+     :params [(:content message)]
+     :on-success #(re-frame/dispatch [::prepared-message
+                                      chat-id
+                                      message
+                                      %
+                                      sender-signature
+                                      whisper-timestamp
+                                      metadata])
+     :on-failure #(log/error "failed to prepare content" %)}]})
+
 (fx/defn handle-membership-update
   "Upsert chat and receive message if valid"
   ;; Care needs to be taken here as chat-id is not coming from a whisper filter
@@ -498,11 +537,13 @@
                               ;; don't allow anything but group messages
                               (instance? protocol/Message message)
                               (= :group-user-message (:message-type message)))
-                     (protocol/receive message
-                                       chat-id
-                                       sender-signature
-                                       whisper-timestamp
-                                       (assoc % :metadata metadata))))))))
+                     (prepare-message-content
+                      %
+                      chat-id
+                      message
+                      sender-signature
+                      whisper-timestamp
+                      metadata)))))))
 
 (defn handle-sign-success
   "Upsert chat and send signed payload to group members"
diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs
index 2c2a2d7fb5..96bc9a1f59 100644
--- a/src/status_im/subs.cljs
+++ b/src/status_im/subs.cljs
@@ -505,9 +505,9 @@
 (re-frame/reg-sub
  ::show-suggestions-view?
  :<- [:chats/current-chat-ui-prop :show-suggestions?]
- :<- [:chats/current-chat]
+ :<- [:chats/current-chat-input-text]
  :<- [:chats/all-available-commands]
- (fn [[show-suggestions? {:keys [input-text]} commands]]
+ (fn [[show-suggestions? input-text commands]]
    (and (or show-suggestions?
             (commands.input/starts-as-command? (string/trim (or input-text ""))))
         (seq commands))))
@@ -523,7 +523,7 @@
  ::get-commands-for-chat
  :<- [:chats/id->command]
  :<- [::access-scope->command-id]
- :<- [:chats/current-chat]
+ :<- [:chats/current-raw-chat]
  (fn [[id->command access-scope->command-id chat]]
    (commands/chat-commands id->command access-scope->command-id chat)))
 
@@ -666,9 +666,21 @@
              :messages))))
 
 (re-frame/reg-sub
- :chats/current-chat
+ :chats/current-raw-chat
  :<- [:chats/active-chats]
  :<- [:chats/current-chat-id]
+ (fn [[chats current-chat-id]]
+   (get chats current-chat-id)))
+
+(re-frame/reg-sub
+ :chats/current-chat-input-text
+ :<- [:chats/current-raw-chat]
+ (fn [chat]
+   (:input-text chat)))
+
+(re-frame/reg-sub
+ :chats/current-chat
+ :<- [:chats/current-raw-chat]
  :<- [:multiaccount/public-key]
  :<- [:mailserver/ranges]
  :<- [:chats/content-layout-height]
@@ -677,27 +689,28 @@
  :<- [:ethereum/chain-keyword]
  :<- [:prices]
  :<- [:wallet/currency]
- (fn [[chats current-chat-id my-public-key ranges height
+ (fn [[{:keys [group-chat
+               chat-id
+               contact
+               messages]
+        :as current-chat} my-public-key ranges height
        input-height ttt-settings chain-keyword prices currency]]
-   (let [{:keys [group-chat contact messages]
-          :as current-chat}
-         (get chats current-chat-id)]
-     (when current-chat
-       (cond-> (enrich-current-chat current-chat ranges height input-height)
-         (empty? messages)
-         (assoc :universal-link
-                (links/generate-link :public-chat :external current-chat-id))
+   (when current-chat
+     (cond-> (enrich-current-chat current-chat ranges height input-height)
+       (empty? messages)
+       (assoc :universal-link
+              (links/generate-link :public-chat :external chat-id))
 
-         (chat.models/public-chat? current-chat)
-         (assoc :show-input? true)
+       (chat.models/public-chat? current-chat)
+       (assoc :show-input? true)
 
-         (and (chat.models/group-chat? current-chat)
-              (group-chats.db/joined? my-public-key current-chat))
-         (assoc :show-input? true)
+       (and (chat.models/group-chat? current-chat)
+            (group-chats.db/joined? my-public-key current-chat))
+       (assoc :show-input? true)
 
-         (not group-chat)
-         (enrich-current-one-to-one-chat my-public-key ttt-settings
-                                         chain-keyword prices currency))))))
+       (not group-chat)
+       (enrich-current-one-to-one-chat my-public-key ttt-settings
+                                       chain-keyword prices currency)))))
 
 (re-frame/reg-sub
  :chats/current-chat-message
@@ -798,10 +811,10 @@
 
 (re-frame/reg-sub
  :chats/selected-chat-command
- :<- [:chats/current-chat]
+ :<- [:chats/current-chat-input-text]
  :<- [:chats/current-chat-ui-prop :selection]
  :<- [::get-commands-for-chat]
- (fn [[{:keys [input-text]} selection commands]]
+ (fn [[input-text selection commands]]
    (commands.input/selected-chat-command input-text selection commands)))
 
 (re-frame/reg-sub
diff --git a/src/status_im/transport/db.cljs b/src/status_im/transport/db.cljs
index 605393ca6d..85a25afcdd 100644
--- a/src/status_im/transport/db.cljs
+++ b/src/status_im/transport/db.cljs
@@ -59,6 +59,7 @@
 (spec/def :message.content/params (spec/map-of keyword? any?))
 
 (spec/def ::content-type #{constants/content-type-text constants/content-type-command
+                           constants/content-type-emoji
                            constants/content-type-command-request constants/content-type-sticker})
 (spec/def ::message-type #{:group-user-message :public-group-user-message :user-message})
 (spec/def ::clock-value (spec/and pos-int?
diff --git a/src/status_im/transport/message/core.cljs b/src/status_im/transport/message/core.cljs
index 1bc6c749bc..860b462047 100644
--- a/src/status_im/transport/message/core.cljs
+++ b/src/status_im/transport/message/core.cljs
@@ -12,6 +12,7 @@
             [status-im.transport.message.transit :as transit]
             [status-im.transport.utils :as transport.utils]
             [status-im.tribute-to-talk.whitelist :as whitelist]
+            [cljs-bean.core :as clj-bean]
             [status-im.utils.config :as config]
             [status-im.utils.fx :as fx]
             [taoensso.timbre :as log]
@@ -19,14 +20,20 @@
 
 (def message-type-message 1)
 
+(defn build-content [content-js]
+  {:text (.-text content-js)
+   :line-count (.-lineCount content-js)
+   :parsed-text (clj-bean/->clj (.-parsedText content-js))
+   :name (.-name content-js)
+   :rtl? (.-rtl content-js)
+   :response-to (aget content-js "response-to")
+   :chat-id (.-chat_id content-js)})
+
 (defn build-message [parsed-message-js]
   (let [content (.-content parsed-message-js)
         built-message
         (protocol/Message.
-         {:text (.-text content)
-          :response-to (aget content "response-to")
-          :name (.-name content)
-          :chat-id (.-chat_id content)}
+         (build-content content)
          (.-content_type parsed-message-js)
          (keyword (.-message_type parsed-message-js))
          (.-clock parsed-message-js)
diff --git a/src/status_im/ui/components/colors.cljs b/src/status_im/ui/components/colors.cljs
index 08507daf76..affa975ec3 100644
--- a/src/status_im/ui/components/colors.cljs
+++ b/src/status_im/ui/components/colors.cljs
@@ -25,7 +25,7 @@
 (def black-transparent (alpha black 0.1)) ;; Used as background color for rounded button on dark background and as background color for containers like "Backup recovery phrase"
 (def black-transparent-20 (alpha black 0.2)) ; accounts divider
 (def black-transparent-40 (alpha black 0.4))
-
+(def black-transparent-50 (alpha black 0.5))
 (def black-light "#2d2d2d") ;; sign-with-keycard-button
 
 ;; DARK GREY
diff --git a/src/status_im/ui/screens/chat/input/input.cljs b/src/status_im/ui/screens/chat/input/input.cljs
index ef9c7cbee5..0c5e9129dd 100644
--- a/src/status_im/ui/screens/chat/input/input.cljs
+++ b/src/status_im/ui/screens/chat/input/input.cljs
@@ -24,7 +24,7 @@
             [status-im.ui.screens.chat.stickers.views :as stickers]))
 
 (defview basic-text-input [{:keys [set-container-width-fn height single-line-input?]}]
-  (letsubs [{:keys [input-text]} [:chats/current-chat]
+  (letsubs [input-text           [:chats/current-chat-input-text]
             cooldown-enabled?    [:chats/cooldown-enabled?]]
     [react/text-input
      (merge
@@ -91,7 +91,7 @@
         {:placeholder (i18n/label :cooldown/text-input-disabled)}))]))
 
 (defview invisible-input [{:keys [set-layout-width-fn value]}]
-  (letsubs [{:keys [input-text]} [:chats/current-chat]]
+  (letsubs [input-text    [:chats/current-chat-input-text]]
     [react/text {:style     style/invisible-input-text
                  :on-layout #(let [w (-> (.-nativeEvent %)
                                          (.-layout)
@@ -184,7 +184,7 @@
 (defview input-container []
   (letsubs [margin               [:chats/input-margin]
             mainnet?             [:mainnet?]
-            {:keys [input-text]} [:chats/current-chat]
+            input-text           [:chats/current-chat-input-text]
             result-box           [:chats/current-chat-ui-prop :result-box]
             show-stickers?       [:chats/current-chat-ui-prop :show-stickers?]
             state-text (reagent/atom "")]
diff --git a/src/status_im/ui/screens/chat/message/message.cljs b/src/status_im/ui/screens/chat/message/message.cljs
index c3f2ef4cf5..6d1131aee4 100644
--- a/src/status_im/ui/screens/chat/message/message.cljs
+++ b/src/status_im/ui/screens/chat/message/message.cljs
@@ -2,8 +2,11 @@
   (:require [re-frame.core :as re-frame]
             [status-im.chat.commands.receiving :as commands-receiving]
             [status-im.constants :as constants]
+            [status-im.utils.http :as http]
             [status-im.i18n :as i18n]
+            [reagent.core :as reagent]
             [status-im.ui.components.colors :as colors]
+            [status-im.utils.security :as security]
             [status-im.ui.components.icons.vector-icons :as vector-icons]
             [status-im.ui.components.list-selection :as list-selection]
             [status-im.ui.components.popup-menu.views :as desktop.pop-up]
@@ -66,32 +69,89 @@
                :on-press #(re-frame/dispatch [:chat.ui/message-expand-toggled chat-id message-id])}
    (i18n/label (if expanded? :show-less :show-more))])
 
+(defn render-inline [message-text outgoing acc {:keys [type literal destination] :as node}]
+  (case type
+    ""
+    (conj acc literal)
+
+    "code"
+    (conj acc [react/text-class style/inline-code-style literal])
+
+    "emph"
+    (conj acc [react/text-class (style/emph-style outgoing) literal])
+
+    "strong"
+    (conj acc [react/text-class (style/strong-style outgoing) literal])
+
+    "link"
+    (conj acc
+          [react/text-class
+           {:style
+            {:color (if outgoing colors/white colors/blue)
+             :text-decoration-line :underline}
+            :on-press
+            #(when (and (security/safe-link? destination)
+                        (security/safe-link-text? message-text))
+               (if platform/desktop?
+                 (.openURL react/linking (http/normalize-url destination))
+                 (re-frame/dispatch
+                  [:browser.ui/message-link-pressed destination])))}
+           destination])
+
+    "status-tag"
+    (conj acc [react/text-class
+               {:style {:color (if outgoing colors/white colors/blue)
+                        :text-decoration-line :underline}
+                :on-press
+                #(re-frame/dispatch
+                  [:chat.ui/start-public-chat literal {:navigation-reset? true}])}
+               "#"
+               literal])
+
+    (conj acc literal)))
+
+(defn render-block [{:keys [chat-id message-id content
+                            timestamp-str group-chat outgoing
+                            current-public-key expanded?] :as message}
+                    acc
+                    {:keys [type literal children]}]
+  (case type
+
+    "paragraph"
+    (conj acc (reduce
+               (fn [acc e] (render-inline (:text content) outgoing acc e))
+               [react/text-class (style/text-style outgoing)]
+               children))
+
+    "blockquote"
+    (conj acc [react/view (style/blockquote-style outgoing)
+               [react/text-class (style/blockquote-text-style outgoing)
+                (.substring literal 0 (dec (.-length literal)))]])
+
+    "codeblock"
+    (conj acc [react/view style/codeblock-style
+               [react/text-class style/codeblock-text-style
+                (.substring literal 0 (dec (.-length literal)))]])
+
+    acc))
+
+(defn render-parsed-text [{:keys [timestamp-str
+                                  outgoing] :as message}
+
+                          tree]
+  (conj (reduce (fn [acc e] (render-block message acc e)) [react/view {}] tree)
+        [react/text {:style (style/message-timestamp-placeholder outgoing)}
+         (str "  " timestamp-str)]))
+
 (defn text-message
   [{:keys [chat-id message-id content
            timestamp-str group-chat outgoing current-public-key expanded?] :as message}]
   [message-view message
-   (let [response-to (:response-to content)
-         collapsible? (and (:should-collapse? content) group-chat)]
+   (let [response-to (:response-to content)]
      [react/view
-      (when response-to
+      (when (seq response-to)
         [quoted-message response-to (:quoted-message message) outgoing current-public-key])
-      (apply react/nested-text
-             (cond-> {:style (style/text-message collapsible? outgoing)
-                      :text-break-strategy :balanced
-                      :parseBasicMarkdown true
-                      :markdownCodeBackgroundColor colors/black
-                      :markdownCodeForegroundColor colors/green}
-
-               (and collapsible? (not expanded?))
-               (assoc :number-of-lines constants/lines-collapse-threshold))
-             (conj (if-let [render-recipe (:render-recipe content)]
-                     (chat.utils/render-chunks render-recipe message)
-                     [(:text content)])
-                   [{:style (style/message-timestamp-placeholder outgoing)}
-                    (str "  " timestamp-str)]))
-
-      (when collapsible?
-        [expand-button expanded? chat-id message-id])])
+      [render-parsed-text message (:parsed-text content)]])
    {:justify-timestamp? true}])
 
 (defn emoji-message
diff --git a/src/status_im/ui/screens/chat/styles/message/message.cljs b/src/status_im/ui/screens/chat/styles/message/message.cljs
index 5dda21444b..91671fc2bd 100644
--- a/src/status_im/ui/screens/chat/styles/message/message.cljs
+++ b/src/status_im/ui/screens/chat/styles/message/message.cljs
@@ -1,8 +1,10 @@
 (ns status-im.ui.screens.chat.styles.message.message
   (:require [status-im.constants :as constants]
             [status-im.ui.components.colors :as colors]
+            [status-im.ui.components.react :as react]
             [status-im.ui.screens.chat.styles.photos :as photos]
             [status-im.utils.platform :as platform]
+            [status-im.ui.components.typography :as typography]
             [status-im.utils.styles :as styles]))
 
 (defn style-message-text
@@ -216,3 +218,98 @@
    :color (if outgoing
             colors/white-transparent-70
             colors/gray)})
+
+;; Markdown styles
+
+(def default-text-style
+  {:max-font-size-multiplier react/max-font-size-multiplier
+   :style (assoc typography/default-style
+                 :line-height 22)})
+
+(def outgoing-text-style
+  (update default-text-style :style
+          assoc :color colors/white))
+
+(defn text-style [outgoing]
+  (if outgoing
+    outgoing-text-style
+    default-text-style))
+
+(def emph-text-style
+  (update default-text-style :style
+          assoc :font-style :italic))
+
+(def outgoing-emph-text-style
+  (update emph-text-style :style
+          assoc :color colors/white))
+
+(defn emph-style [outgoing]
+  (if outgoing
+    outgoing-emph-text-style
+    emph-text-style))
+
+(def strong-text-style
+  (update default-text-style :style
+          assoc :font-weight "700"))
+
+(def outgoing-strong-text-style
+  (update strong-text-style :style
+          assoc :color colors/white))
+
+(defn strong-style [outgoing]
+  (if outgoing
+    outgoing-strong-text-style
+    strong-text-style))
+
+(def monospace-fonts (if platform/ios? "Courier" "monospace"))
+
+(def code-block-background "#2E386B")
+
+(def inline-code-style
+  (update default-text-style :style
+          assoc
+          :font-family monospace-fonts
+          :color colors/white
+          :background-color code-block-background))
+
+(def codeblock-style {:style {:padding 10
+                              :background-color code-block-background
+                              :border-radius 4}})
+
+(def codeblock-text-style
+  (update default-text-style :style
+          assoc
+          :font-family monospace-fonts
+          :color colors/white))
+
+(def default-blockquote-style
+  {:style {:border-left-width 2
+           :padding-left 3
+           :border-left-color colors/gray-transparent-40}})
+
+(def outgoing-blockquote-style
+  (update default-blockquote-style :style
+          assoc
+          :border-left-color colors/white-transparent))
+
+(defn blockquote-style [outgoing]
+  (if outgoing
+    outgoing-blockquote-style
+    default-blockquote-style))
+
+(def default-blockquote-text-style
+  (update default-text-style :style
+          assoc
+          :line-height 19
+          :font-size 14
+          :color colors/black-transparent-50))
+
+(def outgoing-blockquote-text-style
+  (update default-blockquote-text-style :style
+          assoc
+          :color colors/white-transparent-70))
+
+(defn blockquote-text-style [outgoing]
+  (if outgoing
+    outgoing-blockquote-text-style
+    default-blockquote-text-style))
diff --git a/src/status_im/utils/security.cljs b/src/status_im/utils/security.cljs
index 897b70a375..8705e22d91 100644
--- a/src/status_im/utils/security.cljs
+++ b/src/status_im/utils/security.cljs
@@ -24,7 +24,7 @@
     data))
 
 ;; Links starting with javascript:// should not be handled at all
-(def javascript-link-regex #"javascript://.*")
+(def javascript-link-regex #"(?i)javascript://.*")
 ;; Anything with rtlo character we don't handle as it might be a spoofed url
 (def rtlo-link-regex #".*\u202e.*")
 
diff --git a/status-go-version.json b/status-go-version.json
index 18d4e71595..d3b569d8f9 100644
--- a/status-go-version.json
+++ b/status-go-version.json
@@ -2,7 +2,7 @@
     "_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead",
     "owner": "status-im",
     "repo": "status-go",
-    "version": "v0.34.0-beta.7",
-    "commit-sha1": "89659f85b49b48f4409ed9f522397b99728b214b",
-    "src-sha256": "0kyk3r2wl3qxz28ifgnk2r8lh5116q8s58pk9x044dsrl0zvn5qv"
+    "version": "v0.34.0-beta.8",
+    "commit-sha1": "9d7c570593b1f88e9688204d8e1041d57b98da1f",
+    "src-sha256": "1kwxf0h80vdj493c7s3lpmdjpbc72plbll0rj1vv7kzf8a84ff2k"
 }
diff --git a/test/appium/tests/atomic/chats/test_one_to_one.py b/test/appium/tests/atomic/chats/test_one_to_one.py
index 492d7cd89d..a63c4dee7b 100644
--- a/test/appium/tests/atomic/chats/test_one_to_one.py
+++ b/test/appium/tests/atomic/chats/test_one_to_one.py
@@ -207,7 +207,7 @@ class TestMessagesOneToOneChatMultiple(MultipleDeviceTestCase):
         home_2.home_button.click()
 
         chat_1 = home_1.add_contact(public_key_2)
-        url_message = 'status.im'
+        url_message = 'http://status.im'
         chat_1.chat_message_input.send_keys(url_message)
         chat_1.send_message_button.click()
         chat_1.get_back_to_home_view()
diff --git a/test/cljs/status_im/test/chat/models/message_content.cljs b/test/cljs/status_im/test/chat/models/message_content.cljs
deleted file mode 100644
index eb36221e5d..0000000000
--- a/test/cljs/status_im/test/chat/models/message_content.cljs
+++ /dev/null
@@ -1,45 +0,0 @@
-(ns status-im.test.chat.models.message-content
-  (:require [cljs.test :refer-macros [deftest is testing]]
-            [status-im.utils.platform :as platform]
-            [status-im.chat.models.message-content :as message-content]))
-
-(deftest enrich-string-content-test
-  (if platform/desktop?
-    (testing "Text content of the message is enriched correctly"
-      (is (not (:metadata (message-content/enrich-content {:text "Plain message"}))))
-      (is (= {:bold [[5 14]]}
-             (:metadata (message-content/enrich-content {:text "Some *styling* present"}))))
-      (is (= {:bold [[5 14]]
-              :tag  [[28 33] [38 43]]}
-             (:metadata (message-content/enrich-content {:text "Some *styling* present with #tag1 and #tag2 as well"}))))))
-
-  (testing "right to left is correctly identified"
-    (is (not (:rtl? (message-content/enrich-content {:text "You are lucky today!"}))))
-    (is (not (:rtl? (message-content/enrich-content {:text "42"}))))
-    (is (not (:rtl? (message-content/enrich-content {:text "You are lucky today! أنت محظوظ اليوم!"}))))
-    (is (not (:rtl? (message-content/enrich-content {:text "۱۲۳۴۵۶۷۸۹"}))))
-    (is (not (:rtl? (message-content/enrich-content {:text "۱۲۳۴۵۶۷۸۹أنت محظوظ اليوم!"}))))
-    (is (:rtl? (message-content/enrich-content {:text "أنت محظوظ اليوم!"})))
-    (is (:rtl? (message-content/enrich-content {:text "أنت محظوظ اليوم! You are lucky today"})))
-    (is (:rtl? (message-content/enrich-content {:text "יש לך מזל היום!"})))))
-
-(deftest build-render-recipe-test
-  (testing "Render tree is build from text"
-    (is (not (:render-recipe (message-content/enrich-content {:text "Plain message"}))))
-    (is (= (if platform/desktop?
-             '(["Test " :text]
-               ["#status" :tag]
-               [" one three " :text]
-               ["#core-chat (@developer)!" :bold]
-               [" By the way, " :text]
-               ["nice link(https://link.com)" :italic])
-             '(["Test " :text]
-               ["#status" :tag]
-               [" one three *" :text]
-               ["#core-chat" :tag]
-               [" (" :text]
-               ["@developer" :mention]
-               [")!* By the way, ~nice link(" :text]
-               ["https://link.com" :link]
-               [")~" :text]))
-           (:render-recipe (message-content/enrich-content {:text "Test #status one three *#core-chat (@developer)!* By the way, ~nice link(https://link.com)~"}))))))
diff --git a/test/cljs/status_im/test/runner.cljs b/test/cljs/status_im/test/runner.cljs
index 9b177fd79b..d977c317d1 100644
--- a/test/cljs/status_im/test/runner.cljs
+++ b/test/cljs/status_im/test/runner.cljs
@@ -7,7 +7,6 @@
             [status-im.test.chat.commands.input]
             [status-im.test.chat.db]
             [status-im.test.chat.models.input]
-            [status-im.test.chat.models.message-content]
             [status-im.test.chat.models.message]
             [status-im.test.chat.models.message-list]
             [status-im.test.chat.models]
@@ -87,7 +86,6 @@
  'status-im.test.chat.models.input
  'status-im.test.chat.models.message
  'status-im.test.chat.models.message-list
- 'status-im.test.chat.models.message-content
  'status-im.test.chat.views.photos
  'status-im.test.transport.filters.core
  'status-im.test.contacts.db
diff --git a/test/cljs/status_im/test/utils/security.cljs b/test/cljs/status_im/test/utils/security.cljs
index 8a28739b36..08eafd2a8b 100644
--- a/test/cljs/status_im/test/utils/security.cljs
+++ b/test/cljs/status_im/test/utils/security.cljs
@@ -16,6 +16,10 @@
 (deftest safe-link-test-exceptions
   (testing "a javascript link"
     (is (not (security/safe-link? "javascript://anything"))))
+  (testing "a javascript link mixed cases"
+    (is (not (security/safe-link? "JaVasCrIpt://anything"))))
+  (testing "a javascript link upper cases"
+    (is (not (security/safe-link? "JAVASCRIPT://anything"))))
   (testing "rtlo links"
     (is (not (security/safe-link? rtlo-link)))))