ChatLoggerexe chatlogger
Key RequiredUniversal

ChatLoggerexe chatlogger

Universal Scripttlrenny25tlrenny25 414 views 35 executesUpdated Jan 9, 2026
5.0/ 5(4 votes)
40100% Positive
Lua Script•478 lines (16724 chars)
-- ChatLogger.exe - Logs all chat messages in a GUI
local Players = game:GetService("Players")
local StarterGui = game:GetService("StarterGui")
local TextService = game:GetService("TextService")

local player = Players.LocalPlayer

-- Global variables for GUI state
local showTimestamps = false
local showDisplayName = false
local messageHistory = {} -- Store original message data
local maxHistory = 500 -- maximum number of stored messages
local currentSearch = "" -- current search filter (lowercase)

-- Create the ChatLogger GUI
local function createChatLoggerGUI()
	-- Create the main ScreenGui
	local screenGui = Instance.new("ScreenGui")
	screenGui.Name = "ChatLogger"
	screenGui.ResetOnSpawn = false
	screenGui.Parent = player:WaitForChild("PlayerGui")

	-- Create the main frame
	local mainFrame = Instance.new("Frame")
	mainFrame.Name = "MainFrame"
	mainFrame.Size = UDim2.new(0, 400, 0, 300)
	mainFrame.Position = UDim2.new(0, 10, 0, 10)
	mainFrame.BackgroundColor3 = Color3.fromRGB(45, 45, 45)
	mainFrame.BorderSizePixel = 0
	mainFrame.Active = true
	mainFrame.Draggable = true
	mainFrame.Parent = screenGui

	-- Rounded corners and padding for main frame
	local mainCorner = Instance.new("UICorner")
	mainCorner.CornerRadius = UDim.new(0, 8)
	mainCorner.Parent = mainFrame

	local mainPadding = Instance.new("UIPadding")
	mainPadding.PaddingTop = UDim.new(0, 6)
	mainPadding.PaddingLeft = UDim.new(0, 6)
	mainPadding.PaddingRight = UDim.new(0, 6)
	mainPadding.PaddingBottom = UDim.new(0, 6)
	mainPadding.Parent = mainFrame

	-- Create the title bar
	local titleBar = Instance.new("Frame")
	titleBar.Name = "TitleBar"
	titleBar.Size = UDim2.new(1, 0, 0, 30)
	titleBar.Position = UDim2.new(0, 0, 0, 0)
	titleBar.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
	titleBar.BorderSizePixel = 0
	titleBar.Parent = mainFrame

	-- Title bar styling
	local titleCorner = Instance.new("UICorner")
	titleCorner.CornerRadius = UDim.new(0, 8)
	titleCorner.Parent = titleBar

	local titleGradient = Instance.new("UIGradient")
	titleGradient.Color = ColorSequence.new({
		ColorSequenceKeypoint.new(0, Color3.fromRGB(40, 40, 40)),
		ColorSequenceKeypoint.new(1, Color3.fromRGB(28, 28, 28)),
	})
	titleGradient.Parent = titleBar

	local titleStroke = Instance.new("UIStroke")
	titleStroke.Color = Color3.fromRGB(0, 0, 0)
	titleStroke.Transparency = 0.7
	titleStroke.Parent = titleBar

	-- Helper: consistent button styling + hover
	local function styleButton(btn, baseColor, hoverColor)
		local corner = Instance.new("UICorner")
		corner.CornerRadius = UDim.new(0, 6)
		corner.Parent = btn
		btn.BackgroundColor3 = baseColor
		btn.MouseEnter:Connect(function()
			btn.BackgroundColor3 = hoverColor
		end)
		btn.MouseLeave:Connect(function()
			btn.BackgroundColor3 = baseColor
		end)
	end

	-- Create the title label
	local titleLabel = Instance.new("TextLabel")
	titleLabel.Name = "TitleLabel"
	titleLabel.Size = UDim2.new(1, -280, 1, 0)
	titleLabel.Position = UDim2.new(0, 0, 0, 0)
	titleLabel.BackgroundTransparency = 1
	titleLabel.Text = "ChatLogger.exe"
	titleLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
	titleLabel.TextScaled = false
	titleLabel.TextSize = 18
	titleLabel.Font = Enum.Font.Code
	titleLabel.TextXAlignment = Enum.TextXAlignment.Left
	titleLabel.TextWrapped = false
	titleLabel.Parent = titleBar

	-- Create Close button
	local closeButton = Instance.new("TextButton")
	closeButton.Name = "CloseButton"
	closeButton.Size = UDim2.new(0, 36, 0, 24)
	closeButton.Position = UDim2.new(1, -40, 0, 3)
	closeButton.BackgroundColor3 = Color3.fromRGB(200, 50, 50)
	closeButton.BorderSizePixel = 0
	closeButton.Text = "X"
	closeButton.TextColor3 = Color3.fromRGB(255, 255, 255)
	closeButton.TextScaled = false
	closeButton.TextSize = 16
	closeButton.Font = Enum.Font.SourceSansBold
	closeButton.Parent = titleBar
	styleButton(closeButton, Color3.fromRGB(200,50,50), Color3.fromRGB(230,80,80))

	-- Create Refresh button
	local refreshButton = Instance.new("TextButton")
	refreshButton.Name = "RefreshButton"
	refreshButton.Size = UDim2.new(0, 42, 0, 24)
	refreshButton.Position = UDim2.new(1, -86, 0, 3)
	refreshButton.BackgroundColor3 = Color3.fromRGB(50, 150, 200)
	refreshButton.BorderSizePixel = 0
	refreshButton.Text = "R"
	refreshButton.TextColor3 = Color3.fromRGB(255, 255, 255)
	refreshButton.TextScaled = false
	refreshButton.TextSize = 16
	refreshButton.Font = Enum.Font.SourceSansBold
	refreshButton.Parent = titleBar
	styleButton(refreshButton, Color3.fromRGB(50,150,200), Color3.fromRGB(80,180,220))

	-- Create Timestamp toggle button
	local timestampButton = Instance.new("TextButton")
	timestampButton.Name = "TimestampButton"
	timestampButton.Size = UDim2.new(0, 40, 0, 24)
	timestampButton.Position = UDim2.new(1, -128, 0, 3)
	timestampButton.BackgroundColor3 = Color3.fromRGB(100, 100, 100)
	timestampButton.BorderSizePixel = 0
	timestampButton.Text = "TS"
	timestampButton.TextColor3 = Color3.fromRGB(255, 255, 255)
	timestampButton.TextScaled = false
	timestampButton.TextSize = 14
	timestampButton.Font = Enum.Font.SourceSansBold
	timestampButton.Parent = titleBar
	styleButton(timestampButton, Color3.fromRGB(100,100,100), Color3.fromRGB(140,140,140))

	-- Create Display Name toggle button
	local displayNameButton = Instance.new("TextButton")
	displayNameButton.Name = "DisplayNameButton"
	displayNameButton.Size = UDim2.new(0, 40, 0, 24)
	displayNameButton.Position = UDim2.new(1, -172, 0, 3)
	displayNameButton.BackgroundColor3 = Color3.fromRGB(150, 100, 50)
	displayNameButton.BorderSizePixel = 0
	displayNameButton.Text = "DN"
	displayNameButton.TextColor3 = Color3.fromRGB(255, 255, 255)
	displayNameButton.TextScaled = false
	displayNameButton.TextSize = 14
	displayNameButton.Font = Enum.Font.SourceSansBold
	displayNameButton.Parent = titleBar
	styleButton(displayNameButton, Color3.fromRGB(150,100,50), Color3.fromRGB(180,130,60))

	-- Create the search box below the title bar
	local searchBox = Instance.new("TextBox")
	searchBox.Name = "SearchBox"
	searchBox.Size = UDim2.new(1, -20, 0, 24)
	searchBox.Position = UDim2.new(0, 10, 0, 35)
	searchBox.PlaceholderText = "Search chat..."
	searchBox.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
	searchBox.TextColor3 = Color3.fromRGB(255, 255, 255)
	searchBox.ClearTextOnFocus = false
	searchBox.Parent = mainFrame

	-- Create the scrolling frame for chat messages (moved down to fit search)
	local scrollingFrame = Instance.new("ScrollingFrame")
	scrollingFrame.Name = "ChatScrollingFrame"
	scrollingFrame.Size = UDim2.new(1, -10, 1, -80)
	scrollingFrame.Position = UDim2.new(0, 5, 0, 65)
	scrollingFrame.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
	scrollingFrame.BorderSizePixel = 0
	scrollingFrame.ScrollBarThickness = 12
	scrollingFrame.ScrollBarImageColor3 = Color3.fromRGB(100, 100, 100)
	scrollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0)
	scrollingFrame.AutomaticCanvasSize = Enum.AutomaticSize.Y
	scrollingFrame.Parent = mainFrame

	-- Scrolling frame padding and rounded corners
	local scrollPadding = Instance.new("UIPadding")
	scrollPadding.PaddingTop = UDim.new(0, 6)
	scrollPadding.PaddingLeft = UDim.new(0, 6)
	scrollPadding.PaddingRight = UDim.new(0, 6)
	scrollPadding.PaddingBottom = UDim.new(0, 6)
	scrollPadding.Parent = scrollingFrame

	local scrollCorner = Instance.new("UICorner")
	scrollCorner.CornerRadius = UDim.new(0, 6)
	scrollCorner.Parent = scrollingFrame

	-- Create the layout for chat messages
	local listLayout = Instance.new("UIListLayout")
	listLayout.SortOrder = Enum.SortOrder.LayoutOrder
	listLayout.Padding = UDim.new(0, 2)
	listLayout.Parent = scrollingFrame

	-- Create Clear button
	local clearButton = Instance.new("TextButton")
	clearButton.Name = "ClearButton"
	clearButton.Size = UDim2.new(0, 40, 0, 25)
	clearButton.Position = UDim2.new(1, -215, 0, 2.5)
	clearButton.BackgroundColor3 = Color3.fromRGB(180, 80, 80)
	clearButton.BorderSizePixel = 0
	clearButton.Text = "CLR"
	clearButton.TextColor3 = Color3.fromRGB(255, 255, 255)
	clearButton.TextScaled = true
	clearButton.Font = Enum.Font.SourceSansBold
	clearButton.Parent = titleBar

	-- Create Export button
	local exportButton = Instance.new("TextButton")
	exportButton.Name = "ExportButton"
	exportButton.Size = UDim2.new(0, 40, 0, 25)
	exportButton.Position = UDim2.new(1, -260, 0, 2.5)
	exportButton.BackgroundColor3 = Color3.fromRGB(100, 150, 100)
	exportButton.BorderSizePixel = 0
	exportButton.Text = "EXP"
	exportButton.TextColor3 = Color3.fromRGB(255, 255, 255)
	exportButton.TextScaled = true
	exportButton.Font = Enum.Font.SourceSansBold
	exportButton.Parent = titleBar

	return screenGui, scrollingFrame, listLayout, closeButton, refreshButton, timestampButton, displayNameButton, clearButton, exportButton, searchBox
