Documentation

<Getting started>

#Adding a game

To use the SDK features, you need to add the game to the panel.

#Adding an origin

The origin can be esteemed as a trusted domain that is allowed to use the service. One of advantages is that you can filter bad traffic and temporarily disable origins. You can also mark the origin as test to prevent saved players mixing with production ones. This is important so as not to affect statistics and develop without clearing test accounts.

  1. Go to the Allowed origins section of the selected project.
  2. Click Add origin.
  3. Enter the origin in the format https://my-domain.com/.
    If this is a local development, you must also specify the port http://localhost:8000/.
  4. Optional. You can check the flag Test to test the origin or keep it for development.

#Code installing

To embed the SDK into your game, you need to add the script to the game’s index.html. You can find the script on the project page in the Install Code section.

Sample code:

// install code before body close tag
<script async src="https://gamepush.com/sdk/gamepush.js?projectId=4&publicToken=xT3RpsJMXpKWHPrTWkv3VBeHJKvCBccT&callback=onGPInit"></script>
<script>
    window.onGPInit = (gp) => {
        // ready
    };
</script>

#SDK initialization

After initializing the SDK, the onGPInit function will be called, in which a ready-to-use SDK instance with all managers will be passed as an argument.

Also, for correct interaction with the player, you need to wait for its readiness (while the player is synchronizing with the server).

Sample code:

// Add GamePush script url
<script async src="https://gamepush.com/sdk/gamepush.js?projectId=4&publicToken=xT3RpsJMXpKWHPrTWkv3VBeHJKvCBccT&callback=onGPInit"></script>
<script>
window.onGPInit = async (gp) => {
    // Wait while the player syncs with the server
    await gp.player.ready;
    // Show the ad preloader and wait until it ends
    await gp.ads.showPreloader();
    // Show the sticky banner (then it will update itself)
    gp.ads.showSticky();

    // You can start the game :)
};
</script>

<Project settings>

#Avatar generator

The generated avatar is shown if the user does not have his own avatar.

List of supported generators:

Icotar
Robohash Robots
Robohash Cats
DiceBear Retro
DiceBear Identicon
DiceBear Human
DiceBear Micah
DiceBear Bottts
DiceBear Adventurer
DiceBear Adventurer Neutral
DiceBear Avataaars
DiceBear Big Ears
DiceBear Big Ears Neutral
DiceBear Big Smile
DiceBear Croodles
DiceBear Croodles Neutral
DiceBear Female
DiceBear Gridy
DiceBear Miniavs
DiceBear Open Peeps
DiceBear Personas
DiceBear Pixel Art
DiceBear Pixel Art Neutral

#Community link

You can provide a link to the community on social networks, it will be used by default when calling the community join method: socials.joinCommunity.

For a specific platform, you can set the link in the settings of the platform itself.

#Analytics systems

You can integrate your analytics systems into the SDK to track the players through the single point for all systems.

To start storing data, place the counter ID in the settings.

List of supported analytics systems:

  • Yandex.Metrica
  • Google Analytics

<Common Features>

#Language

SDK can autodetect players language. If the platform provides a language, we use it or pick player-preferred language.

To check language:

// Current language, format ISO 639-1
gp.language

To set language:

// set language, format ISO 639-1 ('ru', 'en', 'fr')
gp.changeLanguage('ru')

All supported languages:

  • English: en
  • Russian: ru
  • French: fr
  • Italian: it
  • German: de
  • Spanish: es
  • Chineese (Simplified): zh
  • Portuguese (Brazil): pt
  • Korean: ko
  • Japanese: ja
  • Turkish: tr

#System Information

Device detection:

/**
* Mobile / desktop device
* @readonly
* @type {boolean}
*/
gp.isMobile

Game Host Information:

/**
* GamePush in development mode
* The checkbox dev at the desired source is responsible for this
* @readonly
* @type {boolean}
*/
gp.isDev

/**
* Game host in trusted sources
* The Allowed Origins section is responsible for this.
* @readonly
* @type {boolean}
*/
gp.isAllowedOrigin

You can use the gp.isAllowedOrigin property to check whether the game has been re-uploaded to another site. In the Allowed Origins section there is a switch - Enable origin protection. It will block all new unknown game hosts. In the list of hosts, you can allow access to the desired hosts.

#Server Time

The SDK provides access to server time.

It is always valid, it cannot be changed through the code and by changing the time of the device. You can use it as a reliable time to protect against cheating.

To get time:

// Read-only current server time in ISO 8601 format
gp.serverTime

// Example of using
// One hour in milliseconds
const HOUR = 60 * 60 * 1000;
// Current time
const currentDate = new Date(gp.serverTime);
// Previous reward time
const lastDate = new Date(gp.player.get("lastRewardTime")
    || currentDate - HOUR);

// If an hour of playing time has passed, we give a reward
// And update the time of last reward
if (currentDate - lastDate > HOUR) {
    gp.player.add("gold", 5000);
    gp.player.set("lastRewardTime", currentDate.toISOString());
}

#Pause

You have access to the pause control mechanism in the game. The SDK has a "Paused" flag, by itself it means nothing, however, you can engage in it if you need to pause and continue the game. Additionally, the SDK will notify you when a pause or resume has been triggered.

Auto pause occurs when:

  • Show ads. Pause at the beginning of the show and resume at the close (not when receiving an award).
  • Minimize game. Pause when switching tabs, minimizing the browser, switching applications, locking the screen, and resuming when the game is visible again.

Pause definition:

/**
* Is on pause
* @readonly
* @type {boolean}
*/
gp.isPaused

Set pause manually:

// Pause game
gp.pause();
// Resume game
gp.resume();

Pause and resume events:

// Paused
gp.on('pause', () => {});
// Resumed
gp.on('resume', () => {});

#Set background image

You can set the background of the game

Background set method:

gp.setBackground({ url: '/bg.png' })

Full features of the method:

gp.setBackground({
    // Image link
    url: '/bg.png',
    // Background image blur, px
    blur: 10,
    // Duration of image change animation, sec
    fade: 5,
})

You can call the method one by one to change the background image, for example:

// Set background
gp.setBackground({ url: '/bg.png', blur: 10, fade: 5 })
// Change to another
gp.setBackground({ url: '/bg2.png', blur: 6, fade: 12 })

#Start game

Game start method, required by some sites to set at the start of the game

The call should depend after the game is loaded:

gp.gameStart();

In Unity and Construct 3 is called automatically

#Gameplay

For some platforms, such as POKI and CrazyGames, you need to call the start and end gameplay methods. They need to be called immediately before the start of the gameplay and immediately after completion. For example, at the beginning of the level and the end of the level.

// Notify when gameplay starts
gp.gameplayStart();

// Notify when finished
gp.gameplayStop();

<Application>

#Information

Basic information about the game.

Available application manager properties:

// Taken from og:title / title
gp.app.title
// Taken from og:description / description
gp.app.description
// Taken from og:image
gp.app.image

// URL on the platform
gp.app.url

#App shortcut

Wll create an application shortcut

Available application manager properties:

// Taken from og:title / title
gp.app.title
// Taken from og:description / description
gp.app.description
// Taken from og:image
gp.app.image

// URL on the platform
gp.app.url

<Platform>

#Information

