diff --git a/apps/meteor/app/apps/server/bridges/livechat.ts b/apps/meteor/app/apps/server/bridges/livechat.ts
index 4e2f8e69acaddb0a714fef2a13c9fe6fecffb585..ec5cff29a99be37d90ba040c950ffc52a783623f 100644
--- a/apps/meteor/app/apps/server/bridges/livechat.ts
+++ b/apps/meteor/app/apps/server/bridges/livechat.ts
@@ -246,7 +246,8 @@ export class AppLivechatBridge extends LivechatBridge {
 			username,
 			name,
 			type,
-		};
+			userType: 'user',
+		} as const;
 
 		let userId;
 		let transferredTo;
diff --git a/apps/meteor/app/apps/server/converters/messages.js b/apps/meteor/app/apps/server/converters/messages.js
index 199722a0d8961c24651a3f9fd01b933bcbb5b4ac..d7dae512e9a8f9ea89642532984c356fc1927bc9 100644
--- a/apps/meteor/app/apps/server/converters/messages.js
+++ b/apps/meteor/app/apps/server/converters/messages.js
@@ -1,3 +1,4 @@
+import { isMessageFromVisitor } from '@rocket.chat/core-typings';
 import { Messages, Rooms, Users } from '@rocket.chat/models';
 import { Random } from '@rocket.chat/random';
 
@@ -107,16 +108,19 @@ export class AppMessagesConverter {
 					return undefined;
 				}
 
-				let user = await cache.get('user')(message.u._id);
-
-				// When the sender of the message is a Guest (livechat) and not a user
-				if (!user) {
-					user = this.orch.getConverters().get('users').convertToApp(message.u);
-				}
+				// When the message contains token, means the message is from the visitor(omnichannel)
+				const user = await (isMessageFromVisitor(msgObj)
+					? this.orch.getConverters().get('users').convertToApp(message.u)
+					: cache.get('user')(message.u._id));
 
 				delete message.u;
 
-				return user;
+				/**
+				 * Old System Messages from visitor doesn't have the `token` field, to not return
+				 * `sender` as undefined, so we need to add this fallback here.
+				 */
+
+				return user || this.orch.getConverters().get('users').convertToApp(message.u);
 			},
 		};
 
diff --git a/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts b/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts
index 44654428ae8fb5a9244dc709531f748c40abc6c2..49fcc0ea4725cbc97659a9752dcffac26f295b25 100644
--- a/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts
+++ b/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts
@@ -266,7 +266,7 @@ export async function sendMessageNotifications(message: IMessage, room: IRoom, u
 		return;
 	}
 
-	const sender = await roomCoordinator.getRoomDirectives(room.t).getMsgSender(message.u._id);
+	const sender = await roomCoordinator.getRoomDirectives(room.t).getMsgSender(message);
 	if (!sender) {
 		return message;
 	}
diff --git a/apps/meteor/app/livechat/server/api/v1/room.ts b/apps/meteor/app/livechat/server/api/v1/room.ts
index 94674f801ad5ed1087a95bc505a25ffaecc91b64..b0f45a63ff87db165b8f99d8ac1a3895cfff60d1 100644
--- a/apps/meteor/app/livechat/server/api/v1/room.ts
+++ b/apps/meteor/app/livechat/server/api/v1/room.ts
@@ -293,8 +293,7 @@ API.v1.addRoute(
 				throw new Error('error-invalid-visitor');
 			}
 
