diff --git a/app/controllers/candidates_controller.rb b/app/controllers/candidates_controller.rb
index 61f1c3c9a6280949cfe56e0892f796902fbf0689..4b5afa66eda13004faca5fbc7f12e46eb3fdbe5b 100644
--- a/app/controllers/candidates_controller.rb
+++ b/app/controllers/candidates_controller.rb
@@ -35,24 +35,36 @@ class CandidatesController < ApplicationController
 
   def destroy
     @candidate = Candidate.find(params[:id])
-    @session = @candidate.session
+    @session = Session.find_by(ref_id: params[:session_ref_id])
+    destroy_candidate(@session, @candidate)
+  end
+
+  def destroy_self
+    @session = Session.find_by(ref_id: params[:session_ref_id])
+    user = User.find(session[:user_id])
+    @candidate = Candidate.find_by(user:, session: @session)
+    destroy_candidate(@session, @candidate)
+  end
+
+  private
 
-    if @candidate&.destroy
+  def destroy_candidate(session, candidate)
+    if candidate&.destroy
       Rails.logger.debug("destroyed candidate entry")
       Turbo::StreamsChannel.broadcast_replace_later_to(
-        @session.conference,
-        target: helpers.dom_id(@session),
+        session.conference,
+        target: helpers.dom_id(session),
         partial: "sessions/session",
-        locals: { session: @session }
+        locals: { session: session }
       )
       respond_to do |format|
-        format.turbo_stream { render turbo_stream: turbo_stream.replace(helpers.dom_id(@session), partial: "sessions/session", locals: { session: @session }) }
-        format.html { redirect_to conference_session_path(@session.conference, @session), notice: 'Candidate removed successfully.' }
+        format.turbo_stream { render turbo_stream: turbo_stream.replace(helpers.dom_id(session), partial: "sessions/session", locals: { session: session }) }
+        format.html { redirect_to conference_session_path(session.conference, session), notice: 'Candidate removed successfully.' }
       end
     else
       respond_to do |format|
-        format.turbo_stream { render turbo_stream: turbo_stream.replace(helpers.dom_id(@session), partial: "sessions/session", locals: { session: @session }), status: :unprocessable_entity }
-        format.html { redirect_to conference_session_path(@session.conference, @session), alert: 'Failed to remove candidate.' }
+        format.turbo_stream { render turbo_stream: turbo_stream.replace(helpers.dom_id(session), partial: "sessions/session", locals: { session: session }), status: :unprocessable_entity }
+        format.html { redirect_to conference_session_path(session.conference, session), alert: 'Failed to remove candidate.' }
       end
     end
   end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 6d16c9aeafa09c87a3e7af019880496cae491e27..db5791d8dccaf0db38968adb3ffcbb488c91a5f0 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -2,4 +2,10 @@ module ApplicationHelper
   def logged_in?
     !session[:user_id].nil?
   end
+
+  def body_data_attributes
+    attributes = {}
+    attributes[:loggedin_uid] = session[:user_id] if logged_in?
+    { data: attributes }
+  end
 end
