Integrate with other Unity services

To use the full potential of Cloud Code, you can connect it with other Unity Gaming Services through the JavaScript Service SDKs or REST APIs.

The JavaScript SDKs are more simple and provide a more consistent experience. However, if the UGS service you want to use doesn't have a Cloud Code JavaScript SDK yet, you can still connect with it through its REST API.

Use the UGS SDKs

You can import the Cloud Code JavaScript SDKs directly into your Cloud Code scripts.

To check what services integrations are available, and find detailed SDK documentation and changelogs for each service, refer to the Cloud Code Services SDKs documentation.

Note: The return objects of methods for other Unity services contain additional information about the request, such as the headers of the request or the response. To access the payload of a response, reference the data property of the object.

For a full list of Cloud Code JavaScript SDKs and their documentation, refer to the table below:

ServiceSDK documentationSDK changelog
Cloud SaveCloud Save SDKCloud Save SDK changelog
EconomyEconomy SDKEconomy SDK changelog
Remote ConfigRemote Config SDKRemote Config SDK changelog
VivoxVivox SDKVivox SDK changelog
LobbyLobby SDKLobby SDK changelog
LeaderboardsLeaderboards SDKLeaderboards SDK changelog
MatchmakerMatchmaker SDKMatchmaker SDK changelog
MultiplayMultiplay SDKMultiplay SDK changelog
FriendsFriends SDKFriends SDK changelog
Player NamesPlayer Names SDKPlayer Names SDK changelog
Player AuthenticationPlayer Authentication SDKPlayer Authentication SDK changelog

Cloud Code scripts allow you to interact with cross-player data by combining different UGS services. For more information, refer to the documentation on how to interact with cross-player data.

Use the Cloud Save SDK

You can use the Cloud Save service to save persistent player data (such as game progress) from a game to the cloud and can access the player data anywhere and across devices. This means you can use Cloud Save to mitigate data loss when a player changes devices or re-installs a game.

Read and write data

You can use Cloud Code to save and read data from Cloud Save.

The sample code demonstrates how you can use different access modifiers for players and custom entities to access and modify Cloud Save data:

JavaScript

const _ = require("lodash-4.17");
const { DataApi } = require("@unity-services/cloud-save-1.4");


module.exports = async ({ params, context, logger }) => {
  const { projectId, playerId, accessToken } = context;
  const cloudSaveApi = new DataApi(context);

  try {
    // Default item data, readable and writable by the player
    await cloudSaveApi.setItem(projectId, playerId, {
      key: "defaultData",
      value: "value"
    });

    // Custom item - non-player entities
    // Record any game data!
    const customId = "gameLevelAttributes";
    await cloudSaveApi.setCustomItem(projectId, customId, {
      key: "levelDifficulty",
      value: "easy"
    });

    // Protected data can be read by player, but not written to
    await cloudSaveApi.setProtectedItem(projectId, playerId, {
      key: "protectedItem",
      value: "verySecretData"
    });

    // Private data that should only be accessed by server/service accounts
    await cloudSaveApi.setPrivateCustomItem(projectId, customId, {
      key: "levelTimerInMinutes",
      value: 25,
    });


    const result = await cloudSaveApi.getItems(projectId, playerId);
    logger.info(`Retrieved default items from Cloud Save: ${JSON.stringify(result.data)}`)

    const protectedDataResult = await cloudSaveApi.getProtectedItems(projectId, playerId, ["protectedItem"]);
    logger.info(`Retrieved protected item from Cloud Save: ${JSON.stringify(protectedDataResult.data)}`)

    const customDataResult = await cloudSaveApi.getPrivateCustomItems(projectId, customId);
    logger.info(`Retrieved private custom items from Cloud Save: ${JSON.stringify(customDataResult.data)}`)

  } catch (err) {
    logger.error("Error while calling out to Cloud Save", { "error.message": err.message });
    throw err;
  }
};

Query data

You can use Cloud Code to query Cloud Save data.