end



-- Initialize the GUI
local screenGui, scrollingFrame, listLayout, closeButton, refreshButton, timestampButton, displayNameButton, clearButton, exportButton, searchBox = createChatLoggerGUI()

-- Get current timestamp in [HH:MM:SS] format
local function getTimestamp()
	local time = os.date("*t")
	return string.format("[%02d:%02d:%02d]", time.hour, time.min, time.sec)
end

-- Add a chat message to the log
local function addChatMessage(scrollingFrame, listLayout, playerName, message, skipHistory)
	-- Store original message data (unless skipping for refresh)
	if not skipHistory then
		table.insert(messageHistory, {
			playerName = playerName,
			message = message,
			timestamp = os.time()
		})

		-- enforce history limit
		if #messageHistory > maxHistory then
			table.remove(messageHistory, 1)
		end
	end

	-- Get the player object to check display name
	local playerObj = Players:FindFirstChild(playerName)
	local displayName = playerObj and playerObj.DisplayName or playerName

	-- Create the message text with optional timestamp and display name
	local messageText
	if showTimestamps then
		if showDisplayName then
			messageText = getTimestamp() .. " (" .. displayName .. "): " .. message
		else
			messageText = getTimestamp() .. " (" .. playerName .. "): " .. message
		end
	else
		if showDisplayName then
			messageText = "(" .. displayName .. "): " .. message
		else
			messageText = "(" .. playerName .. "): " .. message
		end
	end

	-- Create a label for the chat message
	local messageLabel = Instance.new("TextLabel")
	messageLabel.Name = "ChatMessage"
	messageLabel.Size = UDim2.new(1, -10, 0, 20)
	messageLabel.BackgroundTransparency = 1
	messageLabel.Text = messageText
	messageLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
	messageLabel.TextScaled = false
	messageLabel.TextSize = 14
	messageLabel.Font = Enum.Font.SourceSans
	messageLabel.TextXAlignment = Enum.TextXAlignment.Left
	messageLabel.TextYAlignment = Enum.TextYAlignment.Top
	messageLabel.TextWrapped = true
	messageLabel.Parent = scrollingFrame

	-- Calculate text size and adjust label height
	local textSize = TextService:GetTextSize(messageLabel.Text, messageLabel.TextSize, messageLabel.Font, Vector2.new(scrollingFrame.AbsoluteSize.X - 20, math.huge))
	messageLabel.Size = UDim2.new(1, -10, 0, textSize.Y)

	-- Auto-scroll to bottom with multiple methods for reliability
	game:GetService("RunService").Heartbeat:Wait()
	task.wait()

	-- Method 1: Use CanvasPosition
	if scrollingFrame and scrollingFrame.CanvasSize then
		scrollingFrame.CanvasPosition = Vector2.new(0, scrollingFrame.CanvasSize.Y.Offset)
	end

	-- Method 2: Use CanvasSize offset for more reliable scrolling
	task.wait()
	if scrollingFrame then
		local maxY = 0
		for _, child in scrollingFrame:GetChildren() do
			if child:IsA("TextLabel") then
				maxY = maxY + child.AbsoluteSize.Y + 2 -- 2 for padding
			end
		end
		scrollingFrame.CanvasPosition = Vector2.new(0, maxY)
	end