diff --git a/app/javascript/controllers/bothhands_controller.js b/app/javascript/controllers/bothhands_controller.js
deleted file mode 100644
index e818f5719abb856472b4b1a568d5f9edd7caacaf..0000000000000000000000000000000000000000
--- a/app/javascript/controllers/bothhands_controller.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { Controller } from "@hotwired/stimulus"
-
-export default class extends Controller {
-  static targets = ["form", "link"];
-
-  submitWithPrompt(event) {
-    event.preventDefault();
-
-    const reason = prompt("Why are you especially qualified? (Please keep it short, thanks)");
-    if (reason !== null && reason.trim() !== "") {
-      const input = document.createElement("input");
-      input.type = "hidden";
-      input.name = "note";
-      input.value = reason;
-      this.formTarget.appendChild(input);
-      this.formTarget.requestSubmit();
-    }
-  }
-}
diff --git a/app/javascript/controllers/session_controller.js b/app/javascript/controllers/session_controller.js
new file mode 100644
index 0000000000000000000000000000000000000000..8cef9dc28456120069c176694ca54d9296f07ad1
--- /dev/null
+++ b/app/javascript/controllers/session_controller.js
@@ -0,0 +1,40 @@
+import { Controller } from "@hotwired/stimulus"
+
+export default class extends Controller {
+  static targets = ["candidates"];
+
+  connect() {
+    const uid = document.body.dataset.loggedinUid;
+    const isCandidate = this.candidatesTarget.querySelector(`a.candidate[data-candidate-uid="${uid}"]`);
+
+    this.element.querySelectorAll('.only-loggedin').forEach(el => {
+      el.hidden = !uid;
+    });
+    this.element.querySelectorAll('.only-loggedout').forEach(el => {
+      el.hidden = uid;
+    });
+    this.element.querySelectorAll('.only-candidate').forEach(el => {
+      el.hidden = !isCandidate;
+    });
+    this.element.querySelectorAll('.only-no-candidate').forEach(el => {
+      el.hidden = isCandidate;
+    });
+
+
+  }
+
+  submitWithPrompt(event) {
+    event.preventDefault();
+
+    const reason = prompt(event.target.dataset.prompt);
+    if (reason !== null && reason.trim() !== "") {
+      const input = document.createElement("input");
+      input.type = "hidden";
+      input.name = "note";
+      input.value = reason;
+      const form = event.target.closest("form");
+      form.appendChild(input);
+      form.requestSubmit();
+    }
+  }
+}
diff --git a/app/views/candidates/_user_avatar.html.erb b/app/views/candidates/_user_avatar.html.erb
index 04f1a3b84a30641888bca5a58c117b40c7c96968..8d2c0c89b2ff318b7ce80cbfc22667ba80075513 100644
--- a/app/views/candidates/_user_avatar.html.erb
+++ b/app/views/candidates/_user_avatar.html.erb
@@ -3,7 +3,7 @@
 <span class="gap-x-0.5 rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10" style="background-color: <%= user.avatar_color %>" title="<%= user.name %>">
   <span style="color: <%= user.text_color %>"><%= user.name %></span>
   <button type="button" class="group relative -mr-1 size-3.5 rounded-sm hover:bg-gray-500/20">
-    <%= link_to conference_session_assignments_path(session.conference, session, user_id: user.id), data: { turbo_method: :post, turbo_frame: dom_id(session) } do %>
+    <%= link_to conference_session_assignments_path(session.conference, session, user_id: user.id), class: "candidate", data: { turbo_method: :post, turbo_frame: dom_id(session), candidate_uid: user.id } do %>
       <span class="sr-only">Add</span>
       <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16" stroke-width="1" class="size-3.5 stroke-gray-600/50 group-hover:stroke-gray-600/75 fill-gray-600/50" style="stroke: <%= user.text_color %>; fill: <%= user.text_color %>">
         <path d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z" />
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 4b08dc167c06cfd63730900da97845981f658872..45f37abdebbeb4d6ddc72321c486e18f5f02bc82 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -11,7 +11,7 @@
     <%= javascript_importmap_tags %>
   </head>
 
-  <body>
+  <body <%= tag.attributes(body_data_attributes) %>>
     <nav class="main-nav bg-slate-100 border-b border-slate-200 shadow">
       <div class="container mx-auto p-5 flex flex-row justify-between">
         <div class="main-nav-left flex flex-row gap-4 items-center">
diff --git a/app/views/sessions/_session.html.erb b/app/views/sessions/_session.html.erb
index e34e709a7e39a3f4e567f6dbb92b586dcfad729f..9a2b4fc969ba0f1438d17dc9da221d7867fc833b 100644
--- a/app/views/sessions/_session.html.erb
+++ b/app/views/sessions/_session.html.erb
@@ -1,5 +1,5 @@
 <% unassigned_users = User.all - session.assignments.collect(&:user) %>