Before you use the sample below, you need to create a query in the Cloud Save service.

Navigate to the Cloud Save service in the Unity Cloud Dashboard, and create queries with the following parameters:

  • An ascending query for player entities with default access class for the key health.
  • A descending query for custom entities with private access class for the key difficulty.
  • An ascending query for player entities with protected access class for the key level.

The sample code demonstrates how you can query Cloud Save data using different access modifiers for players and custom entities:

JavaScript

const _ = require("lodash-4.17");
const { DataApi } = require("@unity-services/cloud-save-1.4");


module.exports = async ({ params, context, logger }) => {
  const { projectId, playerId } = context;
  const cloudSaveApi = new DataApi(context);

  try {
    // --------------------------------------------------------------------------------
    // Query player data with the key `health` to find players with health lower than 100

    // Set data for player
    const requestData = {
      data: [{
        key: "health",
        value: 95,
      },
        {
          key: "stamina",
          value: 20,
        }
      ]
    };

    await cloudSaveApi.setItemBatch(projectId, playerId, requestData);

    // Query and return player stamina for players with health less than 100
    const query = {
      fields: [{
        asc: true,
        key: 'health',
        op: 'LT',
        value: 100,
      }],
      returnKeys: ["stamina"]
    };

    const queryRes = await cloudSaveApi.queryDefaultPlayerData(projectId, query);
    logger.info(`Query results: ${JSON.stringify(queryRes.data)}`)

    // --------------------------------------------------------------------------------
    // Query private custom data to retrieve game levels with easy difficulty

    // Record two levels with different difficulty levels
    const casteLevelId = "castleLevel";
    const anotherLevelId = "forestLevel";
    await cloudSaveApi.setPrivateCustomItem(projectId, casteLevelId, {
      key: "difficulty",
      value: "easy"
    });

    await cloudSaveApi.setPrivateCustomItem(projectId, anotherLevelId, {
      key: "difficulty",
      value: "hard"
    });

    // Query levels with easy levels only
    const privateQuery = {
      fields: [{
        asc: false,
        key: 'difficulty',
        op: 'EQ',
        value: 'easy'
      }],
    };

    const privateQueryRes = await cloudSaveApi.queryPrivateCustomData(projectId, privateQuery);
    logger.info(`Private query results: ${JSON.stringify(privateQueryRes.data)}`)

    // --------------------------------------------------------------------------------
    // Query protected player data for players that are over level 5

    // Set data for player
    const protectedRequestData = {
      data: [{
        key: "level",
        value: 15,
      },
        {
          key: "experiencePoints",
          value: 20,
        }
      ]
    };

    await cloudSaveApi.setProtectedItemBatch(projectId, playerId, protectedRequestData);

    // Query players over level 5, and return their health
    const protectedPlayerQuery = {
      fields: [{
        asc: true,
        key: 'level',
        op: 'GT',
        value: 5,
      }],
      returnKeys: ["experiencePoints", "level"]
    };

    const protectedPlayerRes = await cloudSaveApi.queryProtectedPlayerData(projectId, protectedPlayerQuery);
    logger.info(`Protected player query results: ${JSON.stringify(protectedPlayerRes.data)}`)
    // --------------------------------------------------------------------------------

  } catch (err) {
    logger.error("Error while calling out to Cloud Save", { "error.message": err.message });
    throw err;
  }

};

Use the Economy SDK

The Economy service allows you to create, manage, and publish an economy system in your game with the following resources:

  • Currencies allow your players to have an in-game balance of one or more currencies/denominations.
  • Inventory items represent a definition of a resource that is you create as part of the configuration. A player can own instances of inventory items (for example, multiple copies of the same swords, shields, hats) and, unlike currencies, you can give each instance its own properties.
  • Purchases allow your players to buy in-game currency and inventory items with different in-game currency and inventory items (virtual purchases), or by with real money via a digital storefront.

With Cloud Code, you can manipulate currencies, inventory items, and purchases directly from a script.