end

-- Clear all chat messages
local function clearChatMessages(scrollingFrame)
	for _, child in scrollingFrame:GetChildren() do
		if child:IsA("TextLabel") then
			child:Destroy()
		end
	end
end

-- Refresh all existing messages with new timestamp and display name format
local function refreshMessages(scrollingFrame, listLayout)
	clearChatMessages(scrollingFrame)
	local filter = currentSearch:lower()
	for _, msgData in ipairs(messageHistory) do
		local playerObj = Players:FindFirstChild(msgData.playerName)
		local displayName = playerObj and playerObj.DisplayName or msgData.playerName
		local combined = (msgData.playerName .. " " .. displayName .. " " .. msgData.message):lower()
		if filter == "" or combined:find(filter, 1, true) then
			addChatMessage(scrollingFrame, listLayout, msgData.playerName, msgData.message, true)
		end
	end

end

-- Button event handlers
closeButton.MouseButton1Click:Connect(function()
	screenGui:Destroy()
end)

refreshButton.MouseButton1Click:Connect(function()
	-- Re-render history with current settings (acts as a refresh)
	refreshMessages(scrollingFrame, listLayout)
end)

-- Clear button: clears UI and history
if clearButton then
	clearButton.MouseButton1Click:Connect(function()
		clearChatMessages(scrollingFrame)
		messageHistory = {}
		addChatMessage(scrollingFrame, listLayout, "System", "Chat cleared - logging new messages...")
	end)
