ProfileService Tutorial!

If you don’t save user data with ProfileService or DataStore2, then you’re saving data wrongly (unless you’ve taken proper steps to making a secure data store). I wanted to make this tutorial because I had to figure out how to use Profile Service, and it was hard. But in this tutorial, it won’t be, because you’re not figuring this out on your own.


Why can’t I just setup my own data store?

Well, the issue with that is it’ll take up so much valuable time. There’s so much research and experience needed to make your own data store module that you’d have to dedicate months of hard work and research. But if there’s already a FREE resource out there, why not use it? A bunch of big games use it too.


How to write it out

Make a new server script, and paste this code into it:

-- ProfileTemplate table is what empty profiles will default to.
-- Updating the template will not include missing template values
--   in existing player profiles!
local ProfileTemplate = {
    Cash = 0,
    Items = {},
    LogInTimes = 0,
}

----- Loaded Modules -----

local ProfileService = require(game.ServerScriptService.ProfileService)

----- Private Variables -----

local Players = game:GetService("Players")

local ProfileStore = ProfileService.GetProfileStore(
    "PlayerData",
    ProfileTemplate
)

local Profiles = {} -- [player] = profile

----- Private Functions -----

local function GiveCash(profile, amount)
    -- If "Cash" was not defined in the ProfileTemplate at game launch,
    --   you will have to perform the following:
    if profile.Data.Cash == nil then
        profile.Data.Cash = 0
    end
    -- Increment the "Cash" value:
    profile.Data.Cash = profile.Data.Cash + amount
end

local function DoSomethingWithALoadedProfile(player, profile)
    profile.Data.LogInTimes = profile.Data.LogInTimes + 1
    print(player.Name .. " has logged in " .. tostring(profile.Data.LogInTimes)
        .. " time" .. ((profile.Data.LogInTimes > 1) and "s" or ""))
    GiveCash(profile, 100)
    print(player.Name .. " owns " .. tostring(profile.Data.Cash) .. " now!")
end

local function PlayerAdded(player)
    local profile = ProfileStore:LoadProfileAsync("Player_" .. player.UserId)
    if profile ~= nil then
        profile:AddUserId(player.UserId) -- GDPR compliance
        profile:Reconcile() -- Fill in missing variables from ProfileTemplate (optional)
        profile:ListenToRelease(function()
            Profiles[player] = nil
            -- The profile could've been loaded on another Roblox server:
            player:Kick()
        end)
        if player:IsDescendantOf(Players) == true then
            Profiles[player] = profile
            -- A profile has been successfully loaded:
            DoSomethingWithALoadedProfile(player, profile)
        else
            -- Player left before the profile loaded:
            profile:Release()
        end
        local DataLoaded = Instance.new("StringValue",player)
        DataLoaded.Name = "DataLoaded"
    else
        -- The profile couldn't be loaded possibly due to other
        --   Roblox servers trying to load this profile at the same time:
        player:Kick() 
    end
end

----- Initialize -----

-- In case Players have joined the server earlier than this script ran:
for _, player in ipairs(Players:GetPlayers()) do
    task.spawn(PlayerAdded, player)
end

----- Connections -----

Players.PlayerAdded:Connect(PlayerAdded)

Players.PlayerRemoving:Connect(function(player)
    local profile = Profiles[player]
    if profile ~= nil then
        profile:Release()
    end
end)

Note, do not remove the comments yet, they’ll help you. Also, go to here if you can’t figure something out or if you need more information:
Save your player data with ProfileService! (DataStore Module) - Resources / Community Resources - DevForum | Roblox


Step 1: Firstly, test it out a little with their default “Cash” leader stat. If it saves your data after the Cash is changed, go on from there by removing the cash giving functions.


Step 2: Put in your default player data in the Profile Template.


Step 3 Go to the PlayerRemoved function and find this area:

function PlayerRemoved(player)
	local profile = Profiles[player]
	if profile ~= nil then
        profile:Release()
    end