Economy SDK player inventory

The script below adds the SWORD item to the player's inventory.

Before you use the sample below, you need to create an inventory item of type SWORD in Economy service, and publish your new configuration.

Note: If you published your inventory configuration but the inventory item isn't found, you might need to refresh your playerId. Alternatively, update the script to use a config assignment hash.

JavaScript

const { InventoryApi } = require("@unity-services/economy-2.4");

module.exports = async ({ params, context, logger }) => {
  const { projectId, playerId, accessToken } = context;
  const inventory = new InventoryApi({ accessToken });

  const addInventoryRequest = { inventoryItemId : "SWORD" };
  try {
    await inventory.addInventoryItem({
      addInventoryRequest,
      playerId,
      projectId
    });

    const result = await inventory.getPlayerInventory({ projectId, playerId });
    return result.data;
  } catch (err) {
    logger.error("Error while retrieving inventory items", {"error.message": err.message});
    throw err;
  }
}

Economy SDK player currencies

The script below sets the player's currency balance, then increments and decrements it.

Before you use the sample below, you need a published currency in the Economy service.

The script below takes in a required string parameter currencyId.

Note: If you published your currency configuration but the currency is not found, you might need to refresh your playerId. Alternatively, update the script to use a config assignment hash.

JavaScript

const { CurrenciesApi } = require("@unity-services/economy-2.4");

module.exports = async ({ params, context, logger }) => {
  const { projectId, playerId, accessToken } = context;
  const { currencyId } = params;
  const currencies = new CurrenciesApi({ accessToken });

  try {
    await currencies.setPlayerCurrencyBalance({ projectId, playerId, currencyId, currencyBalanceRequest: { balance: 100 } });
    await currencies.decrementPlayerCurrencyBalance({ projectId, playerId, currencyId, currencyModifyBalanceRequest: { amount: 50 } });
    await currencies.incrementPlayerCurrencyBalance({ projectId, playerId, currencyId, currencyModifyBalanceRequest: { amount: 10 } });

    const result = await currencies.getPlayerCurrencies({ projectId, playerId });
    return result.data;

  } catch (err) {
    logger.error("Error while updating currencies", {"error.message": err.message}, {"currencyId" : currencyId});
    throw err;
  }
}

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@2.5/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   currencyId: { type: "String", required: true },
// };

Use Economy SDK virtual purchases

The script below makes a virtual purchase, then deletes the item from the player's inventory.

Before you use the sample below, you need to create a virtual purchase in Economy service, and publish your new configuration.

The script takes purchaseId and currencyId as parameters. The currencyId is the ID of the currency that the player needs to have to complete the purchase.

Note: If you published your virtual purchase configuration but the purchase isn't found, you might need to refresh your playerId. Alternatively, update the script to use a config assignment hash.

JavaScript

const { CurrenciesApi, PurchasesApi, InventoryApi } = require("@unity-services/economy-2.4");

module.exports = async ({ params, context, logger }) => {
  const { projectId, playerId, accessToken } = context;
  const { purchaseId, currencyId } = params;

  const inventory = new InventoryApi({ accessToken });
  const purchases = new PurchasesApi({ accessToken });
  const currencies = new CurrenciesApi({ accessToken });


  try {
    // Give a player some currency to complete the purchase
    await currencies.setPlayerCurrencyBalance({ projectId, playerId, currencyId, currencyBalanceRequest: { balance: 1 } });
    const makeVirtualPurchaseResult = await purchases.makeVirtualPurchase({ projectId, playerId, playerPurchaseVirtualRequest: { id: purchaseId } });
    const getPlayerInventoryResult = await inventory.getPlayerInventory({ projectId, playerId });

    await inventory.deleteInventoryItem({ projectId, playerId, playersInventoryItemId: makeVirtualPurchaseResult.data.rewards.inventory[0].playersInventoryItemIds[0], inventoryDeleteRequest: {} });

    return {
      makeVirtualPurchaseResult: makeVirtualPurchaseResult.data,
      getPlayerInventoryResult: getPlayerInventoryResult.data
    };

  } catch (err) {
    logger.error("Error while calling out to Economy", {"error.message": err.message});
    throw err;
  }
}

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@2.5/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   currencyId: { type: "String", required: true },
//   purchaseId: { type: "String", required: true },
// };