Information about the active platform.

Available platform manager properties:

// Platform type, e.g. YANDEX, VK
gp.platform.type

// You can check possibility to login
gp.platform.hasIntegratedAuth

// Is allowed to open external links?
gp.platform.isExternalLinksAllowed

All supported platforms:

  • CrazyGames: CRAZY_GAMES
  • GamePix: GAMEPIX
  • GameDistribution: GAME_DISTRIBUTION
  • GameMonetize: GAME_MONETIZE
  • OK Games: OK
  • Poki: POKI
  • SmartMarket: SMARTMARKET
  • VK Games: VK
  • Yandex Games: YANDEX

Also you can get our SDK implementation or native platform SDK:

// Our implementation
gp.platform.getSDK();

// Native platform SDK
gp.platform.getNativeSDK();

#External links

Some platforms explicitly prohibit the use of external links (GameDestribution, OK), some allow any (within the law). Below is a table of platforms.

PlatformAllowed
Yandex.Games❌ Forbidden, but:
1. It is possible to post a link to the community if the community is only talking about the game on Yandex.Games, in other cases it is impossible.
2. Allowed placement of links from the Yandex ecosystem, for example Yandex.Zen or links to other games on the platform.
VK Games✅ Allowed
OK Games❌ Forbidden
CrazyGames✅ Allowed
GameMonetize✅ Allowed
GameDestribution❌ Forbidden
GamePix❌ Forbidden
POKI❌ Forbidden
SmartMarket✅ Allowed

<Advertising>

#Ad Manager

The ad manager rules over the banners on the page. Its responsibility consists in displaying ads, managing auto-refresh and ads frequency timers.

Available ad manager properties:

// Is AdBlock enabled
gp.ads.isAdblockEnabled

// Is the banner available
gp.ads.isStickyAvailable
gp.ads.isFullscreenAvailable
gp.ads.isRewardedAvailable
gp.ads.isPreloaderAvailable

// Is the ads playing now
gp.ads.isStickyPlaying
gp.ads.isFullscreenPlaying
gp.ads.isRewardedPlaying
gp.ads.isPreloaderPlaying

You can subscribe for the following basic events:

// Ads show started
gp.ads.on('start', () => {});
// Ads show ended
gp.ads.on('close', (success) => {});

#Fullscreen

Fullscreen banner or interstitial is pop-up, often fullscreen skippable (sometimes only after a few seconds) advertising. Usually it is shown in transition between levels. Its displaying is prohibited during the gameplay on many platforms. It is allowed to show only in pause between game sessions.

It is also prohibited during the navigation by the VK Games platform. So, we will consider this a bad practice on other platforms too.

Call example:

// Show fullscreen, returns a promise
gp.ads.showFullscreen();

// Showing started
gp.ads.on('fullscreen:start', () => {});
// Showing ended
gp.ads.on('fullscreen:close', (success) => {});

#Preloader

Pleloader is a banner that appears when loading the game. On many platforms, it is implemented through Fullscreen, but is not tied to its timers (except for Yandex.Games).

Displaying is allowed only before the start of the game.

Call example:

// Show preloader, returns a promise
gp.ads.showPreloader();

// Showing started
gp.ads.on('preloader:start', () => {});
// Showing ended
gp.ads.on('preloader:close', (success) => {});

#Rewarded Video

Rewarded Video is a non-skippable video ad that aims to give the player a reward for watching. It is forbidden to show without a reward.

Call example:

// Show rewarded video, returns a promise
gp.ads.showRewardedVideo();

// Asynchronously
const success = await gp.ads.showRewardedVideo();
if (success) {
    gp.player.add('gold', 5000);
}

// Showing started
gp.ads.on('rewarded:start', () => {});
// Showing ended
gp.ads.on('rewarded:close', (success) => {});
// Reward is received
gp.ads.on('rewarded:reward', () => {});

#Sticky Banner

Sticky banner is a fixed bottom banner. It takes ~50-100px (110px VK Direct Games). The banner must not cover the play region.

In the panel, you can customize the auto-refresh frequency. The banner will be updated according to the specified frequency immediately of the start.

Call example:

// Show the sticky banner, then it will auto-update itself
gp.ads.showSticky();
// Refresh the sticky banner, forced refreshing
gp.ads.refreshSticky();
// Close the sticky banner
gp.ads.closeSticky();

// Open the banner
gp.ads.on('sticky:start', () => {});
// The banner appears on the screen
gp.ads.on('sticky:render', () => {});
// The banner updated
gp.ads.on('sticky:refresh', () => {});
// Close the banner
gp.ads.on('sticky:close', () => {});

<Player manager>

#Overview

The manager rules over the player state and his synchronization with the server. After SDK initialization, there starts the process of player’s synchronization with the server. Upon completion, the ready event will be called.

Player manager properties:

// The player is logged in
gp.player.isLoggedIn
// The player uses one of the login methods (cookie, authorization, secret code)
gp.player.hasAnyCredentials
// Player waiting promise
gp.player.ready

The player is initialized automatically; you can wait for readiness:

await gp.player.ready;
// The player is ready

// The player is ready
gp.player.on('ready', () => {});

#Synchronization

After player model changes, they can be sent to the server and saved locally on the device. It is recommended to sync the player after completing a level and receiving rewards, as well as immediately after an important action, for example, purchasing an item.

// Synchronize, returns the promise
gp.player.sync();
// Overwrite the character on the server (local in priority)
gp.player.sync({ override: true });

// The player is synchronized (success === true)
gp.player.on('sync', (success) => {});

#Loading

You can load the player by force from the server (by overwriting the local one).

// Load, returns the promise
gp.player.load();

// The player is loaded (success === true)
gp.player.on('load', (success) => {});

#Login

Show the overlay with login options. This is currently the platform login (if it is supported) and login by secret code.

// Login, returns the promise
gp.player.login();

// The player is logged in (success === true)
gp.player.on('login', (success) => {});

#Fetching the fields

See below what player fields are.
You can fetch the player fields using the following method:

// Fetch fields list, returns the promise
gp.player.fetchFields();

// Fields are fetched (success === true)
gp.player.on('fetchFields', (success) => {});

<Player state>

#Player overview

The player manager is inherited from Player and simply extends it. It includes work with authorization ad synchronization with the server. This part focuses on work with the player state.

Player properties:

// ID
gp.player.id
// Score
gp.player.score
// Name
gp.player.name
// Avatar link
gp.player.avatar
// Stub – is the player default or the data in its model differs from the default
gp.player.isStub
// Player fields
gp.player.fields

Methods for work with the player state

// Get the value of the key field
gp.player.get('gold');
// Set the value of the key field to value, the value is cast to the type
gp.player.set('class', 'warrior');
// Add the value to the key field
gp.player.add('gold', 50);
// Toggle the value of the key field
gp.player.toggle('vip');
// Check if the key field is present and not empty (not 0, '', false, null, undefined)
gp.player.has('vip');

// Return the player state as an object
gp.player.toJSON();
// Set the state from the object
gp.player.fromJSON({
    name: 'test player',
    score: 4522,
    gold: 100,
    vip: false,
    class: 'warrior'
});

// Reset the player state to default
gp.player.reset();
// Remove the player – reset fields and clear ID
gp.player.remove();

