Introduction
Known issue (2026-10-02): one gamepad input is received twice. See details and a workaround.
This page is the integration specification for publishers and developers who ship games on TapFun through cloud gaming. Your Windows exe runs on a Windows server in the cloud and is streamed to the player's browser. It is best suited to titles monetized by play time that do not download additional assets.
If your game runs in the browser, see the Web App specification instead.
Getting to a test play
- Submit a zip file containing an executable exe.
- We send you a link to play it in the test environment. Check how it feels and plays.
- To keep testing after the free play time runs out, purchase energy or a title pass. Choose "AmazonPay" as the payment method (Payments in the test environment).
If the test play shows no major issues, continue with the steps below.
Setting up communication
- Email is the default channel.
- If needed, TapFun creates a Slack Connect channel shared by both companies.
- If you cannot join a Slack Connect channel, we will join your company's communication tool instead.
Logging in to the Publisher Console
You can update your exe and change settings in the Publisher Console of the test environment (https://<TEST_HOST>/publisher). Your TapFun contact grants login access, so send us the email addresses of the people who will log in.
Release planning
Once the remaining issues have a clear path to resolution, we agree on the release date and pricing.
Reporting issues during development
When you hit a problem such as "input does not respond" or "unexpected behavior", report it in the communication channel with:
- The app name where the problem reproduces (if the test environment has several copies of the same game, include the app ID or other identifying information)
- The TapFun user account in the test environment where it happened (unless it only happens as a guest)
- Screenshots that show the situation
- A screen recording of the full reproduction steps, if screenshots are not enough
- The steps to reproduce
If the problem comes from intended behavior, both parties may discuss adding or changing a feature.
Requirements for the exe
- Any game engine is fine, as long as it is an exe that runs on Windows. Whether it actually works is checked in the private test environment (a 13 GB title runs fine).
- There is no installation step. The zip is extracted and the exe is launched directly. Bundled runtime installers (Visual C++ Redistributable, OpenAL, etc.) are not run, so put the required DLLs in the same folder as the exe.
- Do not reference files by absolute path from the exe. Paths differ between your PC and the cloud. Use relative paths.
- The game must start without Steam or other store clients. If you use Steamworks, remove it from the build or make the game continue when initialization fails (without Steam, initialization tends to fail or hang at startup). No other SDK, DRM or launcher support is needed.
- If the game picks its language from the Steam setting, TapFun cannot detect it. Set the language through the OS locale, a bundled settings file, or the "exe launch parameters" in the Publisher Console (shared by the whole title).
- We need the exe itself for testing. Testing with a Steam key is not possible.
- Give the zip a name that identifies the title (e.g.
MyGame_Demo.zip).
Adjusting the exe
Before release, adjust the exe as follows.
- Save data must be stored under one of the supported paths. If it already is, tell TapFun the directory. If not, the exe needs to change. The Windows registry cannot be used.
- If the game starts in a window, make it start in full screen.
- If the in-game settings let players toggle full screen, we recommend disabling that option.
- If players can quit the game from inside it (terminating the exe process), we recommend disabling that.
- In-game external links (store pages, credit URLs, etc.) do not work, because they try to open in the cloud rather than in the player's browser. Use openUrl to open external URLs.
- Features that open other Windows apps or folders, such as "Open save folder", do not work. Hide them.
- Remove any on-screen debug display before submitting.
From testing to release
- Test in the test environment: after the Basic auth, log in with a TapFun account you create yourself (login is required to play). You can also launch a version from "このバージョンで起動" (launch this version) in the Publisher Console version list.
- Final check in production: access to the production Publisher Console is granted separately. Before release, check the private app using Test play in production.
- Publish: TapFun publishes the title. The publish time can be set between 10:00 and 17:00 JST.
- From receiving the exe to release takes about one month (including preparing the cloud environment and testing and adjusting the cloud version).
- The Publisher Console has no roles. Everyone who can log in can do the same things. To add people, send their email addresses to TapFun.
Debugging
Add one of these parameters to the game page URL to see the client API traffic.
| Parameter | Effect |
|---|---|
?debugLog=1 |
Shows a log area over the game screen with the client API requests TapFun received (including consoleLog). |
?verbose=1 |
Writes detailed logs to the browser's developer tools console, including the data of consoleLog. |
Player support
- TapFun handles inquiries about the TapFun platform (login, payment, the game not starting, etc.). When needed, we share them with you along with the player ID.
- Inquiries about the game content are directed to your support contact. Prepare a contact point (such as a form) and let TapFun know.
FAQ
Q. There is no sound until I click the game screen. A. This is expected behavior caused by browser restrictions.
Q. The gamepad does not respond. A. It responds after you click the game screen. It sometimes works without a click, but as a rule, click the game screen first.
Q. On iPhone, the sound stops after switching back from another app. A. This can happen in any title, though not every time. With the sound off, go back to the home screen once and return to the browser; the sound comes back.
Environments
Hostnames
| TapFun environment | Hostname | Basic auth on the web UI |
|---|---|---|
| Test | Ask your TapFun contact (written as <TEST_HOST> in this document) |
Yes (ask your TapFun contact for the user name and password) |
| Production | https://tapfun.co.jp |
No |
The test environment hostname and its Basic auth user name and password are confidential and are not included in this document. Ask your TapFun contact for them. Replace <TEST_HOST> in code examples with the test environment hostname. Do not share them outside your company or anywhere public (public repositories, public channels, and so on).
Payments in the test environment
To buy energy or a title pass in the test environment, use one of the following.
- AmazonPay: takes you to the "Multi-Payment Service test environment". Select "決済する" (Pay) to complete the payment.
- Test credit card: number
4111111111111111, any future expiry month/year, any 3-digit security code.
Test play in production
To access an app before release, enable maintenance mode in the Publisher Console's basic settings and enter the tester's email address in "Maintenance exception email addresses".
For tests in production that involve purchases, TapFun registers a test-play account for each app. The account receives TapFun credit usable only in that app. Purchases by test-play accounts are cancelled immediately and offset against sales.
Publisher Console
Basic settings
| Field | Description |
|---|---|
| App ID | Internal ID of the app. |
| name | Internal name. |
| apiKey | API key for calling the Web API. |
| Bearer token | Value of Authorization: Bearer when calling the Web API (format: <AppID>_<apiKey>). |
| Maintenance mode | Puts the app into maintenance mode when enabled. |
| Maintenance exception email addresses | Users with these email addresses can play during maintenance (one per line). For an unreleased (private) app, enabling maintenance mode also lets these accounts access it. |
| folder | Folder name inside the uploaded zip. |
| exe | File name of the exe to run inside the zip. |
| exe launch parameters | Command-line options. Example: --debug=on --verbose |
| Desktop width / height | Desktop resolution on the cloud rendering server. The default is 1920x1080 (width 720-1920, height 480-1080). |
| Save data directory | Directory for save data. Every file in it is saved and restored as save data, so put nothing but save data there. Contact us to change it (User data save and restore). |
| Gamepad support | Enable for titles playable with a gamepad. When enabled, the title can also be played from smartphones and tablets (Supported input). |
| Virtual pad default | Whether the on-screen virtual pad is shown from the start on smartphones and tablets. Disable it for titles played by tapping only. |
| Pointer device support | Enable for titles playable with a mouse. |
| Always show mouse cursor | For games that need the mouse cursor to be captured. |
Details (introduction page)
The "詳細情報" (details) tab edits what is shown on the game's introduction page on TapFun.
| Field | Description |
|---|---|
| Icon image | The game's icon. Recommended size: 512x512 (square). |
| 2:1 image | A wide image used in listings and on the introduction page. Recommended size: 1920x960. |
| Loading image PC / SP | Images shown while the game starts. Recommended size: 600x520 for PC, 300x260 for smartphones. |
| Controls guide images | Optional images explaining the controls, which players can open from the TapFun screen while playing. |
| Screenshot images | Screenshots shown on the introduction page. |
| Game title | The game name shown on the introduction page and elsewhere. |
| Developer / Publisher | Developer and publisher names shown on the introduction page. |
| Game description | Body text of the introduction page, in Markdown. |
| Third-party EULA | License terms shown on the introduction page, such as third-party licenses included in the game. |
Drag controls guide images and screenshots to reorder them. To delete one, click it to mark it for deletion, then press "追加アップロード & 順序を保存" (upload and save order) to apply the change.
Sales settings
Sales settings are display-only. Contact TapFun to change anything other than DLC.
| Field | Description |
|---|---|
| お試し分数 (trial minutes) | Free play time per session. One session recovers 12 hours after use. |
| パス未所有時 1 エナジープレイ分数 (minutes per energy without pass) | Play time one energy gives a player without the title pass. |
| タイトル利用パス価格 (title pass price) | Price of the title pass. |
| タイトル利用パス購入後無料時間 (free hours after pass purchase) | Free play time after buying the title pass. |
| タイトルパス所有時 1 エナジープレイ分数 (minutes per energy with pass) | Play time one energy gives a player with the title pass. |
| DLC (YAML) | Definition of DLC. |
DLC
- Manage the DLC sold on TapFun's web pages in the Publisher Console.
- When a title pass is on sale, DLC is sold both as a "title pass bundle" and as standalone DLC for owners of the standard edition.
- Describe DLC in YAML. You can register several (there is no limit, but contact us before registering more than one).
- If the player owns DLC, the exe is launched with
--dlcs code,code,...(Launch parameters).
- name: Digital Deluxe Upgrade
code: digital_deluxe_upgrade
price: 3270
bundlePrice: 2000
archived: false
description: |
Upgrades the standard edition to the Digital Deluxe edition.
- Collaboration outfits (6)
- "Photo frame" camera feature (6 types)| Key | Type | Description |
|---|---|---|
name |
string | Product name. |
code |
string | DLC identifier. This value is passed in --dlcs. |
price |
number | Price of the standalone DLC. |
bundlePrice |
number | Price when sold bundled with the title pass. The bundle price is the title pass price plus this amount. |
archived |
bool | When true, hidden as additional content (and as a bundle). |
description |
string | Description shown to owners of the standard edition. Line breaks are kept. |
Steam
For titles with a Steam store page, a Steam store purchase widget is shown on the play screen at PC width.
| Field | Description |
|---|---|
| Steam AppID | The Steam app ID to show. Contact TapFun to change it. |
| Tracking parameters (utm) | utm_source / utm_medium / utm_campaign / utm_term / utm_content added to links to the Steam store (up to 100 characters each). Steam only carries over these five. |
Updating the binary
- You can upload up to 5 versions, including the one in use. Versions other than the one in use can be deleted.
- After uploading, select "First Release" in the version list to release it (Sessions during a release).
- You can launch the game with any uploaded version.
- You cannot upload another version until the newly uploaded one has been released.
- The steps are the same for the test and production environments.
- The version set as "First Release" is the one players launch. To roll back, set an earlier version as "First Release".
- After uploading, processing takes a while before the version can be used. As a guide, 1-5 GB takes up to 30 minutes. Do not upload multiple versions at the same time.
- An upload can end in the "failed" state. If deleting and retrying does not help, contact TapFun.
Sessions during a release
| Situation | Behavior |
|---|---|
| During and right after upload | Players are not affected. Players only launch the version set as "First Release". |
| When you press "First Release" | The new version is used by sessions started after the release. TapFun does not end sessions that are already running. |
| Running sessions | Sessions started before the release continue as they are. To play the new version, a player has to quit and launch the game again. |
| Save data | Kept per TapFun account and carried over when the version changes. Make sure old and new versions can read the same save data. |
| Rolling back | Press "Revert Version" on the version to go back to. It works like "First Release": it applies to sessions started afterwards. |
| Checking before release | "このバージョンで起動" (launch this version) in the version list launches an unreleased version in a new session (other players are not affected). |
The "バイナリ" (binary) tab:
- zip structure: the zip must contain a folder named after "folder", with the "exe" inside it (
<folder>/<exe>). - When you cannot upload: if the screen shows "失敗したバージョンを削除してください" (delete the failed version), "不要なバージョンを削除してください" (delete unneeded versions; the limit of 5 is reached) or "First Release 待ちのバージョンがあります" (a version is waiting for First Release), follow that instruction.
- ApplicationVersions: list of uploaded versions. For each version you can use "First Release" (release), "Revert Version" (go back to an earlier version), "削除" (delete) and "このバージョンで起動" (launch this version).
- Tools → Save data download: enter a TapFun user ID to download that player's save data (do this a few minutes after the game exits).
Launching the game
"アプリページ" (app page) at the top of the app screen launches the game with the options below (Debugging). Unreleased apps show "非公開状態" (private).
| Option | Description |
|---|---|
| 新規セッション (new session) | Starts the game in a new session instead of reusing the existing one. |
| パフォーマンスモニタ (performance monitor) | Shows a performance monitor on the PC play screen. |
| ログ表示 (show log) | Shows consoleLog API and other logs on screen (same as ?debugLog=1). |
| verbose | Increases the logs written to the browser console (same as ?verbose=1). |
Other tabs
| Tab | Contents |
|---|---|
| 月別売上 (monthly sales) | Daily purchase counts, sales and cancellations, with a breakdown by sales category (Platform / Publisher). |
| CustomEvents | Log of requests sent through the client API (custom_event). |
| Leaderboards | Leaderboards and their entries. |
| Times | Per-player play time (free, trial, energy, total) and title pass purchase times. |
| 紹介ページ (introduction page) | Opens the game's introduction page on TapFun in a new tab. |
Cloud runtime
How it works (important)
TapFun runs the game on a server and the player controls it remotely from the browser (remote desktop model). The cloud gaming platform is built on Tencent CAR.
- The exe runs on a Windows server in the cloud (Windows Server 2019 / 2022).
- The desktop graphics and audio output are captured and streamed to a canvas element in the browser (tapfun.co.jp). Start the game in full screen.
- Mouse and keyboard input inside the canvas is sent to the exe on the Windows server.
- There is no limit on game size.
- Maximum resolution is 1920x1080 (the default) and maximum refresh rate is 60 fps. Change the resolution with "Desktop width / height" in the Publisher Console.
- Video formats playable through Windows Media Foundation are H.264 / H.265. VP9 is not supported.
- Additional asset downloads are normally not possible (they would be stored as per-user data; contact us depending on size).
- Contact us if you want to use other Tencent CAR features or APIs.
Server specs
| Plan | CPU | Memory | GPU performance | GPU | FurMark 2 1080p score | Roughly equivalent to |
|---|---|---|---|---|---|---|
| S | 4 cores | 8 GB | 2TF SP/30T | Tesla T4 / GRID T4-8Q, etc. | 2600-3200 | GTX 1650 |
| M | 4 cores | 16 GB | 4TF SP/30T | Tesla T4 / GRID T4-8Q, etc. | 2600-3200 | RTX 3050-3060 |
Network requirements
Requirements when your game servers communicate with the game runtime environment.
- Inbound: allow UDP 8000 and 60000-60100 from all sources.
- If you cannot allow all sources, in the test environment it works if you allow only these IPs:
124.156.222.35,124.156.224.128,43.130.251.233,43.133.176.140,43.133.180.230,43.133.218.250,43.153.145.189,43.153.153.36,43.153.155.47,43.153.157.78,43.163.247.41,150.109.195.27 - Source IP: the source IP of outbound HTTP and other traffic from the servers running the exe is not disclosed.
User data save and restore
User data is restored automatically at launch and saved automatically at exit.
- The save/restore directory is configurable per title, and only one directory is allowed. We recommend keeping the total size within 100 MB.
- Save data is kept per TapFun account and carries over when you update the build.
- Data is saved to cloud storage after the game exits. When downloading save data from the Publisher Console, wait a few minutes after the game exits.
- Supported paths (under one of these):
C:\Users\%UserName%\AppData\Local\<any directory>C:\Users\%UserName%\AppData\LocalLow\<any directory>C:\Users\%UserName%\AppData\Roaming\<any directory><root of the uploaded zip>\<any directory>
- Files placed directly in the exe's folder are not saved. Create a folder at least one level below the exe's folder and save there.
- Put nothing but save data in the save data directory. Every file in it is saved and restored as save data. If it contains DLLs, assets or other files, the old saved copies are restored instead of the latest files from your uploaded zip, which causes bugs.
%UserName%is the Windows login user name. It is fairly stable but essentially random, so only rely on it within a single session.- Tell TapFun the directory name you use. Data written to the registry is not restored. Unity's
PlayerPrefsis stored in the registry on Windows, so switch to saving to files. - There is no feature to reset save data. To check first-time-only behavior (tutorials, etc.), use another TapFun account.
- Saving does not work correctly until the save directory has been configured. Test save behavior after it is configured.
Examples of save directories:
| Engine, etc. | Example |
|---|---|
Unity (Application.persistentDataPath) |
C:\Users\%UserName%\AppData\LocalLow\<CompanyName>\<ProductName> |
| Godot 4 | C:\Users\%UserName%\AppData\Roaming\Godot\app_userdata\<ProjectName> |
| Electron (including localStorage) | C:\Users\%UserName%\AppData\Roaming\<AppName> |
| Action Game Maker | C:\Users\%UserName%\AppData\Local\<FolderName>\save |
Supported input
Player input arrives at Windows in the cloud as follows.
| Player input | What the exe sees |
|---|---|
| Keyboard (PC) | Standard Windows keyboard input |
| Mouse (PC) | Standard Windows mouse input. Available for titles with "Pointer device support" enabled in the Publisher Console |
| Touch (smartphone / tablet) | Mouse clicks |
| Gamepad (PC) / virtual pad (smartphone / tablet) | A virtual gamepad |
- Titles with "Gamepad support" enabled in the Publisher Console can be played from smartphones and tablets (iOS / Android). Players use the on-screen virtual pad (sticks, D-pad, buttons and an Esc key button) or tap. For titles played by tapping only, enable "Gamepad support" and disable "Virtual pad default".
- Virtual pad input arrives as gamepad input, so no extra implementation is needed in the game (in Unreal Engine, the engine's gamepad settings work as-is).
- Keyboard input cannot be sent from smartphones and tablets. If a scene can only be advanced with a key (such as "Press A to start"), players on smartphones and tablets get stuck. Make it work with taps or a gamepad too.
- There is no virtual mouse cursor on touch devices. A touch arrives as a mouse click at that position. Additional fingers (multi-touch) may not be distinguished.
- Gamepad vibration is not supported.
- Gamepads and the virtual pad respond after the game screen has been clicked (tapped) once (FAQ).
Gamepad
In most cases gamepads work as-is.
Known issue (2026-10-02): one gamepad input is received twice
- Symptom: when a gamepad connects, two virtual controllers (Xbox 360 compatible and DualShock 4 compatible) are created on Windows in the cloud, and every input reaches both. Games that read all connected controllers (Unity Input System, SDL, Windows.Gaming.Input RawGameController, etc.) receive each press twice (e.g. the character moves two steps, a "pick up" button picks up and immediately drops). Games that read only XInput are not affected.
- Affected: both physical gamepads on PC and the virtual pad on smartphones and tablets.
- Cause and status: the issue is in the cloud gaming platform (Tencent CAR). TapFun has requested a fix and will update this page when it is fixed.
- What to do: until it is fixed, consider the workaround below.
Workaround
In your game, accept input from only one gamepad.
- Make the first gamepad that sends input (a button or a stick) the "active" one, and ignore input from all other gamepads.
- When the active gamepad disconnects, clear it and make the next gamepad that sends input the new active one.
- In case a player switches controllers on a regular PC, switch the active gamepad to another one only when the active one has had no input for about one second.
The two controllers in the cloud receive the same input a few milliseconds apart, so the controls behave the same whichever becomes active. Because this does not depend on the controller type or name, it keeps working on a regular PC and after the platform is fixed and only one controller remains.
Launch parameters
Only for apps that integrate with the TapFun API, the exe is launched with --tapfun-user-id and other parameters. They are not added by default. Contact your TapFun contact if you need them (we enable it in the admin console). Otherwise the exe receives only the "exe launch parameters" set in the Publisher Console.
C:\Apps\%UserName%\TapFunDebugConsoleApp.exe --type car --port 10100 --bearer-token 123_AAABBBCCC --api-host <TEST_HOST> --sig-key FFFGGGHHH --is-paid-timer 0 --is-sp 0 --tapfun-user-id PLYR01HE2R3JV6Y2NEGRMS4KZQB861DBG --dlcs delux_upgrade,special_upgrade --username=%E3%81%82%E3%81%84| Parameter | Description |
|---|---|
--type |
Always car. |
--port |
UDP port for the CAR Data Channel. Normally fixed at 10100. |
--bearer-token |
Bearer token for the Web API and for sending client API requests. |
--api-host |
Hostname of the Web API (e.g. tapfun.co.jp in production). |
--sig-key |
Signing key (sigKey) from the Publisher Console. |
--tapfun-user-id |
The TapFun user ID. It is not secret, but do not display it on screen. |
--dlcs |
Comma-separated code values of the DLC the player owns. |
--username |
User name. URL-encoded UTF-8, 1-12 characters after decoding, no emoji. |
--is-paid-timer |
1: paid-timer user / 0: free-timer user |
--is-sp |
1: smartphone user / 0: other |
Client API
APIs for communication between your exe and TapFun in the player's browser. Data you send passes through the player's browser, so never include secrets.
| API | Summary |
|---|---|
| openUrl | Open a URL in a new tab |
| inputTextSingleLine | Single-line text input modal |
| inputTextMultiLine | Multi-line text input modal |
| inputTextMultiLineChunkText | Send the initial multi-line text in chunks |
| copyText | Modal for copying text to the clipboard |
| showText | Text modal |
| getPlayerEnvironment | Get the player's environment |
| launchSuccessNotice | Notify successful launch |
| consoleLog | Show a log message |
| clientStatus | Client status notifications (sent automatically) |
Transport
Requests are HTTP POSTs to the TapFun API. Responses arrive over UDP that the exe listens on. Sending requires --tapfun-user-id and --bearer-token (Launch parameters).
Sending
| Item | Value |
|---|---|
| Endpoint | https://<environment hostname>/api/v1/custom_event?userId=<TapFun user ID> |
| Method | HTTP POST |
| Content-Type | application/x-www-form-urlencoded |
| Authentication | Authorization: Bearer <Bearer token> (e.g. Authorization: Bearer 123_NWU0MjlkY2ViYTVkOTdiYjIw) |
| Encoding | UTF-8 |
| Max size | 10 MB |
| Delivery to the browser | WebSocket |
Receiving
| Item | Value |
|---|---|
| Method | CAR Data Channel. Listen on local UDP port 10100 (--port) |
| Encoding | UTF-8 |
| Format | Query string (e.g. from=getPlayerEnvironment&isSP=0). Spaces are encoded as %20. |
Sample Unity project
- GitHub: https://github.com/tapfuncojp/debug-console-app (send us your GitHub account name for access)
Sending sample (Unity / C#):
public IEnumerator SendCustomEventToCar(string userId, WWWForm formData)
{
// config.apiHost = --api-host, config.bearerToken = --bearer-token
string url = $"https://{config.apiHost}/api/v1/custom_event?userId={userId}";
using (UnityWebRequest www = UnityWebRequest.Post(url, formData))
{
www.SetRequestHeader("Authorization", $"Bearer {config.bearerToken}");
yield return www.SendWebRequest();
}
}Receiving sample (Unity / C#):
private UdpClient udpServer;
private IPEndPoint udpEndPoint;
private Thread serverThread;
private int udpServerPort = 10100; // --port
private bool isDataChannelReceiveLoopRunning = false;
public void CarHandleDataChannel()
{
try
{
udpEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), udpServerPort);
udpServer = new UdpClient(udpEndPoint);
isDataChannelReceiveLoopRunning = true;
serverThread = new Thread(CarDataChannelReceiveLoop);
serverThread.IsBackground = true;
serverThread.Start();
}
catch (Exception e)
{
Debug.LogError($"Failed to start UDP server: {e.Message}");
}
}
private void CarDataChannelReceiveLoop()
{
while (isDataChannelReceiveLoopRunning)
{
try
{
byte[] receivedBytes = udpServer.Receive(ref udpEndPoint);
string receivedMessage = Encoding.UTF8.GetString(receivedBytes); // query string
byte[] responseBytes = Encoding.UTF8.GetBytes("OK");
udpServer.Send(responseBytes, responseBytes.Length, udpEndPoint);
lock (queueLock)
{
receivedMessagesQueue.Enqueue(receivedMessage);
}
}
catch (Exception e)
{
Debug.LogError($"Unexpected error in receive loop: {e.Message}");
Thread.Sleep(1000); // wait a little before continuing after an unexpected error
}
}
}openUrl
Opens a URL in a new tab.
| Parameter | Required | Description |
|---|---|---|
req |
✓ | openUrl (fixed) |
url |
✓ | URL to open in a new tab |
Response: none
inputTextSingleLine
Shows a single-line text input modal.
| Parameter | Required | Description |
|---|---|---|
req |
✓ | inputTextSingleLine (fixed) |
label |
Label to identify the response | |
title |
Modal title | |
placeholder |
Placeholder text | |
text |
Default text (max 128 characters) | |
submit |
Submit button label | |
cancel |
Cancel button label | |
position |
Position. Centered by default; bottom for the bottom |
|
maxlength |
Max characters (default 128, max 128) | |
pattern |
Value for the HTML input pattern attribute |
|
invalid |
Message shown when the input does not match pattern (passed to setCustomValidity) |
Response:
| Key | Submitted | Cancelled |
|---|---|---|
from |
inputTextSingleLine |
inputTextSingleLine |
label |
The request's label |
The request's label |
result |
submit |
cancel |
text |
Entered text (max 128 characters) | Entered text |
inputTextMultiLine
Shows a multi-line text input modal.
| Parameter | Required | Description |
|---|---|---|
req |
✓ | inputTextMultiLine (fixed) |
label |
Label to identify the response | |
title |
Modal title | |
placeholder |
Placeholder text | |
submit |
Submit button label | |
cancel |
Cancel button label | |
position |
Position. Centered by default; bottom for the bottom |
|
maxlength |
Max characters (default 128, max 10000; a line break counts as 1) | |
text |
Default text | |
end |
Final sequence number of the chunks sent with inputTextMultiLineChunkText |
Response: input longer than 128 characters is split into a sequence of 128-character chunks and delivered in several notifications.
| Key | Submitted | Cancelled |
|---|---|---|
from |
inputTextMultiLine |
inputTextMultiLine |
label |
The request's label |
The request's label |
result |
submit |
cancel |
text |
Entered text (max 128 characters) | — |
seq |
Sequence number (1 to end) |
— |
end |
Final sequence number | — |
inputTextMultiLineChunkText
Sends the initial text for inputTextMultiLine in chunks ahead of time. After sending all chunks, send inputTextMultiLine with end; the chunks are joined and the modal opens. Use this to send long text in parts.
| Parameter | Required | Description |
|---|---|---|
req |
✓ | inputTextMultiLineChunkText (fixed) |
text |
✓ | Text |
seq |
✓ | Sequence number (max 100) |
Response: none
copyText
Shows a modal that lets the player copy text to the clipboard.
| Parameter | Required | Description |
|---|---|---|
req |
✓ | copyText (fixed) |
title |
Modal title | |
text |
✓ | Text to copy |
Response: none
showText
Shows a text modal.
| Parameter | Required | Description |
|---|---|---|
req |
✓ | showText (fixed) |
text |
✓ | Text to show |
Response: none
getPlayerEnvironment
Gets the player's environment.
| Parameter | Required | Description |
|---|---|---|
req |
✓ | getPlayerEnvironment (fixed) |
Response:
| Key | Description |
|---|---|
from |
getPlayerEnvironment |
userAgent |
The browser's navigator.userAgent |
isSP |
1: smart device (iPhone / iPad / Android) / 0: other |
authenticated |
1: logged in / 0: guest |
isPaidTimer |
1: player has paid play time remaining (1 second or more) / 0: otherwise |
launchSuccessNotice
Notifies the platform that the game launched successfully. Sending it dismisses the "Starting streaming" dialog sooner.
For apps that wait for this notice, mouse input is blocked until the notice arrives or streaming has continued past a threshold. This avoids the process hanging on mouse input before it has finished starting. The timer does not run while input is blocked. We tell you in advance whether your app is one of them.
| Parameter | Required | Description |
|---|---|---|
req |
✓ | launchSuccessNotice (fixed) |
Response: none
consoleLog
Outputs a log line. Add ?verbose=1 to the game page URL to see it in the browser's developer tools console, or ?debugLog=1 to see it in the on-screen log area (Debugging).
| Parameter | Required | Description |
|---|---|---|
req |
✓ | consoleLog (fixed) |
data |
✓ | A string or JSON string. If JSON.parse() succeeds, it is shown in the console as a JSON object. |
Response: none
clientStatus
Notifies changes in client state (no request needed, sent automatically).
result |
When | Extra keys |
|---|---|---|
lastTimeRemain |
Remaining play time reached 90 seconds | second: seconds (90) |
purchaseSelectModalOpen |
The play time purchase modal was shown | — |
lastTimeInfoModalOpen |
The remaining time modal was shown | — |
manualOpen |
The controls guide was shown | — |
isPaidTimer |
The player became a paid-timer user | — |
isFreeTimer |
The player became a free-timer user | — |
Every notification includes req=clientStatus. Example: req=clientStatus&result=lastTimeRemain&second=90
Web API
HTTP APIs called from your servers or from the exe.
Common specification
| Item | Value |
|---|---|
| Base URL | https://<environment hostname>/api/v1 (Hostnames) |
| Method | HTTP GET / POST |
| Encoding | UTF-8 |
| Request format | URL path, query string, POST data (application/x-www-form-urlencoded unless stated otherwise) |
| Response format | JSON. An empty array when an array result has no items. HTTP status is 200 unless stated otherwise |
| Date/time | UTC, yyyy-mm-ddThh:mm:ss.sssZ |
Authentication
Authenticate with the HTTP header Authorization: Bearer <AppID>_<APIKey> (the Bearer token in the Publisher Console).
Authorization: Bearer 123_NWU0MjlkY2ViYTVkOTdiYjIwNThmZTkxMDMzYWM4Y2JmNGUyMTQ0NgOn authentication failure the API returns HTTP 403 with:
{"error":"no authorization"}POST /api/v1/photos
Saves an image to TapFun photo storage. Players can view and download images saved from games on TapFun. Authentication: required.
| Item | Value |
|---|---|
| Content-Type | multipart/form-data |
Query string userId |
TapFun user ID (required) |
POST data file |
PNG / JPEG / WebP image binary (required). The part's Content-Disposition must have a filename (any value), e.g. form-data; name="file"; filename="sample.jpg" |
Limits:
- Max images stored: 1,000 (the oldest are deleted automatically beyond that)
- Max size: 10 MB per image (no overall limit)
- Max width/height: 12,000 pixels
- Max image size: 100 megapixels (e.g. 10,000 × 10,000)
- No wait between calls and no call limit
curl -F "file=@sample.jpg;type=image/jpeg" \
-H "Authorization: Bearer 1_8an4dAfsIyEEvBbaKxd55P2Wgf" \
"https://<TEST_HOST>/api/v1/photos?userId=PLYR01JY39A09EE40YQZRHWTT9EM1VDBG"// Success
{ "result": "success" }
// Failure (404): user ID not found
{ "result": "failure", "message": "userId is not found" }
// Failure (400): other (file missing, too large, invalid type, etc.)
{ "result": "failure", "message": "other problems." }GET /api/v1/leaderboard/entries
Gets leaderboard entries. Authentication: required.
| Query string | Required | Description |
|---|---|---|
name |
✓ | Leaderboard name |
sort |
asc: ascending / desc: descending (default) |
|
userId |
User ID | |
arround |
Gets entries around the given user (1-100). Works when userId is set |
|
offset |
Start position (0-9999). Out of range becomes 0 | |
limit |
Number of entries (1-1000, default 100). Out of range becomes 100 |
// Success
{
"result": "success",
"entries": [
{
"position": 1,
"userId": "PLYR01HE2R3JV6Y2NEGRMS4KZQB861DBG",
"userName": "Player", // UTF-8, no emoji, 1-12 characters
"score": 12345,
"note": "extra info", // up to 8192 characters
"createdAt": "2025-09-24T00:00:00.000Z",
"updatedAt": "2025-09-24T00:00:00.000Z"
}
]
}
// Failure (404): user ID not found
{ "result": "failure", "message": "userId is not found" }
// Failure (400): other
{ "result": "failure", "message": "other problems." }POST /api/v1/leaderboard/entries
Creates or updates a leaderboard entry. If the score is less than or equal to the existing score, it is not updated. A leaderboard is created automatically for each name. Authentication: required.
| POST data | Required | Description |
|---|---|---|
name |
✓ | Leaderboard name. 1-64 characters of letters, digits, _ and - (/^[0-9a-zA-Z_-]{1,64}$/) |
userId |
✓ | User ID |
score |
✓ | Score (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807) |
note |
Extra info (UTF-8, 0-8192 characters) | |
force |
Pass 1 to save even if the score is lower than the existing one |
// Success
{ "result": "success" }
// Failure (404): user ID not found
{ "result": "failure", "message": "userId is not found" }
// Failure (400): other
{ "result": "failure", "message": "other problems." }POST /api/v1/leaderboard/entries/delete
Deletes a leaderboard entry. Returns success even if there is no entry. Authentication: required.
| POST data | Required | Description |
|---|---|---|
name |
✓ | Leaderboard name (/^[0-9a-zA-Z_-]{1,64}$/) |
userId |
✓ | User ID |
// Success
{ "result": "success" }
// Failure (404): user ID not found
{ "result": "failure", "message": "userId is not found" }
// Failure (400): other
{ "result": "failure", "message": "other problems." }Glossary
Runtime environment
The cloud streaming server that runs and streams the exe.
TapFun user ID
- A unique ID of up to 64 characters that identifies a user. Issued per app.
- Characters:
0-9,a-z,A-Z. - Format:
PLYR+ ULID + a per-app suffix of 3-7 characters (e.g.DBG,XENO,MOCODVLP).
App ID
An unsigned int ID that identifies an app.
API key
A 26-character string issued per app. Characters: 0-9, A-Z.
Publisher Console
The management console for publishers, used for app settings, the introduction page, sales and more. The test and production environments each have their own, and TapFun registers who can log in.
Introduction page
The game's page on TapFun (https://tapfun.co.jp/p/<app>). The play screen is https://tapfun.co.jp/p/<app>/play. Edit its contents under Details in the Publisher Console.
Guest
A player who is not logged in to TapFun.
TapFun wallet
The balance a player charges on TapFun, used for purchases on TapFun.
TapFun credit
Wallet balance given to test-play accounts in production, usable only in the target app (Test play in production).
Session
One play from launching the game in the cloud until it exits. Save data is stored when a session ends and restored when the next session starts.
Trial time
Free play time set per title ("お試し分数" in the Publisher Console). One session recovers 12 hours after use.
Energy
A unit players buy to extend play time. The play time per energy is set per title, with separate values for players with and without the title pass (Sales settings).
Title pass
A per-title right of use that players can buy. After purchase, the player can play for free for a set time. A version bundled with DLC can also be sold (DLC).
Paid-timer / free-timer user
A player with at least one second of paid play time remaining (from energy or the title pass) is a paid-timer user; otherwise a free-timer user. You can tell from the launch parameter --is-paid-timer or isPaidTimer of getPlayerEnvironment.
First Release
The Publisher Console operation that makes an uploaded version the one players launch (Sessions during a release).
Virtual pad
A virtual gamepad shown on the play screen on smartphones and tablets. Its input arrives at the exe as gamepad input (Supported input).
Changelog
| Date | Change |
|---|---|
| 2026-10-02 | Published this document. |