-			const transferedBy = this.user satisfies TransferByData;
-			transferData.transferredBy = normalizeTransferredByData(transferedBy, room);
+			transferData.transferredBy = normalizeTransferredByData(this.user, room);
 			if (transferData.userId) {
 				const userToTransfer = await Users.findOneById(transferData.userId);
 				if (userToTransfer) {
diff --git a/apps/meteor/app/livechat/server/lib/Helper.ts b/apps/meteor/app/livechat/server/lib/Helper.ts
index 01bb2ff34e9aaabef7a4d266d18ef334002a16ac..c0e85a8c7c2b2977392f8c20fba0f855e33963f0 100644
--- a/apps/meteor/app/livechat/server/lib/Helper.ts
+++ b/apps/meteor/app/livechat/server/lib/Helper.ts
@@ -142,7 +142,9 @@ export const createLivechatRoom = async <
 
 	await callbacks.run('livechat.newRoom', room);
 
-	await sendMessage(guest, { t: 'livechat-started', msg: '', groupable: false }, room);
+	// TODO: replace with `Message.saveSystemMessage`
+
+	await sendMessage(guest, { t: 'livechat-started', msg: '', groupable: false, token: guest.token }, room);
 
 	return result.value as IOmnichannelRoom;
 };
@@ -646,6 +648,7 @@ export const forwardRoomToDepartment = async (room: IOmnichannelRoom, guest: ILi
 			'',
 			{ _id, username },
 			{
+				...(transferData.transferredBy.userType === 'visitor' && { token: room.v.token }),
 				transferData: {
 					...transferData,
 					prevDepartment: transferData.originalDepartmentName,
@@ -681,18 +684,23 @@ export const forwardRoomToDepartment = async (room: IOmnichannelRoom, guest: ILi
 	return true;
 };
 
-export const normalizeTransferredByData = (transferredBy: TransferByData, room: IOmnichannelRoom) => {
+type MakePropertyOptional<T, K extends keyof T> = Omit<T, K> & { [P in K]?: T[P] };
+
+export const normalizeTransferredByData = (
+	transferredBy: MakePropertyOptional<TransferByData, 'userType'>,
+	room: IOmnichannelRoom,
+): TransferByData => {
 	if (!transferredBy || !room) {
 		throw new Error('You must provide "transferredBy" and "room" params to "getTransferredByData"');
 	}
 	const { servedBy: { _id: agentId } = {} } = room;
 	const { _id, username, name, userType: transferType } = transferredBy;
-	const type = transferType || (_id === agentId ? 'agent' : 'user');
+	const userType = transferType || (_id === agentId ? 'agent' : 'user');
 	return {
 		_id,
 		username,
 		...(name && { name }),
-		type,
+		userType,
 	};
 };
 
diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts
index 800e32d85ab4b3c9632251325bdd6205571e91e9..82c4dff4c485898a2fa287f1378d93e44b934742 100644
--- a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts
+++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts
@@ -328,13 +328,6 @@ class LivechatClass {
 
 		this.logger.debug(`DB updated for room ${room._id}`);
 
-		const message = {
-			t: 'livechat-close',
-			msg: comment,
-			groupable: false,
-			transcriptRequested: !!transcriptRequest,
-		};
-
 		// Retrieve the closed room
 		const newRoom = await LivechatRooms.findOneById(rid);
 
@@ -343,7 +336,17 @@ class LivechatClass {
 		}
 
 		this.logger.debug(`Sending closing message to room ${room._id}`);
-		await sendMessage(chatCloser, message, newRoom);
+		await sendMessage(
+			chatCloser,
+			{
+				t: 'livechat-close',
+				msg: comment,
+				groupable: false,
+				transcriptRequested: !!transcriptRequest,
+				...(isRoomClosedByVisitorParams(params) && { token: chatCloser.token }),
+			},
+			newRoom,
+		);
 
 		await Message.saveSystemMessage('command', rid, 'promptTranscript', closeData.closedBy);
 
@@ -769,7 +772,9 @@ class LivechatClass {
 			visitorDataToUpdate.visitorEmails = [{ address: visitorEmail }];
 		}
 
-		if (department) {
+		const livechatVisitor = await LivechatVisitors.getVisitorByToken(token, { projection: { _id: 1 } });
+
+		if (livechatVisitor?.department !== department && department) {
 			Livechat.logger.debug(`Attempt to find a department with id/name ${department}`);
 			const dep = await LivechatDepartment.findOneByIdOrName(department, { projection: { _id: 1 } });
 			if (!dep) {
@@ -780,8 +785,6 @@ class LivechatClass {
 			visitorDataToUpdate.department = dep._id;
 		}
 
-		const livechatVisitor = await LivechatVisitors.getVisitorByToken(token, { projection: { _id: 1 } });
-
 		visitorDataToUpdate.token = livechatVisitor?.token || token;
 
 		let existingUser = null;
@@ -1324,7 +1327,7 @@ class LivechatClass {
 		if (guest.name) {
 			message.alias = guest.name;
 		}
-		return Object.assign(await sendMessage(guest, message, room), {
+		return Object.assign(await sendMessage(guest, { ...message, token: guest.token }, room), {
 			newRoom,
 			showConnecting: this.showConnecting(),
 		});
@@ -1443,7 +1446,7 @@ class LivechatClass {
 				_id: String,
 				username: String,
 				name: Match.Maybe(String),
-				type: String,
+				userType: String,
 			}),
 		);
 
@@ -1451,34 +1454,31 @@ class LivechatClass {
 		const scopeData = scope || (nextDepartment ? 'department' : 'agent');
 		this.logger.info(`Storing new chat transfer of ${room._id} [Transfered by: ${_id} to ${scopeData}]`);
 
-		const transfer = {
-			transferData: {
-				transferredBy,
+		await sendMessage(
+			transferredBy,
+			{
+				t: 'livechat_transfer_history',
+				rid: room._id,
 				ts: new Date(),
-				scope: scopeData,
-				comment,
-				...(previousDepartment && { previousDepartment }),
-				...(nextDepartment && { nextDepartment }),
-				...(transferredTo && { transferredTo }),
-			},
-		};
-
-		const type = 'livechat_transfer_history';
-		const transferMessage = {
-			t: type,
-			rid: room._id,
-			ts: new Date(),
-			msg: '',
-			u: {
-				_id,
-				username,
+				msg: '',
+				u: {
+					_id,
+					username,
+				},
+				groupable: false,
+				...(transferData.transferredBy.userType === 'visitor' && { token: room.v.token }),
+				transferData: {
+					transferredBy,
+					ts: new Date(),
+					scope: scopeData,
+					comment,
+					...(previousDepartment && { previousDepartment }),
+					...(nextDepartment && { nextDepartment }),
+					...(transferredTo && { transferredTo }),
+				},
 			},
-			groupable: false,
-		};
-
-		Object.assign(transferMessage, transfer);
-
-		await sendMessage(transferredBy, transferMessage, room);
+			room,
+		);
 	}
 
 	async saveGuest(guestData: Pick<ILivechatVisitor, '_id' | 'name' | 'livechatData'> & { email?: string; phone?: string }, userId: string) {
diff --git a/apps/meteor/definition/IRoomTypeConfig.ts b/apps/meteor/definition/IRoomTypeConfig.ts
index 8ac27be14caf527116061542f0239e660d44955a..12a4bea39f056d5c062177d4e012a3a40a213884 100644
--- a/apps/meteor/definition/IRoomTypeConfig.ts
+++ b/apps/meteor/definition/IRoomTypeConfig.ts
@@ -106,7 +106,7 @@ export interface IRoomTypeServerDirectives {
 		notificationMessage: string,
 		userId: string,
 	) => Promise<{ title: string | undefined; text: string; name: string | undefined }>;
-	getMsgSender: (senderId: IUser['_id']) => Promise<IUser | null>;
+	getMsgSender: (message: IMessage) => Promise<IUser | null>;
 	includeInRoomSearch: () => boolean;
 	getReadReceiptsExtraData: (message: IMessage) => Partial<ReadReceipt>;
 	includeInDashboard: () => boolean;
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoTransferChatScheduler.ts b/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoTransferChatScheduler.ts
index 80af04df64728896bc6f95a295f7baa484bbfe66..d8fb08a3e28241de4bc0350e3fd827b1e6a05d0d 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoTransferChatScheduler.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoTransferChatScheduler.ts
@@ -116,7 +116,7 @@ class AutoTransferChatSchedulerClass {
 
 		await forwardRoomToAgent(room, {
 			userId: agent.agentId,
-			transferredBy,
+			transferredBy: { ...transferredBy, userType: 'user' },
 			transferredTo: agent,
 			scope: 'autoTransferUnansweredChatsToAgent',
 			comment: timeoutDuration,
diff --git a/apps/meteor/server/lib/rooms/roomCoordinator.ts b/apps/meteor/server/lib/rooms/roomCoordinator.ts
index c640b8fec4b8297e10ae9f267a893ec8acdae24d..4f4242f5a34aab2bf6e41f3e3a024eb77602115e 100644
--- a/apps/meteor/server/lib/rooms/roomCoordinator.ts
+++ b/apps/meteor/server/lib/rooms/roomCoordinator.ts
@@ -50,8 +50,8 @@ class RoomCoordinatorServer extends RoomCoordinator {
 
 				return { title, text, name: room.name };
 			},
-			getMsgSender(senderId: IUser['_id']): Promise<IUser | null> {
-				return Users.findOneById(senderId);
+			getMsgSender(message: IMessage): Promise<IUser | null> {
+				return Users.findOneById(message.u._id);
 			},
 			includeInRoomSearch(): boolean {
 				return false;
diff --git a/apps/meteor/server/lib/rooms/roomTypes/livechat.ts b/apps/meteor/server/lib/rooms/roomTypes/livechat.ts
index a6b870042696110a9afe9e3ce8baebeb45fee1e3..7a00f75796c02e02fa5aaa352546fc70a25ca1b6 100644
--- a/apps/meteor/server/lib/rooms/roomTypes/livechat.ts
+++ b/apps/meteor/server/lib/rooms/roomTypes/livechat.ts
@@ -1,4 +1,5 @@
 import type { AtLeast, ValueOf } from '@rocket.chat/core-typings';
+import { isMessageFromVisitor } from '@rocket.chat/core-typings';
 import { LivechatVisitors, LivechatRooms } from '@rocket.chat/models';
 
 import { RoomSettingsEnum, RoomMemberActions } from '../../../../definition/IRoomTypeConfig';
@@ -38,8 +39,10 @@ roomCoordinator.add(LivechatRoomType, {
 		return { title, text, name: roomName };
 	},
 
-	async getMsgSender(senderId) {
-		return LivechatVisitors.findOneEnabledById(senderId);
+	async getMsgSender(message) {
+		if (isMessageFromVisitor(message)) {
+			return LivechatVisitors.findOneEnabledById(message.u._id);
+		}
 	},
 
 	getReadReceiptsExtraData(message) {
diff --git a/apps/meteor/server/lib/rooms/roomTypes/voip.ts b/apps/meteor/server/lib/rooms/roomTypes/voip.ts
index 7925cd65e30297f93cd489b4f961df22aaebba48..c7cb26b476b48635c2eb316dace46bfd5b97f4bd 100644
--- a/apps/meteor/server/lib/rooms/roomTypes/voip.ts
+++ b/apps/meteor/server/lib/rooms/roomTypes/voip.ts
@@ -19,7 +19,7 @@ roomCoordinator.add(VoipRoomType, {
 		return { title, text, name: room.name };
 	},
 
-	async getMsgSender(senderId) {
-		return Users.findOneById(senderId);
+	async getMsgSender(message) {
+		return Users.findOneById(message.u._id);
 	},
 } as AtLeast<IRoomTypeServerDirectives, 'roomName'>);
diff --git a/packages/core-typings/src/IMessage/IMessage.ts b/packages/core-typings/src/IMessage/IMessage.ts
index 1812dfb6dad362ee6baf0a9d02bafddca6962de8..694225dc71a47ffbc3fc8cfe0d5d98a6a2d3f299 100644
--- a/packages/core-typings/src/IMessage/IMessage.ts
+++ b/packages/core-typings/src/IMessage/IMessage.ts
@@ -401,3 +401,9 @@ export type IMessageWithPendingFileImport = IMessage & {
 		downloaded?: boolean;
 	};
 };
+
+export interface IMessageFromVisitor extends IMessage {
+	token: string;
+}
+
+export const isMessageFromVisitor = (message: IMessage): message is IMessageFromVisitor => 'token' in message;
diff --git a/packages/core-typings/src/omnichannel/routing.ts b/packages/core-typings/src/omnichannel/routing.ts
index af27f221c2b17c95ab88231c5cfeaa0da042acd8..526c88eb3d5aba7c7965d5b732eb1988ee0f1272 100644
--- a/packages/core-typings/src/omnichannel/routing.ts
+++ b/packages/core-typings/src/omnichannel/routing.ts
@@ -27,10 +27,7 @@ export type TransferData = {
 	userId?: string;
 	departmentId?: string;
 	department?: Pick<ILivechatDepartment, '_id' | 'name'>;
-	transferredBy: {
-		_id: string;
-		username?: string;
-	};
+	transferredBy: TransferByData;
 	transferredTo?: {
 		username?: string;
 		name?: string;
@@ -47,5 +44,5 @@ export type TransferByData = {
 	_id: string;
 	username?: string;
 	name?: string;
-	userType?: 'agent' | 'user' | 'visitor';
+	userType: 'agent' | 'user' | 'visitor';
 };