end

-- Export button: open modal with full log and attempt to copy
if exportButton then
	exportButton.MouseButton1Click:Connect(function()
		-- Build export text
		local lines = {}
		for _, msgData in ipairs(messageHistory) do
			local timeStr = os.date("%Y-%m-%d %H:%M:%S", msgData.timestamp)
			table.insert(lines, string.format("[%s] %s: %s", timeStr, msgData.playerName, msgData.message))
		end
		local exportText = table.concat(lines, "\n")

		-- Try to set clipboard (may fail in normal Roblox environment)
		local ok, err = pcall(function()
			if setclipboard then
				setclipboard(exportText)
			elseif setclipboard == nil and typeof and type(setclipboard) == "function" then
				setclipboard(exportText)
			else
				error("no clipboard available")
			end
		end)

		if ok then
			addChatMessage(scrollingFrame, listLayout, "System", "Export copied to clipboard (if supported).")
		else
			-- Fallback: show export in a modal TextBox for manual copy
			local modal = Instance.new("Frame")
			modal.Name = "ExportModal"
			modal.Size = UDim2.new(0, 500, 0, 300)
			modal.Position = UDim2.new(0.5, -250, 0.5, -150)
			modal.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
			modal.BorderSizePixel = 0
			modal.Parent = screenGui

			local box = Instance.new("TextBox")
			box.Name = "ExportBox"
			box.Size = UDim2.new(1, -20, 1, -60)
			box.Position = UDim2.new(0, 10, 0, 10)
			box.Text = exportText
			box.TextWrapped = true
			box.TextXAlignment = Enum.TextXAlignment.Left
			box.TextYAlignment = Enum.TextYAlignment.Top
			box.MultiLine = true
			box.ClearTextOnFocus = false
			box.TextEditable = true
			box.Parent = modal

			local closeB = Instance.new("TextButton")
			closeB.Name = "CloseExport"
			closeB.Size = UDim2.new(0, 80, 0, 30)
			closeB.Position = UDim2.new(1, -90, 1, -40)
			closeB.Text = "Close"
			closeB.Parent = modal
			closeB.MouseButton1Click:Connect(function()
				modal:Destroy()
			end)

			addChatMessage(scrollingFrame, listLayout, "System", "Export modal opened — select and copy manually.")
		end
	end)
