Developer documentation
Integrate your game with VPlay
Everything needed to publish an HTML5 game, report scores, and enter it into tournaments. Scores are optional — a game runs fine without them — but they are required for leaderboards and tournaments.
Quick start
- Create a developer account.
- Host your game build on any public HTTPS URL that loads in an iframe.
- Submit it from your dashboard with a title, description and category.
- Optional: add the six-line score snippet in Sending a score.
- We review it, then it goes live and starts earning.
You keep hosting the build
Game requirements
HTTPS only
https://. Plain HTTP is rejected at submission — a browser blocks it inside our page anyway.Must run in an iframe
X-Frame-Options: DENY or a frame-ancestors policy that excludes us. This is the single most common reason a submitted game shows a blank player.Self-contained
Responsive
Your rights
No external ads
Engines we routinely accept: Unity WebGL, Godot HTML5, Construct 3, Phaser, PixiJS, Three.js, PlayCanvas, Cocos Creator. Anything that compiles to a web build works.
Sending a score
One postMessage to the parent window. There is no SDK to install, no API key, and no script tag — which means nothing to keep up to date.
// Call this ONCE, when a run genuinely ends.
function submitScore(score) {
window.parent.postMessage(
{ type: 'VPLAY_SCORE', score: Math.floor(score) },
'*'
)
}
// Example: game over
function onGameOver(finalScore) {
submitScore(finalScore)
}type
VPLAY_SCORE.score
Emit on a final result only
The rules
These apply to both destinations — the all-time leaderboard and tournaments. They exist because scores arrive from the player's browser and cannot be trusted on their own.
Integers only
The player must be signed in
Never emit from a nested iframe or a worker
A valid play token must exist
load; it lasts six hours. Without it a score is rejected with no_duration. A document that never fires load can never submit a score.A run must last at least 5 seconds
too_fast otherwise. Measured by the server from when the play token was issued — once per page load, not once per run — so this mainly catches an emit on a splash or menu screen.The score must fit the time played
ceil(effectiveMax × seconds / 60): half the maximum after 30 seconds, all of it after a minute. Exceeding it is rejected as rate_exceeded. This check always applies — with no scoreMax configured it falls back to the platform ceiling of 10,000,000, which still caps a 10-second-old token at roughly 1.67M.Rate limit
Score ceilings and scoreMax
| Destination | Ceiling |
|---|---|
| Leaderboard | A hard 10,000,000, checked first and never raised. When scoreMax is set the lower of the two applies. |
| Tournaments | Your game's scoreMax plus the time-scaled rule above. scoreMax cannot exceed 10,000,000. |
| A score of 0 | Skips the plausibility ceiling, but not the play-token requirement — a 0 with no token is still rejected as no_duration. On a lower-is-better tournament, 0 is the winning score, so it is verified like any other. |
Tell us two numbers before launch
scoreMax from those. Getting it wrong is the one rule that can reject honest players — if a genuine playthrough is ever refused, that is our threshold being wrong, not your game. Send us the run and we will retune it.Tournaments
Timed competitions with entry fees and prizes. No other portal in the field offers them, and any scoring game can be entered. Tournaments apply the same protocol with three differences that matter to you.
Direction is configured per game, not by you
low and a smaller number wins — the entry keeps the lowest score and ranking sorts ascending. Ties break by who reached the score first, so placings are deterministic. Send the raw value and never invert it yourself, or it is inverted twice.Rejections are recorded against the player
Attempts
If your game is lower-is-better
To have a game enabled for tournaments, send us the game and the two scoreMax numbers above. We set supportsScoring and the direction on our side — there is nothing to change in your build.
Host → game messages
The player sends these to your frame. Handling them is optional but strongly recommended — without them a game keeps playing audio behind a modal.
window.addEventListener('message', (e) => {
if (e.data?.type === 'VPLAY_PAUSE') pauseGame()
if (e.data?.type === 'VPLAY_RESUME') resumeGame()
if (e.data?.type === 'VPLAY_MUTE') setMuted(!!e.data.muted)
})Testing
- Confirm your build loads over HTTPS inside a plain local iframe.
- Check the browser console for frame-blocking errors — these are the usual cause of a blank player.
- Verify you emit
VPLAY_SCOREexactly once per finished run, at least five seconds after load, with an integer. - After approval, play the live game signed in and confirm your score appears.
There is no public sandbox yet
Submitting and review
Submit from your dashboard. Every submission is reviewed by a person before it goes live — nothing publishes automatically.
What we check
What we set for you
supportsScoring, score direction and scoreMax.Review time
After approval — what you can change
| Field | Self-serve? | How |
|---|---|---|
| Description, tags, orientation | Yes | Dashboard → your game → Edit |
| The game build itself | Not yet | You host the build, so shipping a new version at the same URL updates the live game immediately — no action needed here. Changing the URL requires us. |
| Thumbnail, title, categories | Not yet | Contact us and we will change it |
Known limitation, being worked on
Revenue share
Your share
Reporting
Payouts are not automated yet
Troubleshooting
| Symptom | Cause |
|---|---|
| Blank player | Your host blocks framing (X-Frame-Options / frame-ancestors), or the URL is not HTTPS. |
| Score never appears | The player is signed out, or you emit before the 5-second minimum, or the value is not an integer. |
| reason: no_duration | No valid play token — usually the iframe never fired load, or the score was sent too early. |
| reason: too_fast | The run was under 5 seconds, measured from when the play token was issued. |
| reason: rate_exceeded | The score is too high for the time played. If it was a genuine run, tell us and we will retune scoreMax. |
| HTTP 429 | More than 12 submissions in a minute. Emit once per finished run. |
| Only the first score of a run counts | The 5-second throttle keeps the FIRST message in each window. Remove mid-run emits. |
| Leaderboard shows my worst run | The game is lower-is-better. Ask us to exclude it from the all-time leaderboard. |
Something unclear, or a rule behaving differently than described here?
Contact the team