Player events

// The player state has changed
gp.player.on('change', () => {})

#Player fields

Player fields are set in the panel, they describe the player state and store the following properties:

/**
* Field name translated into current language
* @type {string}
*/
field.name

/**
* Unique field key
* @type {string}
*/
field.key

/**
* Field type
* @type {'stats' | 'data' | 'flag' | 'service' | 'accounts'}
* stats — numeric fields
* data — string fields
* flags — boolean fields
* service – ID, test, active, remote, etc.
* accounts — vkId, yandexId, okId, etc.
*/
field.type

/**
* Important field for the player
* If you need to decide who will be left, you can display these fields
* @type {boolean}
*/
field.important

/**
* Default field value
* @type {string | number | boolean}
*/
field.default

/**
* Possible variants of values for the fields
* If they are not specified, then the field takes any value
* @type {ModelFieldVariant[]}
*/
field.variants

Field variants can also be set in the panel. Variant properties:

/**
* Variant name translated into current language
* @type {string}
*/
field.name

/**
* Unique value of the variant
* @type {string | number | boolean}
*/
field.value

The list of fields is available directly in the player model.

gp.player.fields

Methods for work with fields:

// Get the field by key
gp.player.getField('gold');
// Get the translated field name by key
gp.player.getFieldName('score');
// Get the translated name of the field variant by the key and its value
gp.player.getFieldVariantName('rank', 2);

<Players>

#Fetch players

You can access other players' data, including achievements and purchases.

All fields marked public will be available to other players.

const result = await gp.players.fetch({
    // Search by player ID
    ids: [66506, 66254],
});

// Response
const { players } = result;

// Player state
players[0].state

// Examples
players[0].state.id
players[0].state.name
players[0].state.score
players[0].state.gold

// Player achievements, see Achievements section
players[0].achievements

// Examples
players[0].achievements[0].id
players[0].achievements[0].createdAt

// Player purchases, see Payments section
players[0].purchases

// Examples
players[0].purchases[0].id
players[0].purchases[0].createdAt

<Leaderboard>

#Open the leaderboard

In order not to implement the displaying of the leaderboard on your side, you can simply open it in the in-game overlay.

gp.leaderboard.open();

By default, the top is displayed, sorted by player's score, but you can customize everything.

gp.leaderboard.open({
    // Sorting by fields from left to right
    orderBy: ['level', 'gold'],
    // DESC sorting – big values first, ASC sorting – small values first
    order: 'DESC',
    // The number of players in the list
    limit: 10,
    // Include the field list to display in the leaderboard, in addition to orderBy
    includeFields: ['rank'],
    // Display only the required fields one by one
    displayFields: ['rank', 'level'],
    /**
    * Whether to show the current player in the list if he is not in the top
    * none — do not show
    * first — show first
    * last — show last
    */
    withMe: 'first'
});

#Get the leaderboard

If there is a need to represent the list yourself, then you can simply get a list of players.

const result = await gp.leaderboard.fetch({
    // Sorting by fields from left to right
    orderBy: ['level', 'gold'],
    // DESC sorting – big values first, ASC sorting – small values first
    order: 'DESC',
    // The number of players in the list
    limit: 10,
    // Include the field list to display in the leaderboard, in addition to orderBy
    includeFields: ['rank'],
    /**
    * Whether to show the current player in the list if he is not in the top
    * none — do not show
    * first — show first
    * last — show last
    */
    withMe: 'first'
});

// Response result
const { players, fields } = result;

#Player rating

You can get the rating position of a player through fetchPlayerRating. This is a crippled version of fetch for the player.

const result = await gp.leaderboard.fetchPlayerRating({
    // Optional, by default the current player ID
    playerId: 754133,
    // Sorting by fields from left to right
    orderBy: ['level', 'gold'],
    // DESC sorting – big values first, ASC sorting – small values first
    order: 'DESC',
    // Include the field list to display in the leaderboard, in addition to orderBy
    includeFields: ['rank']
});

// Response result
const { player, fields } = result;
// Player position
player.position

<Scoped Leaderboard>

#Overview

Scoped leaderboards help separate records into different scopes. All scopes are stored by variant name. The name can be anything.

A few use cases and example tags for saving points:

  • Levels. Custom rating for each level. LEVEL_15, LEVEL_35
  • Time ranges. Leaderbords for today / week / month. DAY_01/31/2022, WEEK_4/2022, MONTH_1/2022
  • Names scopes. Best in location, clan, race, guild. LOC_FOREST, GUILD_NAGIBATORbl, RACE_ORC
  • Events. The best in the event, tournament. EVENT_HALLOWEEN, TOURNAMENT_POKER_1871

Global leaderboard in its structure repeats a scoped table. It can be accessed by a tag in the format global@key1,key2,key3, for example global@score, global@level,exp

#Open the leaderboard

In order not to implement the displaying of the leaderboard on your side, you can simply open it in the in-game overlay.

gp.leaderboard.openScoped();

By default, the top is displayed, sorted by player's score, but you can customize everything.

gp.leaderboard.openScoped({
    // leaderboard ID
    id: 17,
    // leaderboard Tag
    tag: 'LEVELS',
    // Scope name
    variant: 'level_15',
    // Sort DESC / ASC, by default - leaderboard value
    order: 'DESC',
    // Number of players on the list, max - 100, by default - leaderboard value
    limit: 10,
    // Add list of player fields to display in table, in addition to table fields
    includeFields: ['rank'],
    // Display only required fields one by one
    displayFields: ['rank', 'level'],
    /**
    * Whether to show the current player in the list if he is not in the top
    * none — do not show
    * first — show first
    * last — show last
    */
    withMe: 'first'
});

Examples:

// Show leaderboard for the custom level
function openLevelRecords (level) {
    gp.leaderboard.openScoped({
        tag: 'LEVELS',
        variant: `LEVEL_${level}`,
    });
}

// Show top players today
gp.leaderboard.openScoped({
    tag: 'BEST_DAY',
    // 01/31/2022
    variant: new Date().toLocaleString('en', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
    }),
});

#Get the leaderboard

If there is a need to represent the list yourself, then you can simply get a list of players.

const result = await gp.leaderboard.fetchScoped({
    // leaderboard ID
    id: 17,
    // leaderboard Tag
    tag: 'LEVELS',
    // Scope name
    variant: 'level_15',
    // Sort DESC / ASC, by default - leaderboard value
    order: 'DESC',
    // Number of players on the list, max - 100, by default - leaderboard value
    limit: 10,
    // Add list of player fields to display in table, in addition to table fields
    includeFields: ['rank'],
    /**
    * Whether to show the current player in the list if he is not in the top
    * none — do not show
    * first — show first
    * last — show last
    */
    withMe: 'first'
});

// Result
const { leaderboard, players, fields } = result;

#Publish player record

In order for the player to see himself in the table, you need to publish his record for the desired version of the table.

const result = await gp.leaderboard.publishRecord({
    // leaderboard ID
    id: 17,
    // leaderboard Tag
    tag: 'LEVELS',
    // Scope name
    variant: 'level_15',
    // Override the highest record?
    // By default, the record will be updated if it beats the previous one
    override: true,
    // Player record, set the values of the required leaderboard fields
    record: {
        score: myScore,
        level: myLevel,
        exp: myExp,
    },
});