end

Now, just save your player’s data the same way you would with the default data saving method, by doing something like this:

profile.Data.Wins = player.leaderstats.Wins.Value

Step 4 If you didn’t set up your data store saving method properly and your game is kind of popular, then you’ll want to use the data store you’ve been using and disable it from saving. Then, when they first join, make a new value inside the player called, “ProfileHoldOut.” At the very bottom of the if statement for success of loading their data, you do:

YourDataStore:RemoveAsync(player.UserId)

Then after your if statement for success of loading their data, you delete ProfileHoldOut. Now, go to the Profile Service script you made, and at the very top of the player added function, you put:

repeat task.wait(0.1) until not player:FindFirstChild("ProfileLoadoutHold")

Now after all data is loaded, you’ll see a value called “DataLoaded” is created. This is for client scripts loading information like displaying their equipped weapon for example. So before trying to display a player’s possible equipped weapon, you can do this:

player.EquippedWeapon.ChildAdded:Connect(function()

end)

Since data doesn’t load right away, you’ll have to instead listen for when the object will get added.


Closing

You might be wondering about why I didn’t make a tutorial about DataStore2, and that’s because DataStore2 is older than Profile Service. If you do use DataStore2, you don’t need to change to Profile Service. DataStore2 works great and is used in games like Dungeon Quest. It’s always best to use the latest and greatest stuff though.

Please tell me if I did anything wrong in this tutorial, I’ll edit it right away!

33 Likes

Hm, what?

The Default Data Store is good and efficient - you just need to know how to use it correctly.
The 2 other modules [ProfileService and DataStore2 are cool, but not ‘better’ than the default one.]
I’ve been using the default one always, and it’s been great.

This happens because people dont use the default data store correctly.

Not true. It’s always best to use the most working method that suits you and makes it easy for you.(as long as it works fine, then continue with it if you want.)
The default data store might be tough sometimes, but if you use it correctly, there is no need to switch to ProfileService or to DS2.

22 Likes

I am coming here from the bad developing practices topic and I don’t quite understand this. I have done some research and have found nothing about “the default data saving method will start to fail and wipe players’ data”, this just doesn’t sound right to me. I believe that if you are having an issue with Roblox’s datastore, it just a user error. I could be wrong, but I am not convinced seeing how you made a lot of assumptions with zero evidence to back it up.

In the nicest way possible, please delete this. I cringe at the sight of this because it is so incredibly incorrect, Microsoft’s Windows 11 proved this. Again, as nicely as possible.
This is just incorrect, look at Roblox and Apple, they release stuff all the time that isn’t anything close to great.

6 Likes

I agree that using default data stored is great, but one of the reasons ProfileService is so good is because it has Session-Locking, which is great to prevent duping.

I’m not saying that you’re wrong, but even if you say “as nicely as possible” it’s still incredibly rude.

You should at least phrase it in a way that makes it look more like actual feedback rather than clearly displaying unhelpful criticism.

Sorry if this sounded harsh. Its just a pet peeve to see people replying to posts with criticism that doesn’t help the OP improve at all.

2 Likes

I guess I was a little harsh, but my pet peeve is when a new update comes out on Roblox or on my phone and it’s absolute doo-doo, messing up all of my stuff, so that statement was a little bit triggering for me, I guess.

1 Like

Well, just wait until you get a game that gets more than 500 players at once, it hits. You do have access to make a system to stop it from saving if their data didn’t load, or kick them if it doesn’t load, but it only goes so far. Session locking and probably other securities are put in place in Profile Service to protect your data and not cause any data loss. But trust me, get a game popular, and it happens! I’m the owner of Creeper Chaos, the game peaked 2k players and now averages 500-600 concurrent players. Data loss started at around 200 players, and it was extremely hard as my game was getting more players by the day. If you don’t switch to Profile Service and it gets popular, you’ll get hate that will make you want to quit.

3 Likes

You overall did a good tutorial, maybe add more details and examples.