end

timestampButton.MouseButton1Click:Connect(function()
	showTimestamps = not showTimestamps
	if showTimestamps then
		timestampButton.BackgroundColor3 = Color3.fromRGB(50, 200, 50)
		refreshMessages(scrollingFrame, listLayout)
	else
		timestampButton.BackgroundColor3 = Color3.fromRGB(100, 100, 100)
		refreshMessages(scrollingFrame, listLayout)
	end
end)

displayNameButton.MouseButton1Click:Connect(function()
	showDisplayName = not showDisplayName
	if showDisplayName then
		displayNameButton.BackgroundColor3 = Color3.fromRGB(200, 150, 50)
		refreshMessages(scrollingFrame, listLayout)
	else
		displayNameButton.BackgroundColor3 = Color3.fromRGB(150, 100, 50)
		refreshMessages(scrollingFrame, listLayout)
	end
end)

-- Add a startup message
addChatMessage(scrollingFrame, listLayout, "System", "ChatLogger initialized - logging chat messages...")

-- Connect to chat messages for all players
local function connectPlayerChat(playerToConnect)
	playerToConnect.Chatted:Connect(function(message)
		addChatMessage(scrollingFrame, listLayout, playerToConnect.Name, message)
	end)
end

-- Connect to local player's chat
connectPlayerChat(player)

-- Connect to existing players
for _, otherPlayer in Players:GetPlayers() do
	if otherPlayer ~= player then
		connectPlayerChat(otherPlayer)
	end
end

-- Connect to players who join later
Players.PlayerAdded:Connect(function(newPlayer)
	connectPlayerChat(newPlayer)
end)

-- Search box handler
if searchBox then
	searchBox:GetPropertyChangedSignal("Text"):Connect(function()
		currentSearch = searchBox.Text or ""
		refreshMessages(scrollingFrame, listLayout)
	end)
end

Features & Information

works in all games and logs chats
#blahblahblah#logger

Community Comments (4)

tlrenny25tlrenny25Jan 9, 2026

hi

Replying to @tlrenny25
ProScripter2000ProScripter2000Jan 9, 2026

@tlrenny25 hi

ProScripter2000ProScripter2000Jan 9, 2026

cool script

vxstyvxstyJan 9, 2026

fully ai generated, good job

More Scripts for Universal Scripts