// Result
const { record, fields } = result;

Examples:

// Publish score for the custom level
function saveLevelRecord (level, myScore) {
    gp.leaderboard.publishRecord({
        tag: 'LEVELS',
        variant: `LEVEL_${level}`,
        record: {
            score: myScore
        },
    });
}

// Publish today's score
gp.leaderboard.publishRecord({
    tag: 'BEST_DAY',
    // 01/31/2022
    variant: new Date().toLocaleString('en', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
    }),
    record: {
        score: 15781
    },
});

#Player rating

You can get the rating position of a player through fetchPlayerRatingScoped. This is a crippled version of fetchScoped for the player.

const result = await gp.leaderboard.fetchPlayerRatingScoped({
    // leaderboard ID
    id: 17,
    // leaderboard Tag
    tag: 'LEVELS',
    // Scope name
    variant: 'level_15',
    // Add list of player fields to display in table, in addition to table fields
    includeFields: ['rank']
});

// Result
const { player, fields } = result;
// My player position
player.position

<Achievements>

#Unlock achievement

To unlock player's achievement, you need to pass an ID or Tag of achievement.

// Unlock by id
gp.achievements.unlock({ id: 17541 });

// Unlock by tag
gp.achievements.unlock({ tag: 'WIN_FIRST_BATTLE' });

Unlock achievement events

// Unlock success
gp.achievements.on('unlock', (achievement) => {});

// Unlock error
gp.achievements.on('error:unlock', (error) => {});

Unlock with promises

const result = await gp.achievements.unlock({ id: 17541 });

/**
* Is achievement was success unlocked
* @type {boolean}
*/
result.success

/**
* Achievement data
* @type {Achievement | null}
*/
result.achievement

/**
* Error if unlock failed
* @type {
*     'player_not_found' |
*     'empty_id_or_tag' |
*     'achievement_not_found' |
*     'already_unlocked' |
*      undefined
* }
*/
result.error

#Open achievements list

In order not to implement the displaying of the achievements on your side, you can simply open it in the in-game overlay.

gp.achievements.open();

Open with promises

// wait until closed
await gp.achievements.open();

Achievements overlay events

// On open
gp.achievements.on('open', () => {});

// On close
gp.achievements.on('close', () => {});

#Get achievements list

gp.achievements.fetch();

Fetch with promises

const result = await gp.achievements.fetch();

// Response result
const {
    // Achievements list
    achievements,
    // Achievements groups
    achievementsGroups,
    // Player's unlocked achievements
    playerAchievements
} = result;

Fetch achievements events

// Fetch success
gp.achievements.on('fetch', (result) => {});

// Fetch error
gp.achievements.on('error:fetch', (error) => {});

#Achievement fields

/**
* Achievement ID
* @type {number}
*/
achievement.id

/**
* Optional tag for help in selecting
* You can use it instead of ID
* @type {string}
*/
achievement.tag

/**
* Name translated into current language
* @type {string}
*/
achievement.name

/**
* Description translated into current language
* @type {string}
*/
achievement.description

/**
* Icon src 256x256
* @type {string}
*/
achievement.icon

/**
* Icon src 64x64
* @type {string}
*/
achievement.iconSmall

/**
* Rarity of achievement
* @type {'COMMON' | 'UNCOMMON' | 'RARE' | 'EPIC' | 'LEGENDARY' | 'MYTHIC'}
*/
achievement.rare

#Achievements Group fields

/**
* Achievement group ID
* @type {number}
*/
achievementsGroup.id

/**
* Optional tag for help in selecting
* You can use it instead of ID
* @type {string}
*/
achievementsGroup.tag

/**
* Name translated into current language
* @type {string}
*/
achievementsGroup.name

/**
* Description translated into current language
* @type {string}
*/
achievementsGroup.description

/**
* Array of achievement ID in group
* @type {number[]}
*/
achievementsGroup.achievements

#Player Achievement fields

/**
* Achievement ID
* @type {number}
*/
playerAchievement.achievementId

/**
* Time when the achievement was unlocked
* @type {string}
*/
playerAchievement.createdAt

<Payments>

#Overview

All supported platforms:

  • OK Games
  • VK Games
  • Yandex Games

The shopping list is populated in the Products section of your game in the panel.

// Check payments on paltform
if (gp.payments.isAvailable) {
    // can show / purchase products
}

#Payment Rules

Stick to payments rules.

There are two types of payments: one-time and permanent.

Example of a one-time purchase:

  • Buy 1000 gold
  • Buy chest
  • Restore Lives

One-time purchases must be consumed immediately.

An example of a permanent purchase:

  • Disable ads
  • VIP status
  • Increase x5 reward per level

Constant purchases do not need to be consumed. As soon as the purchase is paid, it will always be visible to the user, until it is used up.

One-time purchase rules:

// 1. Make purchase
await gp.payments.purchase({ tag: 'GOLD_1000' });

// 2. Give a reward
gp.player.add('gold', 1000);

// 3. Save player progess on server
await gp.player.sync();

// 4. Consume purchase
await gp.payments.consume({ tag: 'GOLD_1000' });

Permanent purchase rules:

// 1. Make purchase
await gp.payments.purchase({ tag: 'VIP' });

// 2. Checking for purchase availability when needed
if (gp.payments.has('VIP')) {
    // do something with VIP status
}

#Platform setup

Yandex.Games

Setup

In the Yandex.Games console, fill in the list of products in accordance with the list of products in the GamePush control panel.

Testing

In the Yandex.Games console, you must specify your username as a tester.

VK Direct Games

Setup

You must fill in the "Callback URL" in the Payments section. Set: https://gamepush.com/api/vk/payments

Testing

In the Payments section, specify the tester's account.

OK Games

Setup

You must fill in the "Callback URL" in application settings. Set: https://gamepush.com/api/ok/payments

Testing

Absent. Top up your account balance with a few OKs. Set your purchases at 1 OK. The price can be changed at any time in the panel.

SmartMarket

Setup

You must fill in the "Webhook смартапа" in application settings. Set: https://gamepush.com/api/smartmarket/webhook

Testing

Absent. Payment by card. Set your purchases at 1 RUB. The price can be changed at any time in the panel.

Local testing

On the test domain, a test purchase form that imitates the platform order form is used. You do not need to upload the game to the platform to test it.

#Purchase product

To purchase product, you need to pass an ID or Tag of product.

// Purchase by id
gp.payments.purchase({ id: 17541 });

// Purchase by tag
gp.payments.purchase({ tag: 'GOLD_1000' });

Purchase product events

// Purchase success
gp.payments.on('purchase', ({ product, purchase }) => {});

/**
* Error if purchase failed
* @type {
*     'player_not_found' |
*     'empty_id_or_tag' |
*     'product_not_found' |
*     'purchases_not_alloved_on_platform' |
*      undefined
* }
*/
gp.payments.on('error:purchase', (error) => {});

Purchase with promises

const result = await gp.payments.purchase({ id: 17541 });

/**
* Product data
* @type {Product}
*/
result.product

/**
* Purchase data
* @type {PlayerPurchase}
*/
result.purchase

#Consume product

To consume product, you need to pass an ID or Tag of product.

