Need help removing user data from datastore to comply with GDPR

Hello I am trying to remove user data from a datastore

I followed this tutorial About GDPR and CCPA | Documentation - Roblox Creator Hub

I have a script called “ConsoleEvent” in ServerScriptService. Here is the script!

local ServerStorage = game:GetService("ServerStorage")
local DataStoreService = game:GetService("DataStoreService")
local removePlayerDataEvent = ServerStorage:WaitForChild("RemovePlayerData")
 
-- Reference to player data store (replace "PlayerData" with the name of your data store)
local playerData = DataStoreService:GetDataStore("AvatarData")
 
local function onRemovePlayerDataEvent(userID)
	-- Pattern for data store player key, for instance "Player_12345678"
	local dataStoreKey = "Player_" .. userID
 
	local success, err = pcall(function()
		return playerData:RemoveAsync(dataStoreKey)
	end)
	if success then
		warn("Removed player data for user ID '" .. userID .. "'")
	else
		warn(err)
	end
end
removePlayerDataEvent.Event:Connect(onRemovePlayerDataEvent)

and here is my DataStore

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("AvatarData")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Data = {
	Face = 0;
	Shirt = 0;
	Pant = 0;
	Hat = 48474313;
	Torso = {39, 70, 45};
	Arms = {255, 204, 153};
	Head = {255, 204, 153};
	Legs = {82, 124, 174}
}

local function color3ToDictionary(color3Object)

    local color3Dictionary = {
        R = color3Object.R,
        G = color3Object.G,
        B = color3Object.B,
    }

    return color3Dictionary
end


local playersavetable = {};

local function loadStarterData(Player)
		local CharData = Instance.new("Folder")
		CharData.Name = "AvatarConf"
		CharData.Parent = Player
		for statname, statvalue in pairs(Data) do
			if type(statvalue) == 'number' then
			local intvalue = Instance.new("IntValue")
			intvalue.Name = statname
			intvalue.Value = statvalue
			intvalue.Parent = CharData
			else
			local colorvalue = Instance.new("Color3Value")
			colorvalue.Name = statname
			colorvalue.Value = Color3.fromRGB(statvalue[1],statvalue[2],statvalue[3])
			colorvalue.Parent = CharData
		end
	end
end

local function loadData(player)
	local Data
	local s, e = pcall(function()
	Data = DataStore:GetAsync('UserId'..player.UserId)
	end)
	
	if s then 
		print (player.Name.."Data loaded")
	else
		print(player.Name.."Data failed to load")
	end
	
	if Data then
		for statname, statvalue in pairs(Data) do
			if type(statvalue) == "number" then
			player.AvatarConf[statname].Value = statvalue
			else
			player.AvatarConf[statname].Value = Color3.new(statvalue.R,statvalue.G,statvalue.B)
			end
		end
		print(player.Name.."Data has been loaded")
	else
		print(player.Name.."No data found! generating..")
		end
	end

local function saveData(player)
	--if RunService:IsStudio() then return end
	local Data = {}
	for _, stat in ipairs(player.AvatarConf:GetChildren()) do
    if stat:IsA("Color3Value") then
		Data[stat.Name] = color3ToDictionary(stat.Value)
    else
        Data[stat.Name] = stat.Value
    end
end
	local s, e = pcall(function()
		DataStore:SetAsync('UserId'..player.UserId, Data)
	end)
		if s then 
	print(player.Name.."Data has been saved")
		else
	warn (player.Name.."Data failed to save"..e)
	end
end

ReplicatedStorage.SaveEvent.OnServerEvent:Connect(function(player)
 saveData(player)	
end)

---------------------------------------------------------------------------------------------------------------

--Hats

ReplicatedStorage.Hat.OnServerEvent:Connect(function(player, ID)
	game.Players[player.Name].AvatarConf.Hat.Value = ID
end)

--Faces
ReplicatedStorage.Face.OnServerEvent:Connect(function(player, ID)
	game.Players[player.Name].AvatarConf.Face.Value = ID
end)

--Legs
ReplicatedStorage.LegColors.Black.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Legs.Value = Color3.fromRGB(20, 37, 50)
end)
ReplicatedStorage.LegColors.Yellow.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Legs.Value = Color3.fromRGB(245, 206, 44)
end)
ReplicatedStorage.LegColors.Blue.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Legs.Value = Color3.fromRGB(5, 105, 174)
end)
ReplicatedStorage.LegColors.Green.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Legs.Value = Color3.fromRGB(165, 190, 69)
end)
ReplicatedStorage.LegColors.Red.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Legs.Value = Color3.fromRGB(197, 35, 21)
end)
ReplicatedStorage.LegColors.Peach.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Legs.Value = Color3.fromRGB(235, 185, 147)
end)

--Torso
ReplicatedStorage.TorsoColors.Black.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Torso.Value = Color3.fromRGB(20, 37, 50)
end)
ReplicatedStorage.TorsoColors.Yellow.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Torso.Value = Color3.fromRGB(245, 206, 44)
end)
ReplicatedStorage.TorsoColors.Blue.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Torso.Value = Color3.fromRGB(5, 105, 174)
end)
ReplicatedStorage.TorsoColors.Green.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Torso.Value = Color3.fromRGB(165, 190, 69)
end)
ReplicatedStorage.TorsoColors.Red.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Torso.Value = Color3.fromRGB(197, 35, 21)
end)
ReplicatedStorage.TorsoColors.Peach.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Torso.Value = Color3.fromRGB(235, 185, 147)
end)