(Take my notes from above as a feedback/constructive critique).

2 Likes

While this tutorial itself is not bad at all, there is a bunch of claims here that are completely invalid.

What?? You are acting like ProfileService and DataStore2 are completely different from DataStoreService. They are not. They just have extra security measures to prevent data loss. If you make your own module that does something similar, then you wont be losing data.

The idea is that you are most definitely going to require the module in some other server script that changes data. For instance, if you have a shop script, it would require the data handling module to get a players profile, and then subtract coins and add an item, or something.

Not really. The method that works best for you and your use case is the one you should use.

3 Likes

You clearly don’t have a game with more than 400 concurrent players. This starts to happen extremely frequently when you do reach 400 or more players. The data store requests will start to fail, and it’s a disaster.

3 Likes

I know, I already dealt with this. First I switched to DataStore2, and then to ProfileService. This doesnt make the points I made suddenly invalid.

3 Likes

So, you do admit to that data loss. If there’s extra security measures, then why not use Profile Service or DataStore2? Plus, this is open sourced and easy to use, so there’s no point in making your own module with doing all the research and headache.

1 Like

First of all the default data store is completely fine. Data will not fail and wipe any players’ data. My friend and I have once made a game that peaked at 3k players. All the data was completely fine. DataStoreService is fine but requires skill to make correctly and to a custom module. Profile Service just coded it correctly and made it a module which was easy to use.

Ignoring the fact that you completely misunderstood how the default data store works… The reason youtubers put the functions and everything else in a module script is so they can use it in other scripts. A module script is MUCH better than putting it in a regular script.

Regarding your tutorial, you have copied the ENTIRE example code that Profile Service has. You didn’t even replace a word. This would be fine if you explained the example code in depth. But you only wrote what to do.

Make a new server script, and paste this code into it:

??? You calling this a tutorial ???

Where to learn from
For everyone seeing this post I recommend learning from youtubers or from the profile service page.

Never copy scripts that you don’t know how work and actually make and learn how to make them yourself.

6 Likes

There’s one issue with making a custom data store module, and that’s experience. How many people know how to make their own data store module, and do people really wanna go through all the work to make their own session locking system and write a couple thousand lines of code? No, of course not lol. People can see how the code works by going to the original post, which is clearly linked… plus the tutorial code was intentionally copy and pasted? You’re making problems from nowhere.

2 Likes

I have clearly stated at the beginning of my post that it requires skill to make a custom module.

DataStoreService is fine but requires skill to make correctly and to a custom module. Profile Service just coded it correctly and made it a module which was easy to use.

I clearly stated that it is tough to make a custom data store module.
I have never even written that people should make their own custom module. Where did you get that from???

People can see how the code works by going to the original post

A tutorial means to teach people about a certain subject. Don’t believe it??? Here is proof
image

It would have been fine if you named it something like “How to use Profile Service”

Also, what is the point of copy pasting something if it is already given in the original post? With better instructions. You are basically using something that is already given and making it worse, with a few false points as well. Like this

It’s always best to use the latest and greatest stuff.

It is not always the best to use something new. You always have to use what suits you.

I recommend changing the title, and not copy pasting the whole thing, and also removing the first paragraph because it is faulty, and the last line is also just an opinion.

2 Likes

The tutorial doesn’t explain how it works. It only says to paste code…
This tutorial could be better
I prefer to use the default datastore

1 Like

It doesn’t take 1000 lines of code to write a session locking system, and if so it’s most likely bloated code.

1 Like

It’s literally made by the developer of Mad City and is used by a multitude of big games

If I explained how the module worked this tutorial would be way way way too long and way above your head.

I didn’t say ProfileService specifically. I said if it takes 1000 lines to only make a session locking system it is bloated code.

Appreciate your tutorial! I followed a youtube video on ProfileService and had a simple mistake that you helped me realize how to fix! Thank you for the time you spent making this post :slight_smile:

1 Like