// Consume by id
gp.payments.consume({ id: 17541 });

// Consume by tag
gp.payments.consume({ tag: 'GOLD_1000' });

Consume product events

// Consume success
gp.payments.on('consume', ({ product, purchase }) => {});

/**
* Error if consume failed
* @type {
*     'player_not_found' |
*     'empty_id_or_tag' |
*     'product_not_found' |
*     'purchases_not_alloved_on_platform' |
*      undefined
* }
*/
gp.payments.on('error:consume', (error) => {});

Consume with promises

const result = await gp.payments.consume({ id: 17541 });

/**
* Product data
* @type {Product}
*/
result.product

/**
* Purchase data
* @type {PlayerPurchase}
*/
result.purchase

#Fetch products list

gp.payments.fetchProducts();

Fetch with promises

const result = await gp.payments.fetchProducts();

// Response result
const {
    // Products list
    products,
    // Player's purchases list
    playerPurchases
} = result;

Fetch products events

// Fetch success
gp.payments.on('fetchProducts', (result) => {});

/**
* Error if fetch failed
* @type {
*     'player_not_found' |
*      undefined
* }
*/
gp.payments.on('error:fetchProducts', (error) => {});

#Product fields

/**
* Product ID
* @type {number}
*/
product.id

/**
* Optional tag for help in selecting
* You can use it instead of ID
* @type {string}
*/
product.tag

/**
* Name translated into current language
* @type {string}
*/
product.name

/**
* Description translated into current language
* @type {string}
*/
product.description

/**
* Icon src 256x256
* @type {string}
*/
product.icon

/**
* Icon src 64x64
* @type {string}
*/
product.iconSmall

/**
* Price
* @type {number}
*/
product.price

/**
* Currency code
* @type {'YAN' | 'OK' | 'VOTE' | 'GP'}
*/
product.currency

/**
* Currency symbol (translated and formatted)
* @example YAN => 1 YAN, 5 ЯНЫ
* @example VOTE => 1 Vote, 5 Votes
* @example OK => 1 OK, 5 OK
* @type {string}
*/
product.currencySymbol

#Player Purchase fields

/**
* Purchase ID
* @type {number}
*/
playerPurchase.productId

/**
* Custom platform purchase payload (e.g. order ID or token)
* @type {Object}
*/
playerPurchase.payload

<Social actions>

#Overview

We suggest using social actions for audience multiplication — share, post and invite friends to the game. Platforms such as VK and OK allow you to use the tools built into the platform. The rest of the platforms will imitate the functionality through the usual link sharing with the ability to add a comment and sometimes pictures.

The list of supported social networks and messengers for sharing:

For better parsing of games by messengers and social networks, we recommend placing Open Graph meta tags in the game. And also fill in the title and description. As a bonus, this can be regarded as a SEO recommendation.

// Fill in the basic information about the game
<title>My awesome game 2</title>
<meta name="og:title" content="My awesome game 2">
<meta name="description" content="There are not enough words to describe the awesomeness of the game">
<meta name="og:description" content="There are not enough words to describe the awesomeness of the game">
<meta name="og:image" content="/img/ogimage.png">

To check that sharing is allowed and supported on the platform:

// Is sharing supported
gp.socials.isSupportsShare

#Share

By default, you can share a game link through share method calling. We will define the link ourselves depending on the platform and substitute the required text, it is taken from the meta tag og:title or tag title.

// Is native sharing supported
gp.socials.isSupportsNativeShare

In platforms without native support for this method, there will be used an overlay with an offer to share on social networks and messengers.

gp.socials.share();

Share with free text adding:

gp.socials.share({
    text: `I tapped the square 73 times in 5 seconds!
        Now I am number 23 in "Fastest Fingers" list.
        Can you beat out me?`
});

Share with an arbitrary link adding:

gp.socials.share({
    url: `${gp.app.url}?invitedBy=${gp.player.id}`
});

Share with an optional picture adding:

gp.socials.share({
    image: 'https://gamepush.com/img/ogimage.png'
});

Fully customizable sharing:

gp.socials.share({
    text: 'Join me in the game "My awesome game 2"',
    url: gp.app.url,
    image: 'https://gamepush.com/img/ogimage.png'
});

#Post

As opposed to share method, the post method involves posting to the player’s friends news feed.

// Is native posting supported
gp.socials.isSupportsNativePosts

On the platforms without native supporting for this method, there will be used an overlay with an offer to share, as in the case of the share method.

The usage logic duplicates the share method.

gp.socials.post();

Fully customizable post:

gp.socials.post({
    text: 'Join me in the game "My awesome game 2"',
    url: gp.app.url,
    image: 'https://gamepush.com/img/ogimage.png'
});

#Invite friends

Shows the player a friends list to whom you can send the invitation.

// Are native invites supported
gp.socials.isSupportsNativeInvite

On the platform without native supporting of this method, there will be used an overlay with the offer to invite friends, as in the case of share and post methods.

The usage logic duplicates the share method.

gp.socials.invite();

Customizable text for some platforms:

gp.socials.invite({
    text: 'Join me in the game "My awesome game 2"',
});

#Join community

Shows the player an overlay with the option to join the community (if the platform allows) or opens a community link in a new tab.

// check is community join is available on platform
gp.socials.canJoinCommunity

// check is native community join is supported
gp.socials.isSupportsNativeCommunityJoin

Join community:

gp.socials.joinCommunity();

<Game variables>

#Overview

Game global variables allow you to control game content without updating the game itself. Each variable can be assigned a value in any available language. It will be loaded in the player's preferred language, or by default taken from English, if in another language the value is empty.

Some examples of using variables:

  • Dynamic values. Any value in the game that you would like to change at any time. For example, for the sake of experiment or correction of the balance of the game.
  • Download Content. Add levels to the game, change maps, add heroes, equipment, story chapters.
  • Translations. Upload files with translations in different languages of the variable and provide instant corrections and additions to translations. This applies not only to text, but also to images, video and audio.
  • Events. You will be able to control the events and, with the help of languages, include the desired events in the desired translation. For example, New Year in Russian, Christmas in English. As well as local holidays.

#Fetch variables

By default, project variables are loaded automatically on the first request to the service. However, if they contain a lot of data and you want to control the download yourself, then you can turn off the Load variables on game boot property and call the load method yourself.

// waiting for the variables
await gp.variables.fetch();

Events:

// successful fetched
gp.variables.on('fetch', () => console.info('variables available'));
// Event on error
gp.variables.on('error:fetch', (error) => console.error(error));

Getting the value of a variable:

// Getting a variable
const dialogs = gp.variables.get("dialogs");

Existence check:

// Checking if a variable exists or contains a value
if (gp.variables.has("newYearEvent")) {
    // mygame.enableNewYearEvent();
}

Variable type check:

// Checking the type of a variable
// data - string
// stats - number
// flag - boolean
// doc_html - text in html format
// image - image link
// file - file link
if (gp.variables.type("lastNews") === "doc_html") {
    $newsContainer.innerHtml = gp.variables.get("lastNews");
}

Example with getting a file from a variable:

const levelsUrl = gp.variables.get("levels");
// Retrieving the content of a file through the file module
const levels = await gp.files.loadContent(levelsUrl);
// myGame.setLevels(JSON.parse(levels));