Use Economy with Game Overrides

For more information, refer to the Economy Game Overrides with Cloud Code documentation.

Use the Remote Config SDK

Remote Config is a cloud service you can use to tune your game design without the need to deploy new versions of your application. Remote config consists of a set of namespaced key-value parameters, and you can optionally define a set of values that override or add to these parameters.

You can modify Remote Config settings from a Cloud Code script.

The sample below demonstrates how you can assign Remote Config settings to a player.

JavaScript

const { SettingsApi } = require("@unity-services/remote-config-1.1");

module.exports = async ({ context, logger }) => {
  const { projectId, playerId, accessToken } = context;
  const remoteConfig = new SettingsApi({ accessToken });

  try {
    const result = await remoteConfig.assignSettings({ projectId, "userId": playerId, "attributes": { "unity": {}, "app": {}, "user": {} } });
    return result.data;

  } catch (err) {
    logger.error("Error while assigning settings", {"error.message": err.message});
    throw err;
  }
}

Use the Vivox SDK

Vivox provides voice and text-based communication services for your game. Cloud Code allows you to generate a Vivox Token, which lets game clients to safely access Vivox service actions.

The sample below demonstrates how you can generate a Vivox Token with a Cloud Code script.

JavaScript

const { TokenApi } = require("@unity-services/vivox-0.1");

module.exports = (async e => {
  const o = {
    iss: "gary.charlton.oogabooga",
    exp: 1559359105,
    vxa: "join",
    vxi: 1,
    f: "sip:.username.@domain.vivox.com",
    t: "sip:confctl-g-channelname@domain.vivox.com"
  };

  try {
    return TokenApi.generateVivoxToken("TEST_KEY", o)

  } catch (err) {
    logger.error("Error while generating vivox token", {"error.message": err.message});
    throw err;
  }
});

Use the Lobby SDK

Lobby allows your players to connect before or during a game session. Players create public lobbies with simple game attributes that other players can then search, discover, and join. Invite-only lobbies also allow players to create private spaces for select participants only.

The following is an example of how you can create, update and heartbeat a lobby using a Cloud Code script.

The sample uses the service token to create an empty lobby with no owner. It then takes in a playerId parameter, which you can use to add a player to the lobby, and a serviceId parameter, which you can use to identify the service that owns the lobby.

While you can use Cloud Code to make Lobby requests as a player, the default uses service authentication. You can give the serviceId that the sample uses below any value you want; it gives the Lobby service a unique identifier in case you want to differentiate among your service-owned lobbies.

The sample below creates a private lobby, updates the lobby's name, joins the lobby as an impersonated player, and retrieves the lobby.

JavaScript

const { LobbyApi } = require("@unity-services/lobby-1.2");

module.exports = async ({ params, context, logger }) => {
  const lobbyApi = new LobbyApi(context);
  const { serviceId, playerId } = params;

  try {
    // Create a private lobby without any initial players.
    const { data: lobby } = await lobbyApi.createLobby(
      serviceId,
      null, {
        name: "my new lobby name",
        maxPlayers: 4,
        isPrivate: true,
      }
    );

    logger.info(`Created lobby: ${JSON.stringify(lobby)}`);

    // Heartbeat the lobby to keep it active.
    await lobbyApi.heartbeat(lobby.id, serviceId);


    // Update the lobby's name and get the updated lobby.
    const { data: updateResponse } = await lobbyApi.updateLobby(
      lobby.id,
      serviceId,
      null, { name: "my updated lobby name" }
    );

    logger.info(`Lobby updated: ${JSON.stringify(updateResponse)}`);

    // Join the lobby as an impersonated player.
    const { data: joinResponse } = await lobbyApi.joinLobbyById(lobby.id, serviceId, playerId);
    logger.info(`Player joined: ${JSON.stringify(joinResponse)}`);

    // Get and return the lobby.
    const getResponse = await lobbyApi.getLobby(lobby.id, serviceId);
    return getResponse.data;

  } catch (err) {
    logger.error("Error while calling out to Lobby", {"error.message": err.message});
    throw err;
  }
};

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@2.5/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   serviceId: { type: "String", required: true },
//   playerId: { type: "String", required: true },
// };

