diff --git a/backend/src/app/rpc/mutations/profile.clj b/backend/src/app/rpc/mutations/profile.clj
index 68179b31a..a6a5cb1c2 100644
--- a/backend/src/app/rpc/mutations/profile.clj
+++ b/backend/src/app/rpc/mutations/profile.clj
@@ -49,8 +49,10 @@
 (declare register-profile)
 
 (s/def ::invitation-token ::us/not-empty-string)
+(s/def ::terms-privacy ::us/boolean)
+
 (s/def ::register-profile
-  (s/keys :req-un [::email ::password ::fullname]
+  (s/keys :req-un [::email ::password ::fullname ::terms-privacy]
           :opt-un [::invitation-token]))
 
 (sv/defmethod ::register-profile {:auth false :rlimit :password}
@@ -63,6 +65,10 @@
     (ex/raise :type :validation
               :code :email-domain-is-not-allowed))
 
+  (when-not (:terms-privacy params)
+    (ex/raise :type :validation
+              :code :invalid-terms-and-privacy))
+
   (db/with-atomic [conn pool]
     (let [cfg     (assoc cfg :conn conn)]
       (register-profile cfg params))))
@@ -331,7 +337,8 @@
               {:id id}))
 
 (s/def ::update-profile
-  (s/keys :req-un [::id ::fullname ::lang ::theme]))
+  (s/keys :req-un [::id ::fullname]
+          :opt-un [::lang ::theme]))
 
 (sv/defmethod ::update-profile
   [{:keys [pool] :as cfg} params]
diff --git a/backend/tests/app/tests/test_services_profile.clj b/backend/tests/app/tests/test_services_profile.clj
index f48fc8801..f527a3d31 100644
--- a/backend/tests/app/tests/test_services_profile.clj
+++ b/backend/tests/app/tests/test_services_profile.clj
@@ -190,6 +190,32 @@
     (t/testing "not allowed email domain"
       (t/is (false? (profile/email-domain-in-whitelist? whitelist "username@somedomain.com"))))))
 
+(t/deftest test-register-with-no-terms-and-privacy
+  (let [data  {::th/type :register-profile
+               :email "user@example.com"
+               :password "foobar"
+               :fullname "foobar"
+               :terms-privacy nil}
+        out   (th/mutation! data)
+        error (:error out)
+        edata (ex-data error)]
+    (t/is (th/ex-info? error))
+    (t/is (= (:type edata) :validation))
+    (t/is (= (:code edata) :spec-validation))))
+
+(t/deftest test-register-with-bad-terms-and-privacy
+  (let [data  {::th/type :register-profile
+               :email "user@example.com"
+               :password "foobar"
+               :fullname "foobar"
+               :terms-privacy false}
+        out   (th/mutation! data)
+        error (:error out)
+        edata (ex-data error)]
+    (t/is (th/ex-info? error))
+    (t/is (= (:type edata) :validation))
+    (t/is (= (:code edata) :invalid-terms-and-privacy))))
+
 (t/deftest test-register-when-registration-disabled
   (with-mocks [mock {:target 'app.config/get
                      :return (th/mock-config-get-with
@@ -197,7 +223,8 @@
     (let [data  {::th/type :register-profile
                  :email "user@example.com"
                  :password "foobar"
-                 :fullname "foobar"}
+                 :fullname "foobar"
+                 :terms-privacy true}
           out   (th/mutation! data)
           error (:error out)
           edata (ex-data error)]
@@ -210,7 +237,8 @@
         data    {::th/type :register-profile
                  :email (:email profile)
                  :password "foobar"
-                 :fullname "foobar"}
+                 :fullname "foobar"
+                 :terms-privacy true}
         out     (th/mutation! data)
         error   (:error out)
         edata   (ex-data error)]
@@ -225,7 +253,8 @@
           data  {::th/type :register-profile
                  :email "user@example.com"
                  :password "foobar"
-                 :fullname "foobar"}
+                 :fullname "foobar"
+                 :terms-privacy true}
           out   (th/mutation! data)]
       ;; (th/print-result! out)
       (let [mock          (deref mock)
@@ -250,7 +279,8 @@
           data  {::th/type :register-profile
                  :email "user@example.com"
                  :password "foobar"
-                 :fullname "foobar"}
+                 :fullname "foobar"
+                 :terms-privacy true}
           _     (th/create-global-complaint-for pool {:type :bounce :email "user@example.com"})
           out   (th/mutation! data)]
       ;; (th/print-result! out)
@@ -270,7 +300,8 @@
           data  {::th/type :register-profile
                  :email "user@example.com"
                  :password "foobar"
-                 :fullname "foobar"}
+                 :fullname "foobar"
+                 :terms-privacy true}
           _     (th/create-global-complaint-for pool {:type :complaint :email "user@example.com"})
           out   (th/mutation! data)]
 
diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json
index 92fe6d64e..912b78ab1 100644
--- a/frontend/resources/locales.json
+++ b/frontend/resources/locales.json
@@ -369,6 +369,13 @@
     },
     "used-in" : [ "src/app/main/ui/auth.cljs" ]
   },
+  "auth.terms-privacy-agreement" : {
+    "translations" : {
+      "en" : "When creating a new account, you agree to our terms of service and privacy policy.",
+      "es" : "Al crear una nueva cuenta, aceptas nuestros términos de servicio y política de privacidad."
+    },
+    "used-in" : [ "src/app/main/ui/auth/register.cljs" ]
+  },
   "auth.verification-email-sent" : {
     "translations" : {
       "ca" : "Em enviat un correu de verificació a",
@@ -941,6 +948,13 @@
     },
     "used-in" : [ "src/app/main/ui/dashboard/grid.cljs" ]
   },
+  "errors.terms-privacy-agreement-invalid" : {
+    "translations" : {
+      "en" : "You must accept our terms of service and privacy policy.",
+      "es" : "Debes aceptar nuestros términos de servicio y política de privacidad."
+    },
+    "used-in" : [ "src/app/main/ui/auth/register.cljs" ]
+  },
   "errors.clipboard-not-implemented" : {
     "translations" : {
       "ca" : "El teu navegador no pot realitzar aquesta operació",
diff --git a/frontend/resources/styles/common/framework.scss b/frontend/resources/styles/common/framework.scss
index 33116b33d..064541a06 100644
--- a/frontend/resources/styles/common/framework.scss
+++ b/frontend/resources/styles/common/framework.scss
@@ -561,27 +561,28 @@ input.element-name {
 .input-radio,
 .input-checkbox {
   align-items: center;
+  color: $color-gray-40;
   display: flex;
   margin-bottom: 10px;
   margin-top: 10px;
   padding-left: 0px;
 
   label{
-    align-items: center;
     cursor: pointer;
     display: flex;
     margin-right: 15px;
-    font-size: $fs13;
+    font-size: $fs12;
 
     &:before{
       content:"";
       width: 20px;
       height: 20px;
       margin-right: 10px;
-      background-color: $color-gray-50;
-      border: 1px solid $color-gray-60;
-      box-shadow: inset 0 0 0 0 $color-primary ;
+      background-color: $color-gray-10;
+      border: 1px solid $color-gray-30;
+      box-shadow: inset 0 0 0 0 $color-primary;
       box-sizing: border-box;
+      flex-shrink: 0;
     }
 
   }
@@ -676,7 +677,6 @@ input[type=radio]:checked + label:before{
 
   label {
     transition: border 0.2s linear 0s, color 0.2s linear 0s;
-    white-space: nowrap;
     position: relative;
 
     &:before {
@@ -687,11 +687,11 @@ input[type=radio]:checked + label:before{
 
     &::after {
       display: inline-block;
-      width: 16px;
-      height: 16px;
+      width: 20px;
+      height: 20px;
       position: absolute;
       left: 3.2px;
-      top: 0px;
+      top: 0;
       font-size: $fs11;
       transition: border 0.2s linear 0s, color 0.2s linear 0s;
     }
@@ -732,7 +732,7 @@ input[type=radio]:checked + label:before{
 
       &::after {
         content:"✓";
-        color: #000000;
+        color: #ffffff;
         font-size: $fs16;
       }
 
diff --git a/frontend/resources/styles/main/partials/dashboard-grid.scss b/frontend/resources/styles/main/partials/dashboard-grid.scss
index 9a19ef4e7..5c1e98555 100644
--- a/frontend/resources/styles/main/partials/dashboard-grid.scss
+++ b/frontend/resources/styles/main/partials/dashboard-grid.scss
@@ -275,18 +275,6 @@
       margin-top: 15px;
     }
 
-    .input-checkbox {
-      margin: 0;
-      position: absolute;
-      top: 10px;
-      right: 5px;
-
-      label {
-        margin: 0;
-      }
-
-    }
-
   }
 
   // STYLES FOR LIBRARIES
diff --git a/frontend/src/app/main/data/users.cljs b/frontend/src/app/main/data/users.cljs
index 8490095c2..b1250d86e 100644
--- a/frontend/src/app/main/data/users.cljs
+++ b/frontend/src/app/main/data/users.cljs
@@ -33,7 +33,7 @@
 (s/def ::email ::us/email)
 (s/def ::password ::us/string)
 (s/def ::lang (s/nilable ::us/string))
-(s/def ::theme ::us/string)
+(s/def ::theme (s/nilable ::us/string))
 (s/def ::created-at ::us/inst)
 (s/def ::password-1 ::us/string)
 (s/def ::password-2 ::us/string)
@@ -55,17 +55,15 @@
   (ptk/reify ::profile-fetched
     ptk/UpdateEvent
     (update [_ state]
-      (assoc state :profile
-             (cond-> data
-               (nil? (:theme data))
-               (assoc :theme cfg/default-theme))))
+      (assoc state :profile data))
 
     ptk/EffectEvent
     (effect [_ state stream]
       (let [profile (:profile state)]
         (swap! storage assoc :profile profile)
         (i18n/set-locale! (:lang profile))
-        (theme/set-current-theme! (:theme profile))))))
+        (some-> (:theme profile)
+                (theme/set-current-theme!))))))
 
 ;; --- Fetch Profile
 
@@ -91,16 +89,19 @@
     (watch [_ state stream]
       (let [mdata      (meta data)
             on-success (:on-success mdata identity)
-            on-error   (:on-error mdata identity)]
-        (rx/merge
-         (->> (rp/mutation :update-profile data)
-              (rx/map fetch-profile)
-              (rx/catch on-error))
-         (->> stream
-              (rx/filter (ptk/type? ::profile-fetched))
-              (rx/take 1)
-              (rx/tap on-success)
-              (rx/ignore)))))))
+            on-error   (:on-error mdata #(rx/throw %))]
+        (->> (rp/mutation :update-profile data)
+             (rx/catch on-error)
+             (rx/mapcat
+              (fn [_]
+                (rx/merge
+                 (->> stream
+                      (rx/filter (ptk/type? ::profile-fetched))
+                      (rx/take 1)
+                      (rx/tap on-success)
+                      (rx/ignore))
+                 (rx/of (profile-fetched data))))))))))
+
 
 ;; --- Request Email Change
 
diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs
index 63b59b1b9..0f3745b5a 100644
--- a/frontend/src/app/main/ui/auth/register.cljs
+++ b/frontend/src/app/main/ui/auth/register.cljs
@@ -36,17 +36,23 @@
 
 (defn- validate
   [data]
-  (let [password (:password data)]
-    (when (> 8 (count password))
-      {:password {:message "errors.password-too-short"}})))
+  (let [password (:password data)
+        terms-privacy (:terms-privacy data)]
+    (cond-> {}
+      (> 8 (count password))
+      (assoc :password {:message "errors.password-too-short"})
+
+      (and (not terms-privacy) false)
+      (assoc :terms-privacy {:message "errors.terms-privacy-agreement-invalid"}))))
 
 (s/def ::fullname ::us/not-empty-string)
 (s/def ::password ::us/not-empty-string)
 (s/def ::email ::us/email)
 (s/def ::invitation-token ::us/not-empty-string)
+(s/def ::terms-privacy ::us/boolean)
 
 (s/def ::register-form
-  (s/keys :req-un [::password ::fullname ::email]
+  (s/keys :req-un [::password ::fullname ::email ::terms-privacy]
           :opt-un [::invitation-token]))
 
 (mf/defc register-form
@@ -113,10 +119,16 @@
                     :label (tr "auth.password")
                     :type "password"}]]
 