<Games Collections>

#Overview

With GamePush, you can show the list of games to the player. An overlay will open with a list of games available on the current site.

For the game to be visible on the platform, you need:

  1. Go to the game settings and mark all sites on which the game has already been published. This can be done in the "Published on Platforms" field in the "Public zone" section.
  2. On sites that do not support internal urls - add a public url to the game. This can be done in the "Public game URL" field in the "Project Settings" section.

Some platforms allow the exchange of links only within the platform. Below is a table of link types. External - the game will be shown only if the Public URL is filled in the game.

PlatformLink Type
Yandex.Games✅ Internal
VK Games✅ Internal
OK Games✅ Internal
CrazyGames⚠️ External (Public URL)
GameMonetize⚠️ External (Public URL)
GameDestribution❌ Forbidden
GamePix❌ Forbidden
POKI❌ Forbidden
SmartMarket❌⚠️ No sharing mechanism, can't get game url (waiting for feature)

#Open games collection

Open overlay with all games sorted by newest

gp.gamesCollections.open();

// Or by tag "ALL"
gp.gamesCollections.open({ tag: 'ALL' });

Open overlay with games from special collection by ID or TAG

// By custom TAG
gp.gamesCollections.open({ tag: 'HALLOWEEN_GAMES' });

// By ID
gp.gamesCollections.open({ id: 547 });

Open games collection events

// Overlay opened
gp.gamesCollections.on('open', () => {});

// Overlay closed
gp.gamesCollections.on('close', () => {});

#Fetch games collection

Fetch all games sorted by newest

gp.gamesCollections.fetch();

// Or by tag "ALL"
gp.gamesCollections.fetch({ tag: 'ALL' });

Fetch games from special collection by ID or TAG

// By custom TAG
gp.gamesCollections.fetch({ tag: 'HALLOWEEN_GAMES' });

// By ID
gp.gamesCollections.fetch({ id: 547 });

Fetch with promises

const result = await gp.gamesCollections.fetch();

// Response result
const {
    // Collection ID
    id,
    // Collection Tag
    tag,
    // Collection name
    name,
    // Collection description
    description,
    // Games in collection
    games
} = result;

Fetch games collection events

// Fetch success
gp.gamesCollections.on('fetch', (result) => {});

/**
* Error if fetch failed
* @type {
*     'not_found' |
*      undefined
* }
*/
gp.gamesCollections.on('error:fetch', (error) => {});

#Collection fields

/**
* Collection ID
* @type {number}
*/
collection.id

/**
* Optional tag for help in selecting
* You can use it instead of ID
* @type {string}
*/
collection.tag

/**
* Name translated into current language
* @type {string}
*/
collection.name

/**
* Description translated into current language
* @type {string}
*/
collection.description

/**
* List of games in collections (sorted)
* @type {GamePreview[]}
*/
collection.games

#Game fields

/**
* Game ID
* @type {number}
*/
game.id

/**
* Name translated into current language
* @type {string}
*/
game.name

/**
* Description translated into current language
* @type {string}
*/
game.description

/**
* Icon src 256x256
* @type {string}
*/
game.icon

/**
* URL on platform or public URL
* @type {string}
*/
game.url

<Images>

#Overview

You and your players can upload images to the cloud. On-the-fly resizing, a modern format and a global CDN will allow you to fastly get pictures.

For VK and OK platforms, internal hosting is used, but the image will also be available in the GamePush panel.

By default, image uploads by players are disabled. You can enable it with the Allow players to upload images switch.

Please be aware that uploading images allows unscrupulous players to upload prohibited images. You can always remove these images through the GamePush panel and disable this option at any time.

#Vkontakte platform

The first time the image is uploaded, the player will be asked for the necessary permissions.

No additional developer action is required.

#Odnoklassniki platform

In order to use uploading pictures in Odnoklassniki, you must:

  1. In order to use uploading pictures in Odnoklassniki, you need to: Go to the platform settings in GamePush and specify the game's public key in the "Public Key" field. It is required to work with the Odnoklassniki API.
  2. Go to the game settings in Odnoklassniki and in the section "Permissions" set the permissions "Change photos and photo albums (PHOTO_CONTENT)" to "Optional".

The first time the image is uploaded, the player will be asked for the necessary permissions.

#Upload Image

To upload an image, you need to call the method with the desired file of the image:

/**
 * @type {File} file - desired image file
 */
gp.images.upload({ file: myFile });

Not many game engines provide the ability to work with JavaScript and the DOM API directly.

Therefore, if you do not specify a file, a file selection window will open with the image type (jpeg/png).

The image will then be uploaded to the server.

gp.images.upload();

When uploading, you can tag the image. Additionally, the image is assigned the UGC tag.

gp.images.upload({
    tags: [
        'screenshot',
        'level7',
        'valentinesday',
    ]
});

Upload events

// Image uploaded successfully
gp.images.on('upload', (image) => {});

/**
 * An error occurred while uploading
 * @type {
 *    'player_not_found' - player account has not been created yet
 *    'project_not_found' - did not match the game ID or the game does not exist
 *    'origin_not_allowed' - forbidden origin
 *    'access_not_granted' - the player on the platform did not grant permission
 *    'not_permitted' - it is forbidden to upload images
 *    'internal_error' - something went wrong
 *     other - any error not related to the service
 * }
 */
gp.images.on('error:upload', (error) => {});

#Upload by URL

The method is similar to the previous one, only a URL is used instead of a file. To upload an image, you need to call the method with the desired image URL:

/**
 * @type {string} url - desired image URL
 */
gp.images.uploadUrl({ url: 'https://gamepush.com/img/ogimage.png' });

The method is mostly needed to upload screenshots and graphics via blob and Base64 Data URI.

Game engines allow you to save a screenshot of the canvas and return a blob link or Data URI. You can paste them into the url field and upload the image to the server.

// upload blob
gp.images.uploadUrl({ url: 'blob:https://example.com/123e4567-e89b-12d3-a456-426614174000' });