Use the Leaderboards SDK

Leaderboards allow you to create and manage leaderboards for your game.

Before you use the sample below, you need to create a leaderboard in Leaderboards service.

The sample below shows how you can add a score to a leaderboard, and retrieve the leaderboard scores with a Cloud Code script. It takes in a leaderboardId parameter.

JavaScript

const { LeaderboardsApi } = require("@unity-services/leaderboards-1.1");


module.exports = async ({ params, context, logger }) => {
  const leaderboardsApi = new LeaderboardsApi({accessToken : context.accessToken});
  let result;

  try {
    await leaderboardsApi.addLeaderboardPlayerScore(context.projectId, params.leaderboardId, context.playerId, { score : 20});
    const result = await leaderboardsApi.getLeaderboardScores(context.projectId, params.leaderboardId);
    return result.data;

  } catch (err) {
    logger.error("Error while calling out to Leaderboards", {"error.message": err.message});
    throw err;
  }
};

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@2.5/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   leaderboardId: { type: "String", required: true },
// };

Use the Friends SDK

Friends allows you to create and manage relationships between players in your game. You can use Friends to manage in-game relationships, send and accept friend requests, control presence, and send messages between players. The sample below demonstrates how you can use Friends with Cloud Code to send friend requests, retrieve friends, retrieve a notification token, set and receive presence, and send messages.

To test this sample in the Unity Cloud Dashboard, run the script in two different browser tabs authenticated as two different players. In one tab, run a script with the first player's ID, and run a script with the second player's ID in another tab.

Note: Some of the calls below fail if the requested user hasn't accepted the friend request.

JavaScript

const { RelationshipsApi, PresenceApi, MessagingApi, NotificationsApi } = require("@unity-services/friends-1.0");


module.exports = async ({ params, context, logger }) => {
  // Send friend requests and retrieve friends
  const relationshipsApi = new RelationshipsApi({ accessToken: context.accessToken });

  try {
    const payload = {
      type: "FRIEND_REQUEST",
      members: [{ id: params.playerId }]
    };

    const createRes = await relationshipsApi.createRelationship(true, true, payload);
    logger.info(`New relationship initiated: ${JSON.stringify(createRes.data)}`)
  } catch (err) {
    // The call will fail if the friend request has already been sent
    logger.error("Error while sending a friend request", { "error.message": err.message });
  }

  try {
    const list = await relationshipsApi.getRelationships(10, 0, true, true, ["FRIEND_REQUEST", "FRIEND"]);
    logger.info(`Retrieved relationships: ${JSON.stringify(list.data)}`)
  } catch (err) {
    logger.error("Error while retrieving relationships", { "error.message": err.message });
  }

  // -------------------------------------------------------------------------
  // Retrieve a notification token
  const notificationsApi = new NotificationsApi({ accessToken: context.accessToken });
  try {
    const auth = await notificationsApi.getNotificationsAuth();
    logger.info(`Retrieved notifications subscription token: ${JSON.stringify(auth.data)}`)
  } catch (err) {
    logger.error("Error while retrieving notification subscription token", { "error.message": err.message });
  }
  // -------------------------------------------------------------------------
  // Set and receive presence
  const presenceApi = new PresenceApi({ accessToken: context.accessToken });
  try {
    const newStatus = {
      activity: { // define any payload structure
        location: "In Menu",
      },
      availability: "ONLINE",
    };

    const setPresenceStatus = await presenceApi.setPresence(newStatus);
    logger.info(`Changed player presence status for player ${context.playerId}: ${JSON.stringify(setPresenceStatus.data)}`)
  } catch (err) {
    logger.error("Error while setting a presence status", { "error.message": err.message });
  }

  try {
    // This call will fail if the requested user has not accepted the friend request!
    const presenceStatus = await presenceApi.getPresence(params.playerId);
    logger.info(`Retrieved player presence for player ${params.playerId}: ${JSON.stringify(presenceStatus.data)}`)

  } catch (err) {
    logger.error("Error while retrieving a presence status", { "error.message": err.message });
  }
  // -------------------------------------------------------------------------
  // Send messages
  const messagingApi = new MessagingApi({ accessToken: context.accessToken });

  try {
    const messagePayload = {
      id: params.playerId,
      message: { // define any payload structure
        hello: "world",
        custom: "sending you a message!"
      }
    }

    // This call will fail if the requested user has not accepted the friend request!
    const messageResponse = await messagingApi.message(messagePayload);
    logger.info(`Sent a message to player ${params.playerId}`)

  } catch (err) {
    logger.error("Error while sending a message", { "error.message": err.message });
    throw err;
  }

}

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@2.5/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   playerId: { type: "String", required: true },
// };

