PlayCanvas Storage minimal example
Learn how to combine the VIVERSE Storage SDK with PlayCanvas UI then publish the project via VIVERSE Studio
The Storage SDK empowers developers to add persistent data to their games per world for logged-in users. VIVERSE's Storage SDK can be combined with PlayCanvas' powerful Element UI systems to provide an end-to-end solution for saving persistent data in your game. This page will a provide minimum viable example.

Pre-requisite #1: Create a World, App ID and Leaderboard in VIVERSE Studio
All SDK usage requires an App ID tied to a specific VIVERSE World, which can be created via VIVERSE Studio. This process is described in detail in our documentation on VIVERSE Studio.
NOTE: because VIVERSE SDKs require an App ID, this means VIVERSE SDKs cannot be used with projects published via the PlayCanvas Create SDK extension, which do not have App IDs.



Pre-requisite #2: Clone the Login & Authentication SDK example project
We'll base this project on the PlayCanvas Login & Authentication minimal example, which already shows how to add the VIVERSE SDK to external scripts, then checkAuth()
and run the SSO login loop if necessary, all within the viverse-manager.mjs
script. This will be required before we can set up and use the Storage SDK. Fork the project, and don't forget to replace the App ID in the script with the one you created in Pre-requisite #1.


Step 1: Set Up Additional UI
To start, add a two-column horizontal Layout Group with the login UI as the first child, and a new Group Element as the second child on the right. In that column we can create one UI button and three labels as shown here:

Then in viverse-manager.mjs
, add references for a few of these like so:
/**
* @attribute
* @type {Entity}
*/
scoreLabel
/**
* @attribute
* @type {Entity}
*/
saveScoreButton
/**
* @attribute
* @type {Entity}
*/
lastSavedScoreLabel
Step 2: Create a Score to Save
Add a this.score
property to the initialize()
lifecycle event, and iterate by 1 every frame after a this.hasCheckedForScore
flag has been set to true (this gives us the chance to check for a value saved in the cloud before we start — we'll come back to this). Now we have a continually changing value to save to the cloud. This could just as easily be gems, experience points, resources gathered or other gameplay elements, depending on your game's needs.
initialize() {
// somewhere in initialize
this.score = 0
this.hasCheckedForScore = false
}
update() {
if (this.hasCheckedForScore) { // wait until this flag is set before updating
this.score++
this.scoreLabel.element.text = this.score.toString()
}
}
Step 3: Set up the VIVERSE `storageClient`
With the code from the Login & Auth example in the loadViverse()
method, we should have valid credentials to create Storage and Cloud Save SDK clients. The API reference for this process can be found on the Storage SDK page.
// Continued from loadViverse() method, after successful login via checkAuth():
} else {
// Get the token to start making requests;
const accessToken = await globalThis.viverseClient.getToken();
try { // Attempt storage client init
globalThis.storageClient = new globalThis.viverse.storage()
globalThis.cloudSaveClient = await globalThis.storageClient.newCloudSaveClient(this.appId);
// Start by checking for existing player data
globalThis.cloudSaveClient.getPlayerData('score', this.accessToken).then((response) => {
if (response!= null) { // there exists some data for this property!
this.score = response
this.scoreLabel.element.text = this.score.toString()
this.lastSavedScoreLabel.element.text = "Last saved score: " + this.score.toString()
} else { // the response was null - no saved value exists for this key
this.lastSavedScoreLabel.element.text = "No saved score found. Save now!"
}
this.saveScoreButton.button.active = true
this.hasCheckedForScore = true; // start iterating on score
});
} catch(err) { console.error(err) }
}
}
Step 4: Add a Cloud Save Callback
That should function well, but until we submit some cloud data, the getPlayerData()
check will return null and nothing will display! We already added the "Save Score" button and referenced it with an attribute in our script. Now let's create an set the click callback.
initialize() {
// somewhere within initialize()
this.saveScoreButton.button.on("click", () => {
this.cloudSaveScore();
});
}
async cloudSaveScore() {
let savedScore = await globalThis.cloudSaveClient.setPlayerData("score", this.score.toString(), this.accessToken)
this.lastSavedScoreLabel.element.text = "Last Saved Score: " + this.score.toString();
}
Step 5: Export and Publish to VIVERSE
That's it! That should fulfil our minimal requirements to use the VIVERSE Storage SDK along with PlayCanvas UI. Now we just need to export and publish.
In PlayCanvas' Publish/Download menus, choose the "DOWNLOAD ZIP," then set your export options and click the first grey "DOWNLOAD," which will prepare you a build, exposing the final orange "DOWNLOAD" button after a few seconds.


Once the build .zip is downloaded, navigate to VIVERSE Studio's Upload section, click "Manage Content" next to the app you created earlier, and use the "Upload Content" section to select the .zip.
From there, you can preview your build, or submit it for content review and approval. This process is explored in great detail in the VIVERSE Studio section of our docs if you have further questions.

Final Build
The build is ready. Here are the relevant links:
Public PlayCanvas project: https://playcanvas.com/project/1380461/overview/viverse-storage-sdk--pc
Demo scene live on VIVERSE: https://worlds.viverse.com/xESmRTh

Last updated
Was this helpful?