// upload base64 data URI
gp.images.uploadUrl({ url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAYAAAA4...' });

When uploading, you can tag the image. Additionally, the image is assigned the UGC tag.

gp.images.uploadUrl({
    url: 'https://gamepush.com/img/ogimage.png',
    tags: [
        'screenshot',
        'level7',
        'valentinesday',
    ]
});

Upload events

// Image uploaded successfully
gp.images.on('upload', (image) => {});

/**
 * An error occurred while uploading
 * @type {
 *    'empty_url' - no image URL specified
 *    'player_not_found' - player account has not been created yet
 *    'project_not_found' - did not match the game ID or the game does not exist
 *    'origin_not_allowed' - forbidden origin
 *    'access_not_granted' - the player on the platform did not grant permission
 *    'not_permitted' - it is forbidden to upload images
 *    'internal_error' - something went wrong
 *     other - any error not related to the service
 * }
 */
gp.images.on('error:upload', (error) => {});

#Choose file

You can ask the player to choose a file without uploading it to the server. For example, for applying effects, drawing, preprocessing before loading, or mechanics associated with a picture. The method will return the file and a temporary blob link to it.

const result = await gp.images.chooseFile();

const {
    /**
     * Image file
     * @type {File}
     */
    file,
    /**
     * Temporary image link
     * (only available from the current browser)
     * @type {string}
     */
    tempUrl
} = result;

Later you can upload this link or file to the server:

const { file, tempUrl } = await gp.images.chooseFile();

// file
gp.images.upload({ file });
// temporary link
gp.images.uploadUrl({ url: tempUrl });

File choosing events:

// File choosed
gp.images.on('choose', (result) => {});

/**
 * An error occurred during choosing
* @type {
*     'cancelled' - the file picker window has been closed
*      other - any error not related to the service
* }
 */
gp.images.on('error:choose', (error) => {});

#Image fetch

Fetch images sorted by newest:

const result = await gp.images.fetch();

const {
    /**
     * Image array
     * @type {ImageInfo[]}
     */
    items,
    /**
     * Check to see if you can upload more
     * @type {boolean}
     */
    canLoadMore
} = result;

Fetch images from a special collection by tag. The set of tags searches through AND: if you specify the tags screenshot and valentinesday - images that have both of these tags will be found:

gp.images.fetch({
    tags: ['screenshot', 'valentinesday']
});

Fetch images created by a specific player:

// own images
gp.images.fetch({ playerId: gp.player.id });

// another player
gp.images.fetch({ playerId: 16977410 });

Fetch a certain number of images at a time with the desired offset:

// First 100 images
gp.images.fetch({
    limit: 100,
    offset: 0,
});

// Images 101 to 200
gp.images.fetch({
    limit: 100,
    offset: 100,
});

Fetch events

// Successful fetch
gp.images.on('fetch', (result) => {});

/**
* Error while fetching
* @type {
*    'player_not_found' - player account has not been created yet
*    'project_not_found' - did not match the game ID or the game does not exist
*    'origin_not_allowed' - forbidden origin
*    'internal_error' - something went wrong
*     other - any error not related to the service
* }
*/
gp.images.on('error:fetch', (error) => {});

#Fetch more

Fetch the next batch of images with the desired settings:

// default behavior
const result = await gp.images.fetchMore();

const {
    /**
     * Image array
     * @type {ImageInfo[]}
     */
    items,
    /**
     * Check to see if you can upload more
     * @type {boolean}
     */
    canLoadMore
} = result;

// next batch with screenshot tag,
// only uploaded by my player,
// load 10 items
gp.images.fetchMore({
    tags: ['screenshot'],
    playerId: gp.player.id,
    limit: 10
});

Fetch more events

// Successful fetch
gp.images.on('fetchMore', (result) => {});

/**
* Error while fetching
* @type {
*    'player_not_found' - player account has not been created yet
*    'project_not_found' - did not match the game ID or the game does not exist
*    'origin_not_allowed' - forbidden origin
*    'internal_error' - something went wrong
*     other - any error not related to the service
* }
*/
gp.images.on('error:fetchMore', (error) => {});

#Image fields

/**
* Image ID
* @type {string}
*/
image.id

/**
* ID of the Player who posted the image or 0
* @type {number}
*/
image.playerId

/**
* Source link
* @type {string}
*/
image.src

/**
* Original width
* @type {number}
*/
image.width

/**
* Original height
* @type {number}
*/
image.height

/**
* Tags array
* @type {string[]}
*/
image.tags

#Resize

For GamePush-hosted image links, you can request any image size and it will be transformed.

const url = 'https://cdn.gamepush.com/static/images/97d/ddb/97dddbe1cde68de40bf637349b31f44a.webp';
const url128x128 = gp.images.resize(
    // image link
    url,
    // required width
    128,
    // required height
    128,
    // true - crop to size
    // false - resize without cropping
    true,
);

// https://cdn.gamepush.com/static/128x128crop/images/97d/ddb/97dddbe1cde68de40bf637349b31f44a.webp
gp.player.avatar = url128x128;

<Files>

#Overview

You and your players can upload files to the cloud. Global CDN, gzip and brotli compression and caching will allow you to get files fastly.

By default, file uploads by players are disabled. You can enable it with the Allow players to upload files switch.

Please be aware that downloading files allows unscrupulous players to upload prohibited materials. You can always remove these materials through the GamePush panel and disable this option at any time.

#Upload file

To upload a file, you need to call the method with the desired file:

/**
 * @type {File} file - desired file
 */
gp.files.upload({ file: myFile });

If you do not specify a file, a file selection window will open with the desired file type, by default *.

The file will then be uploaded to the server.

// Select files of any type
gp.files.upload();

// Select only .txt or .json files
gp.files.upload({ accept: '.txt, .json' });

When uploading, you can tag the file. Additionally, the file is assigned the UGC tag.

gp.files.upload({
    tags: [
        'replay',
        'level7',
        'valentinesday',
    ]
});

Upload events

// File uploaded successfully
gp.files.on('upload', (image) => {});

/**
 * An error occurred while uploading
 * @type {
 *    'player_not_found' - player account has not been created yet
 *    'project_not_found' - did not match the game ID or the game does not exist
 *    'origin_not_allowed' - forbidden origin
 *    'not_permitted' - it is forbidden to upload files
 *    'internal_error' - something went wrong
 *     other - any error not related to the service
 * }
 */
gp.files.on('error:upload', (error) => {});

#Upload by URL

The method is similar to the previous one, only a URL is used instead of a file. To upload an file, you need to call the method with the desired file URL:

/**
 * @type {string} url - desired file URL
 */
gp.files.uploadUrl({ url: 'https://mygame.com/myfile.txt' });

The method is mostly needed to upload screenshots and graphics via blob and Base64 Data URI.

Game engines allow you to save a screenshot of the canvas and return a blob link or Data URI. You can paste them into the url field and upload the file to the server.

// upload blob
gp.files.uploadUrl({ url: 'blob:https://example.com/123e4567-e89b-12d3-a456-426614174000' });

// upload base64 data URI
gp.files.uploadUrl({ url: 'data:file/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAYAAAA4...' });

When uploading, you can tag the file. Additionally, the file is assigned the UGC tag.

gp.files.uploadUrl({
    url: 'https://mygame.com/myfile.txt',
    tags: [
        'replay',
        'level7',
        'valentinesday',
    ]
});

Upload events

// File uploaded successfully
gp.files.on('upload', (image) => {});

/**
 * An error occurred while uploading
 * @type {
*     'empty_url' - no file URL specified
 *    'player_not_found' - player account has not been created yet
 *    'project_not_found' - did not match the game ID or the game does not exist
 *    'origin_not_allowed' - forbidden origin
 *    'not_permitted' - it is forbidden to upload files
 *    'internal_error' - something went wrong
 *     other - any error not related to the service
 * }
 */
gp.files.on('error:upload', (error) => {});

#Upload content

The method is similar to the previous ones, only the content is used instead of a file or URL. To upload a file, you need to call the method with the desired file content and file name:

/**
 * @type {string} filename - file name
 * @type {string} content - file content
 */
gp.files.uploadContent({
    filename: 'mysave.txt',
    content: 'Hello world!'
});

The method is mostly needed to load saves, replays or other data in .txt or .json format.

// upload json
gp.files.uploadContent({
    filename: 'replay-1771.json',
    content: JSON.stringify({
        teams: [...],
        timeline: [...]
    }),
});

// upload gamesave with any file name
gp.files.uploadContent({
    filename: 'mysave.mygmsv',
    content: mygame.save(),
});

When uploading, you can tag the file. Additionally, the file is assigned the UGC tag.

gp.files.uploadContent({
    url: 'https://mygame.com/myfile.txt',
    tags: [
        'replay',
        'level7',
        'valentinesday',
    ]
});

Upload events

// File uploaded successfully
gp.files.on('upload', (image) => {});

/**
 * An error occurred while uploading
 * @type {
 *    'empty_filename' - file name not specified
 *    'empty_content' - no file content specified
 *    'player_not_found' - player account has not been created yet
 *    'project_not_found' - did not match the game ID or the game does not exist
 *    'origin_not_allowed' - forbidden origin
 *    'not_permitted' - it is forbidden to upload files
 *    'internal_error' - something went wrong
 *     other - any error not related to the service
 * }
 */
gp.files.on('error:upload', (error) => {});

#Load content

You can load the content of any file from the link in text format:

const content = await gp.files.loadContent('https://mygame.com/myfile.json');

Load events

// content received successfully
gp.files.on('loadContent', (text) => {});

/**
 * An error occurred while receiving
* @type {any error not related to the service}
 */
gp.files.on('error:loadContent', (error) => {});

#Choose file

You can ask the player to choose a file without uploading it to the server. For example, to open a local save, load file content or other mechanics. The method will return the file and a temporary blob link to it.

gp.files.chooseFile();

// with a certain file type
const result = await gp.files.chooseFile('.txt, .mp4');

const {
    /**
     * File
     * @type {File}
     */
    file,
    /**
     * Temporary link to a file
     * (only available from the current browser)
     * @type {string}
     */
    tempUrl
} = result;

Later you can upload this link or file to the server:

const { file, tempUrl } = await gp.files.chooseFile();

// file
gp.files.upload({ file });
// temporary link
gp.files.uploadUrl({ url: tempUrl });

File choosing events:

// File choosed
gp.files.on('choose', (result) => {});

/**
 * An error occurred during choosing
* @type {
*     'cancelled' - the file picker window has been closed
*      other - any error not related to the service
* }
 */
gp.files.on('error:choose', (error) => {});

#Fetch files

Fetch files sorted by newest:

const result = await gp.files.fetch();

const {
    /**
     * Files array
     * @type {FileInfo[]}
     */
    items,
    /**
     * Check to see if you can upload more
     * @type {boolean}
     */
    canLoadMore
} = result;

Fetch files from a special collection by tag. The set of tags searches through AND: if you specify the tags replay and valentinesday - files that have both of these tags will be found:

gp.files.fetch({
    tags: ['replay', 'valentinesday']
});

Fetch files created by a specific player:

// own files
gp.files.fetch({ playerId: gp.player.id });

// another player
gp.files.fetch({ playerId: 16977410 });

Fetch a certain number of files at a time with the desired offset:

// First 100 files
gp.files.fetch({
    limit: 100,
    offset: 0,
});

// Files 101 to 200
gp.files.fetch({
    limit: 100,
    offset: 100,
});

Fetch events

// Successful fetch
gp.files.on('fetch', (result) => {});

/**
* Error while fetching
* @type {
*    'player_not_found' - player account has not been created yet
*    'project_not_found' - did not match the game ID or the game does not exist
*    'origin_not_allowed' - forbidden origin
*    'internal_error' - something went wrong
*     other - any error not related to the service
* }
*/
gp.files.on('error:fetch', (error) => {});

#Fetch more

Fetch the following batch of files with the desired settings:

// default behavior
const result = await gp.files.fetchMore();

const {
    /**
     * Files array
     * @type {FileInfo[]}
     */
    items,
    /**
     * Check to see if you can upload more
     * @type {boolean}
     */
    canLoadMore
} = result;

// next batch with replay tag,
// only uploaded by my player,
// load 10 items
gp.files.fetchMore({
    tags: ['replay'],
    playerId: gp.player.id,
    limit: 10
});

Fetch events

// Successful fetch
gp.files.on('fetchMore', (result) => {});

/**
* Error while fetching
* @type {
*    'player_not_found' - player account has not been created yet
*    'project_not_found' - did not match the game ID or the game does not exist
*    'origin_not_allowed' - forbidden origin
*    'internal_error' - something went wrong
*     other - any error not related to the service
* }
*/
gp.files.on('error:fetchMore', (error) => {});

#File fileds

/**
* File ID
* @type {string}
*/
file.id

/**
* ID of the Player who posted the file or 0
* @type {number}
*/
file.playerId

/**
* File name with extension
* @type {string}
*/
file.name

/**
* Link
* @type {string}
*/
file.src

/**
* File size, Byte
* @type {number}
*/
file.size

/**
* Tags array
* @type {string[]}
*/
file.tags

<Documents>

#Privacy Policy

You can turn on the privacy policy for the game at any time in the documents section of the project.

You can use an auto-generated standard document, taking into account GamePush and the metrics that you have included in the project.

Or you can upload your document, it can be text or HTML.

Then you can open privacy policy from the game by:

gp.documents.open({ type: 'PLAYER_PRIVACY_POLICY' });

Or you can download document and display as you want:

// By default format is HTML
const document = await gp.documents.fetch({
    type: 'PLAYER_PRIVACY_POLICY',
});

// Type of document - PLAYER_PRIVACY_POLICY
document.type
// Content in preferred format
document.content

// Custom format - HTML | RAW | TXT
gp.documents.fetch({
    type: 'PLAYER_PRIVACY_POLICY',
    format: 'TXT'
});

Documents events

// Overlay opened
gp.documents.on('open', () => {});

// Overlay closed
gp.documents.on('close', () => {});

// Fetch
gp.documents.on('fetch', (document) => {});

// Fetch error
gp.documents.on('error:fetch', (error) => {});

<Analytics>

#Page hit

You can use the following method to send page hit or view:

gp.analytics.hit('/my-page/example?query=1');

#Conversion

To send the goal:

// Event/goal name
gp.analytics.goal('LEVEL_START');
// Event/goal name and value
gp.analytics.goal('LEVEL_START', 15);
// Yandex.Metrica converts as LEVEL_START_15

<Fullscreen>

#Overview

The SDK allows to control fullscreen mode.

List of methods:

// Enter fullscreen mode
gp.fullscreen.open();
// Exit fullscreen mode
gp.fullscreen.close();
// Toggle fullscreen mode
gp.fullscreen.toggle();

Events list:

gp.fullscreen.on('open', () => {});
gp.fullscreen.on('close', () => {});
gp.fullscreen.on('change', () => {});

<Developer tools>

#Advertising

It is not possible to test ads on many platforms. We display ad stubs on the test origin so that you know that you have succeeded in triggering an ad. Advertising works in the same way as on production origins. You can consider it the source of a truth and the guarantee of working capacity. As soon as you launch the game, advertising will work through a native platform service.

#Logs

We added messages directly to the game page during development, and also duplicate them into the console. Not all game engines need to work with the console, so it will be problematic to find out if something went wrong. We show a small error/warning message or information.

#Payments

We have added a test purchase form on test origins. GamePush will emit the purchase process as it will be on the platforms.