Use the Player Names SDK

Player Names allows you to retrieve the player name of a player in your game. You can use this to generate a new player name for a player if they haven't set one yet, or update an existing player name.

JavaScript

const { PlayerNamesApi } = require("@unity-services/player-names-1.0");


module.exports = async ({ params, context, logger }) => {
  const playerNamesApi = new PlayerNamesApi({ accessToken: context.accessToken });

  try {
    const playerData = await playerNamesApi.getName(context.playerId);
    logger.info(`The received player data is ${JSON.stringify(playerData.data)}`);

    const updatedData = await playerNamesApi.updateName(context.playerId, {name: "newCustomName"});
    logger.info(`The updated player data is ${JSON.stringify(updatedData.data)})`);
  } catch (err) {
    logger.error("Error while calling out to Player Names", { "error.message": err.message });
    throw err;
  }

};

Connect with UGS through REST API

You can also connect with the services through their REST API. This is useful if you want to use a service that doesn't have a JavaScript SDK yet.

Authentication

Depending on your use case, you can use either the accessToken or the serviceToken to authenticate the API call. If you use the serviceToken to authenticate UGS Client APIs, ensure the service you want to call supports service tokens. For a list of services and use cases that support service tokens, refer to the Service and access token support documentation.

Note: If the service you want to call provides a Cloud Code JavaScript SDK, you can use the SDK instead so you don't have to call the service API directly. For more information, refer to Cloud Code Services SDKs.

Call the API

The sample below demonstrates how you can call out to the User Generated Content API, create a custom content item, retrieve the items, and delete the item:

Note: Before you can use the sample below, you need to enable the User Generated Content service in your project.

JavaScript

const axios = require("axios-0.21");

module.exports = async ({ params, context, logger }) => {
  const config = {
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${context.accessToken}`
    }
  };


  const baseUrl = `https://ugc.services.api.unity.com/v1/projects/${context.projectId}/environments/${context.environmentId}/content`;

  let result;
  try {
    const payload = {
      name: "a festive treat",
      description: "banasco is a traditional british toast",
      visbility: "Unlisted",
    };

    const postResult = await axios.post(baseUrl, payload, config);
    logger.info(`Created content: ${JSON.stringify(postResult.data)}`);

    const getUrl = `https://ugc.services.api.unity.com/v1/content/search`;
    result = await axios.get(getUrl, config);

    const deleteContentUrl = `${baseUrl}/${postResult.data.content.id}`
    await axios.delete(deleteContentUrl, config);

    return result.data;
  } catch (err) {
    logger.error("Error while calling out to User Generated Content", {"error.message": err.message});
    throw err;
  }
};