--Arms
ReplicatedStorage.ArmColors.Black.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Arms.Value = Color3.fromRGB(20, 37, 50)
end)
ReplicatedStorage.ArmColors.Yellow.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Arms.Value = Color3.fromRGB(245, 206, 44)
end)
ReplicatedStorage.ArmColors.Blue.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Arms.Value = Color3.fromRGB(5, 105, 174)
end)
ReplicatedStorage.ArmColors.Green.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Arms.Value = Color3.fromRGB(165, 190, 69)
end)
ReplicatedStorage.ArmColors.Red.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Arms.Value = Color3.fromRGB(197, 35, 21)
end)
ReplicatedStorage.ArmColors.Peach.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Arms.Value = Color3.fromRGB(235, 185, 147)
end)

--Head
ReplicatedStorage.HeadColors.Black.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Head.Value = Color3.fromRGB(20, 37, 50)
end)
ReplicatedStorage.HeadColors.Yellow.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Head.Value = Color3.fromRGB(245, 206, 44)
end)
ReplicatedStorage.HeadColors.Blue.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Head.Value = Color3.fromRGB(5, 105, 174)
end)
ReplicatedStorage.HeadColors.Green.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Head.Value = Color3.fromRGB(165, 190, 69)
end)
ReplicatedStorage.HeadColors.Red.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Head.Value = Color3.fromRGB(197, 35, 21)
end)
ReplicatedStorage.HeadColors.Peach.OnServerEvent:Connect(function(player)
	game.Players[player.Name].AvatarConf.Head.Value = Color3.fromRGB(235, 185, 147)
end)

--Shirts
ReplicatedStorage.Shirt.OnServerEvent:Connect(function(player, ID)
	game.Players[player.Name].AvatarConf.Shirt.Value = ID
end)

--Pants
ReplicatedStorage.Pant.OnServerEvent:Connect(function(player, ID)
	game.Players[player.Name].AvatarConf.Pant.Value = ID
end)



----------------------------------------------------------------------------------------------------------
Players.PlayerAdded:Connect(function(player)
	playersavetable[player] = tick()
	loadStarterData(player)
	loadData(player)
end)

Players.PlayerRemoving:Connect(function(player)
	saveData(player)
end)

Upon publishing the game and then loading the console I did the command " game.ServerStorage.RemovePlayerData:Fire(“47292876”)" and it outputs " [ - Removed player data for user ID ‘47292876’" but upon signing into that account the data still loads so it clearly hasn’t been removed.

Note: the userID provided is my old account. I need to learn how to comply with GDPR requests and am using my old account for testing.

You wouldn’t be able to unless you used :GetOrderedDataStore().
You could try to remove the specified player(s) data upon joining the game though.

also how do I know what my DataStoreKey is?

Your key is AvatarData.

local playerData = DataStoreService:GetDataStore("AvatarData")

Isn’t that the name of the DataStore? I actually just got a datastore editing plugin and im trying to do it using that GUI. How do I know the DataStores name

Data is just a table you use to save their data, the actual key is what I mentioned above, by changing this, everyone’s saved data will be wiped.

The pattern for the data store key is incorrect.
In your data saving code the pattern is "UserId" .. UserId, however in the code sample you’re using from wiki the pattern is "Player_" .. UserId.

To fix the issue you would replace the value of the dataStoreKey variable with "UserId" .. userId".

local ServerStorage = game:GetService("ServerStorage")
local DataStoreService = game:GetService("DataStoreService")
local removePlayerDataEvent = ServerStorage:WaitForChild("RemovePlayerData")
 
-- Reference to player data store (replace "PlayerData" with the name of your data store)
local playerData = DataStoreService:GetDataStore("AvatarData")
 
local function onRemovePlayerDataEvent(userID)
	-- Pattern for data store player key, for instance "Player_12345678"
	local dataStoreKey = "UserId" .. userId
 
	local success, err = pcall(function()
		return playerData:RemoveAsync(dataStoreKey)
	end)
	if success then
		warn("Removed player data for user ID '" .. userID .. "'")
	else
		warn(err)
	end
end

On line 10 “UserId” is a unknown variable. It seems to work in other cases though so I am confused.

Also, now the remove data command outputs nothing

Capitalize the “d” in .. userId.

I already tried that and its still unknown. I am getting really concerned because I dont know how long I have to comply with the data removal request

edit: sorry, I misread your comment. the variable is now known

it now outputs this " console:1: Unexpected Unicode character: U+201c. Did you mean ‘"’?"

The output message has “console” in it?
It seems like you’re trying to use some kind of special quotation marks, so I think you should do what the output message suggests, replacing those special quotation marks with ".

alright that was weird but its fixed now but now its back to outputting nothing. I would just rename the datastore but that wouldnt actually wipe it but rather just make it inaccessible

You no longer listen to the event, you seem to have removed it?
Add removePlayerDataEvent.Event:Connect(onRemovePlayerDataEvent) back at the end of the script.

1 Like

that seemed to do the trick! The data was removed!