+     [:div.fields-row
+      [:& fm/input {:name :terms-privacy
+                    :class "check-primary"
+                    :tab-index "4"
+                    :label (tr "auth.terms-privacy-agreement")
+                    :type "checkbox"}]]
+
      [:& fm/submit-button
       {:label (tr "auth.register-submit")
-       :disabled @submitted?
-       }]]))
+       :disabled @submitted?}]]))
 
 ;; --- Register Page
 
diff --git a/frontend/src/app/main/ui/components/forms.cljs b/frontend/src/app/main/ui/components/forms.cljs
index 37b08f6c9..1df0408bb 100644
--- a/frontend/src/app/main/ui/components/forms.cljs
+++ b/frontend/src/app/main/ui/components/forms.cljs
@@ -9,70 +9,84 @@
 
 (ns app.main.ui.components.forms
   (:require
-   [rumext.alpha :as mf]
-   [cuerdas.core :as str]
    [app.common.data :as d]
    [app.main.ui.icons :as i]
-   [app.util.object :as obj]
+   [app.util.dom :as dom]
    [app.util.forms :as fm]
-   [app.util.i18n :as i18n :refer [t tr]]
-   ["react" :as react]
-   [app.util.dom :as dom]))
+   [app.util.i18n :as i18n :refer [tr]]
+   [app.util.object :as obj]
+   [cuerdas.core :as str]
+   [rumext.alpha :as mf]))
 
 (def form-ctx (mf/create-context nil))
 (def use-form fm/use-form)
 
 (mf/defc input
-  [{:keys [type label help-icon disabled name form hint trim] :as props}]
-  (let [form       (or form (mf/use-ctx form-ctx))
+  [{:keys [label help-icon disabled form hint trim] :as props}]
+  (let [input-type   (get props :type)
+        input-name   (get props :name)
+        more-classes (get props :class)
 
-        type'      (mf/use-state type)
-        focus?     (mf/use-state false)
+        form         (or form (mf/use-ctx form-ctx))
 
-        touched?   (get-in @form [:touched name])
-        error      (get-in @form [:errors name])
+        type'        (mf/use-state input-type)
+        focus?       (mf/use-state false)
 
-        value      (get-in @form [:data name] "")
+        is-checkbox? (= @type' "checkbox")
+        is-radio?    (= @type' "radio")
+        is-text?     (or (= @type' "password")
+                         (= @type' "text")
+                         (= @type' "email"))
 
-        help-icon' (cond
-                     (and (= type "password")
-                          (= @type' "password"))
-                     i/eye
+        touched?     (get-in @form [:touched input-name])
+        error        (get-in @form [:errors input-name])
 
-                     (and (= type "password")
-                          (= @type' "text"))
-                     i/eye-closed
+        value        (get-in @form [:data input-name] "")
 
-                     :else
-                     help-icon)
+        help-icon'   (cond
+                       (and (= input-type "password")
+                            (= @type' "password"))
+                       i/eye
 
-        klass (dom/classnames
-               :focus     @focus?
-               :valid     (and touched? (not error))
-               :invalid   (and touched? error)
-               :disabled  disabled
-               :empty     (str/empty? value)
-               :with-icon (not (nil? help-icon')))
+                       (and (= input-type "password")
+                            (= @type' "text"))
+                       i/eye-closed
+
+                       :else
+                       help-icon)
+
+        klass (str more-classes " "
+                   (dom/classnames
+                     :focus          @focus?
+                     :valid          (and touched? (not error))
+                     :invalid        (and touched? error)
+                     :disabled       disabled
+                     :empty          (and is-text? (str/empty? value))
+                     :with-icon      (not (nil? help-icon'))
+                     :custom-input   is-text?
+                     :input-radio    is-radio?
+                     :input-checkbox is-checkbox?))
 
         swap-text-password
         (fn []
-          (swap! type' (fn [type]
-                         (if (= "password" type)
+          (swap! type' (fn [input-type]
+                         (if (= "password" input-type)
                            "text"
                            "password"))))
 
         on-focus  #(reset! focus? true)
-        on-change (fm/on-input-change form name trim)
+        on-change (fm/on-input-change form input-name trim)
 
         on-blur
-        (fn [event]
+        (fn [_]
           (reset! focus? false)
-          (when-not (get-in @form [:touched name])
-            (swap! form assoc-in [:touched name] true)))
+          (when-not (get-in @form [:touched input-name])
+            (swap! form assoc-in [:touched input-name] true)))
 
         props (-> props
                   (dissoc :help-icon :form :trim)
-                  (assoc :value value
+                  (assoc :id (name input-name)
+                         :value value
                          :on-focus on-focus
                          :on-blur on-blur
                          :placeholder label
@@ -80,15 +94,15 @@
                          :type @type')
                   (obj/clj->props))]
 
-    [:div.custom-input
+    [:div
      {:class klass}
      [:*
-      [:label label]
       [:> :input props]
+      [:label {:for (name input-name)} label]
       (when help-icon'
         [:div.help-icon
          {:style {:cursor "pointer"}
-          :on-click (when (= "password" type)
+          :on-click (when (= "password" input-type)
                       swap-text-password)}
          help-icon'])
       (cond
@@ -100,16 +114,17 @@
 
 
 (mf/defc textarea
-  [{:keys [label disabled name form hint trim] :as props}]
-  (let [form     (or form (mf/use-ctx form-ctx))
+  [{:keys [label disabled form hint trim] :as props}]
+  (let [input-name (get props :name)
+
+        form     (or form (mf/use-ctx form-ctx))
 
-        type'    (mf/use-state type)
         focus?   (mf/use-state false)
 
-        touched? (get-in @form [:touched name])
-        error    (get-in @form [:errors name])
+        touched? (get-in @form [:touched input-name])
+        error    (get-in @form [:errors input-name])
 
-        value    (get-in @form [:data name] "")
+        value    (get-in @form [:data input-name] "")
 
         klass    (dom/classnames
                   :focus     @focus?
@@ -120,13 +135,13 @@
                   )
 
         on-focus  #(reset! focus? true)
-        on-change (fm/on-input-change form name trim)
+        on-change (fm/on-input-change form input-name trim)
 
         on-blur
-        (fn [event]
+        (fn [_]
           (reset! focus? false)
-          (when-not (get-in @form [:touched name])
-            (swap! form assoc-in [:touched name] true)))
+          (when-not (get-in @form [:touched input-name])
+            (swap! form assoc-in [:touched input-name] true)))
 
         props (-> props
                   (dissoc :help-icon :form :trim)
@@ -134,8 +149,7 @@
                          :on-focus on-focus
                          :on-blur on-blur
                          ;; :placeholder label
-                         :on-change on-change
-                         :type @type')
+                         :on-change on-change)
                   (obj/clj->props))]
 
     [:div.custom-input
@@ -151,12 +165,14 @@
         [:span.hint hint])]]))
 
 (mf/defc select
-  [{:keys [options label name form default]
+  [{:keys [options label form default] :as props
     :or {default ""}}]
-  (let [form      (or form (mf/use-ctx form-ctx))
-        value     (get-in @form [:data name] default)
+  (let [input-name (get props :name)
+
+        form      (or form (mf/use-ctx form-ctx))
+        value     (or (get-in @form [:data input-name]) default)
         cvalue    (d/seek #(= value (:value %)) options)
-        on-change (fm/on-input-change form name)]
+        on-change (fm/on-input-change form input-name)]
 
     [:div.custom-select
      [:select {:value value
diff --git a/frontend/src/app/main/ui/settings/options.cljs b/frontend/src/app/main/ui/settings/options.cljs
index 1ad0d6d2c..5d7c82ed8 100644
--- a/frontend/src/app/main/ui/settings/options.cljs
+++ b/frontend/src/app/main/ui/settings/options.cljs
@@ -9,8 +9,8 @@
 
 (ns app.main.ui.settings.options
   (:require
-   [app.common.spec :as us]
    [app.common.data :as d]
+   [app.common.spec :as us]
    [app.main.data.messages :as dm]
    [app.main.data.users :as du]
    [app.main.refs :as refs]
@@ -28,10 +28,6 @@
 (s/def ::options-form
   (s/keys :opt-un [::lang ::theme]))
 
-(defn- on-error
-  [form error]
-  (st/emit! (dm/error (tr "errors.generic"))))
-
 (defn- on-success
   [form]
   (st/emit! (dm/success (tr "notifications.profile-saved"))))
@@ -42,8 +38,7 @@
         data  (cond-> data
                 (empty? (:lang data))
                 (assoc :lang nil))
-        mdata {:on-success (partial on-success form)
-               :on-error (partial on-error form)}]
+        mdata {:on-success (partial on-success form)}]
     (st/emit! (du/update-profile (with-meta data mdata)))))
 
 (mf/defc options-form
diff --git a/frontend/src/app/main/ui/settings/profile.cljs b/frontend/src/app/main/ui/settings/profile.cljs
index d38a225e8..abc833fb4 100644
--- a/frontend/src/app/main/ui/settings/profile.cljs
+++ b/frontend/src/app/main/ui/settings/profile.cljs
@@ -31,24 +31,18 @@
 (s/def ::email ::us/email)
 
 (s/def ::profile-form
-  (s/keys :req-un [::fullname ::lang ::theme ::email]))
+  (s/keys :req-un [::fullname ::email]))
 
 (defn- on-success
   [form]
   (st/emit! (dm/success (tr "notifications.profile-saved"))))
 
-(defn- on-error
-  [form error]
-  (st/emit! (dm/error (tr "errors.generic"))))
-
 (defn- on-submit
   [form event]
   (let [data  (:clean-data @form)
-        mdata {:on-success (partial on-success form)
-               :on-error (partial on-error form)}]
+        mdata {:on-success (partial on-success form)}]
     (st/emit! (du/update-profile (with-meta data mdata)))))
 
-
 ;; --- Profile Form
 
 (mf/defc profile-form
diff --git a/frontend/src/app/util/forms.cljs b/frontend/src/app/util/forms.cljs
index 94e1a385e..d7465bd48 100644
--- a/frontend/src/app/util/forms.cljs
+++ b/frontend/src/app/util/forms.cljs
@@ -89,7 +89,6 @@
       (mf/set-ref-val! state-ref new-value)
       (render inc))
 
-
     ISwap
     (-swap! [self f]
       (let [f (wrap-update-fn f opts)]
@@ -119,7 +118,10 @@
   ([form field trim?]
   (fn [event]
     (let [target (dom/get-target event)
-          value  (dom/get-value target)]
+          value  (if (or (= (.-type target) "checkbox")
+                         (= (.-type target) "radio"))
+                   (.-checked target)
+                   (dom/get-value target))]
       (swap! form (fn [state]
                     (-> state
                         (assoc-in [:data field] (if trim? (str/trim value) value))