-<%= turbo_frame_tag dom_id(session), method: "morph", class: "w-full" do %>
+<%= turbo_frame_tag dom_id(session), method: "morph", class: "w-full", data: { controller: "session" } do %>
   <div class="session shadow hover:shadow-lg overflow-scroll text-sm w-full !h-full min-h-full hover:!min-h-max <%= session.translators_needed? ? "translators-needed" : "no-translators-needed" %> <%= session.backup_needed? ? "backup-needed" : "no-backup-needed" %> <%= session.assignees? ? "has-assignees" : "no-assignees" %> <%= (session.ends_at < Time.now ? "past" : "") %>">
     <h4>
       <small class="text-2xs uppercase font-light bg-black/10 rounded-sm p-1 mr-1 lang-<%= session.language %>"><%= session.language %></small>
@@ -20,24 +20,19 @@
         </svg>
         <%= session.stage.name %>
       </span>
-      <% if logged_in? %>
-        <span class="absolute top-0 right-0 text-3xl">
-        <% if candidate = session.candidates.find_by(user_id: current_user.id) %>
-          <%= link_to conference_session_candidate_path(session.conference, session, candidate), class: "pr-1", title: "Withdraw", aria_label: "Withdraw", data: { turbo_method: :delete, turbo_frame: dom_id(session) }, method: :delete do %>
-            🙅
-          <% end %>
-        <% else %>
-          <%= link_to conference_session_candidates_path(session.conference, session), class: "pr-1", title: "Volunteer Myself", aria_label: "Volunteer Myself", data: { turbo_method: :post, turbo_frame: dom_id(session) } do %>
-            🙋
-          <% end %>
-          <%= form_with url: conference_session_candidates_path(session.conference, session), method: :post, class: "inline", data: { turbo_frame: dom_id(session), controller: "bothhands", bothhands_target: "form" } do |form| %>
-            <%= link_to conference_session_candidates_path(session.conference, session), class: "pr-1", title: "Volunteer (with special skills)", aria_label: "Volunteer (with special skills)", data: { action: "bothhands#submitWithPrompt", turbo_prefetch:"false" } do %>
-                🙌
-            <% end %>
+      <span class="absolute top-0 right-0 text-3xl only-loggedin">
+        <%= link_to conference_session_candidates_path(session.conference, session), class: "pr-1 only-candidate", title: "Withdraw", aria_label: "Withdraw", data: { turbo_method: :delete, turbo_frame: dom_id(session) }, method: :delete do %>
+          🙅
+        <% end %>
+        <%= link_to conference_session_candidates_path(session.conference, session), class: "pr-1 only-no-candidate", title: "Volunteer Myself", aria_label: "Volunteer Myself", data: { turbo_method: :post, turbo_frame: dom_id(session) } do %>
+          🙋
+        <% end %>
+        <%= form_with url: conference_session_candidates_path(session.conference, session), method: :post, class: "inline", data: { turbo_frame: dom_id(session) } do |form| %>
+          <%= link_to conference_session_candidates_path(session.conference, session), class: "pr-1 only-no-candidate", title: "Volunteer (with special skills)", aria_label: "Volunteer (with special skills)", data: { action: "session#submitWithPrompt", prompt: "Why are you especially qualified? (Please keep it short, thanks)", turbo_prefetch:"false" } do %>
+              🙌
           <% end %>
         <% end %>
-        </span>
-      <% end %>
+      </span>
     </div>
     <div>
     <ul class="flex flex-wrap text-xs gap-1">
@@ -76,7 +71,7 @@
       </div>
     <% end %>
     <small>candidates (<%= session.candidates.length %>)</small>
-    <ul class="inline-flex flex-wrap gap-1 my-1">
+    <ul class="inline-flex flex-wrap gap-1 my-1" data-session-target="candidates">
       <% session.candidates.sort_by { |cand| cand.note.nil? ? 1:0 }.each do |candidate| %>
         <li class="inline-flex items-end">
           <span class="assigned-user"><%= render partial: 'candidates/user_avatar', locals: { candidate: } %></span>
diff --git a/config/routes.rb b/config/routes.rb
index 0483a6e75f73813647670ac1453ad5caa500bf1b..9f10884a9afee88b726c47286df61229a9a79744 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -26,6 +26,7 @@ Rails.application.routes.draw do
     resources :sessions, param: :ref_id do
       resources :assignments, only: [:create, :destroy]
       resources :candidates, only: [:create, :destroy]
+      delete 'candidates', to: 'candidates#destroy_self'
     end
     resources :speakers, param: :ref_id
   end