01 · Install
Add the plugin
Unzip the release into the project's Plugins folder and enable Prototir. The plugin starts with the game; nothing goes in a level.
Unreal Engine 5 has no browser export, so an Unreal prototype is a native build: it runs on the machine of whoever downloads it, outside the Prototir sandbox. You package for each platform you support, and Prototir hosts and serves the files. Choose how you build below: setup, export, manifest, SDK and testing follow your choice.
Unreal Native documentation selected
01 / Unreal Engine setup
Selected: Unreal Engine
This section changes with the platform selector. Shared packaging, publishing, page, and community guidance stays below it.
01 · Install
Unzip the release into the project's Plugins folder and enable Prototir. The plugin starts with the game; nothing goes in a level.
02 · Publish
Tools → Prototir → Publish to Prototir packages the game, uploads it and opens the website with the build waiting.
03 · Finish
Add the title, cover and visibility on the upload page and publish. The editor never publishes on its own.
Good fit
Heavy scenes, large assets, native plugins and long play sessions all work as they do on your machine. Expect large downloads: even an empty Unreal 5 project packages to about 250 MB, so check the per-file limit of your plan.
Current boundary
Prototir does not sandbox, scan, sign, or notarize your build, and does not broker signing for you. Expect Windows SmartScreen and macOS Gatekeeper to warn people before opening an unsigned app, and expect occasional antivirus false positives on engine builds. The prototype page states all of this to visitors rather than implying the file was vetted.
Install and connect
Install the Prototir plugin into the project. It is C++, so packaging needs Visual Studio on Windows or Xcode on Mac, as for any plugin with code; Blueprint-only projects can use it. The editor checks for a newer plugin once a day and links to the release; a native build keeps the plugin it was packaged with, so publish again to give testers new tools:
1. Download Prototir-0.1.0.zip from the v0.1.0 release.
2. Unzip it into the project's Plugins folder (Plugins/Prototir).
3. Enable Prototir in Edit > Plugins and restart the editor.Prototir writes the prototype slug into uploaded ZIPs. Call Prototir Ready when play can begin, Prototir Event and Prototir Score as it goes; the plugin reports them as one session once the tester has paired the build. Show Prototir Pairing Screen draws the built-in code and QR screen, or listen to On Pairing Started on the Prototir subsystem to draw your own. Testers get Feedback & tools (Screenshot, Comment, Console, Performance) without any code, and F8 opens them in games that capture the mouse. Play in the editor can pair but never counts as a session.
// The same from C++: add "Prototir" to your module's dependencies.
#include "PrototirSubsystem.h"
if (UPrototirSubsystem* Prototir = UPrototirSubsystem::Get(this))
{
Prototir->Ready();
Prototir->Event(TEXT("first_action"));
if (!Prototir->IsPaired()) Prototir->ShowPairingScreen();
}Supported profile
Input and player behavior
The visitor has none of your development environment. The usual reason a native build fails is a dependency that only exists on the machine that built it.
02 / Start
Prototir hosts finished client files, not a source repository, editor project, or development server. Browser builds need an HTML entry and their runtime assets in a ZIP. Native builds need the executable and its runtime files, packaged for each supported platform and architecture. You can publish either format or both on one prototype page.
Example · Unreal Windows package
MyGame-windows/
|-- MyGame.exe
|-- prototir-build.json
|-- Engine/
`-- MyGame/
|-- Binaries/Win64/MyGame.exe
`-- Content/Paks/Unreal Engine is selected. Changing the platform above updates this export, setup, manifest, SDK syntax, and testing guidance together.
03 / Build
Native builds do not use an HTML entry, browser permissions, or a web manifest. In Builds, choose the platform, architecture, version, minimum OS, and installation notes. The SDK export command writes a build identifier; Prototir adds the prototype slug to uploaded ZIPs. Set the slug in the SDK yourself for an installer or disk image.
// Native builds do not need an HTML entry or a web prototir.json.
// Publish to Prototir writes prototir-build.json with the build ID.
// Prototir adds prototir-prototype.json with the slug to uploaded ZIPs.
// Choose platform, architecture, version and requirements in Builds.
// Packaged by hand? ZIP the whole Windows folder, not just the .exe.04 / Build
Native builds report Ready, events, scores, sessions, and feedback after device pairing, and show Feedback & tools to testers by themselves. SDK storage stays in memory and managed AI is not connected.
Web, Unity, and Godot use APIs shaped for their runtime. Capabilities differ between browser and native builds. The selector above is currently showing Unreal Engine. Call Ready only after the first meaningful interaction is possible. For browser builds, preview generation does not wait for Ready. Native-only publications require a cover image.
// Blueprint nodes: Prototir Ready, Prototir Event, Prototir Score.
// After the tester approves the pairing code:
Prototir->Ready();
Prototir->Event(TEXT("first_action"));
Prototir->Score(1200);
Prototir->FlushSession();
Prototir->SendFeedback(TEXT("The first interaction was clear."));| Capability | Kind | What it can do |
|---|---|---|
| Ready | function | Starts a real session after the prototype becomes interactive. |
| Event | function | Records a small, non-personal milestone. Its normalized name, sessions reached,
and total triggers appear in creator analytics. Use stable names made from
letters, numbers, _, -, ., or :. |
| Score | function | Reports the current numeric score. |
| Storage | member | Contains asynchronous get, set, and remove functions
for in-memory values in native builds. They are not persistent saves or synced account storage. |
| Managed AI | member | Not connected to the native SDK. An explicit local mock handler is available for testing. |
| Seeded RNG | function | Returns deterministic local randomness. Currently exposed by the browser SDK. |
Use your own save system for persistence. Native SDK AI hooks are local mocks, not requests to Prototir's managed gateway.
// The Unreal plugin has no Prototir storage.
// Use your game's own SaveGame objects.// Managed AI is not available in the Unreal plugin.First action, onboarding completion, important tool use, level completion, creation/export, retry, and a clearly named abandonment point.
Use stable short names and small values. Never place names, email addresses, free-form messages, secrets, or other personal data in event payloads.
05 / Build
A session is one play. Prototir counts it as real once it lasts at least three seconds and reports at least one event, and almost everything you care about is built on real sessions rather than on opens.
That threshold is also the reason a prototype can look unplayed while people are clearly playing it. A build that never calls Ready and never reports an event has no real sessions, so its analytics stay near zero and it has no real use to rank with. Browser comments require real play; native feedback from an approved device uses its pairing authorization.
Starts the clock. Call it on the first frame the visitor can actually do something, not when loading finishes: a two minute cutscene before any input is not two minutes of play. Calling it twice does not restart anything.
Marks a milestone. One event is what turns an open into a real session, so report the first meaningful action early rather than only at the end of a level nobody reaches.
Reports a number. The best score of the session is the one kept, so a run that ends badly does not erase what the player achieved. Challenge leaderboards are built from scores on real sessions.
Names are lowercased and must be 1 to 64 characters of letters, numbers, _, -, . or :. Anything else is dropped rather than corrected, so Level Complete records nothing while level.complete records what you meant.
Pick names once and keep them. A name that changes between builds splits one behaviour across two rows and makes the before and after impossible to compare. Prototir keeps up to 50 distinct names per session; past that the events still count towards the total, but the per-name breakdown stops growing, which is what stops one runaway loop from becoming your entire analytics page.
Your prototype's analytics shows each event by name with two numbers: how many sessions reached it, and how many times it fired in total. The two together are the useful part. A step reached by few sessions is a wall; a step fired many times within few sessions is a retry loop. Duration buckets sit beside them as a rough drop-off curve.
A web build runs inside the shell, which watches it and reports for it. A native build has no shell, so the SDK keeps its own count and sends one session for the play instead of a request per event. The SDK reports periodically and when the window loses focus. You can also flush at a natural break; unsent data is retained for the next launch.
A native build also reports nothing until a tester has paired it, because until then there is nobody to attribute the play to. Running from the editor never reports: your own testing does not belong in your own numbers.
06 / Build
A prototype is one page with one set of comments, and it can be reached in more than one way: played in the browser, run as a native build on Windows, macOS or Linux, or both at once. Each of those is a build, they sit side by side, and none of them is the main one.
The publish form starts empty with one Add a build button, and the browser build is the first option in the same list as the rest. What you add decides how the prototype is delivered: a browser build alone plays on the page, platform builds alone are native only, both gives you both. Nothing is a one-way door, and the rest can be added later from Studio.
For a web prototype we take a screenshot of it running. A native build never runs on our machines, so there is nothing to capture. Your cover is the only picture the prototype has, on its page and everywhere it is listed.
Each platform build says which processor it is for, because a visitor handed the wrong one gets an app that will not start. The words differ per platform, on purpose: they are the words owners of those machines use for their own hardware.
Windows and Linux. x86-64 for the usual desktop processor, ARM64 for machines like a Snapdragon X laptop, and Any 64-bit for one file that runs on either.
macOS. Intel and Apple Silicon, which is how Apple splits its own machines and what About This Mac says, plus Universal for a binary holding both.
We do not say "Intel or AMD" for the desktop processor. That names two companies for what is really an instruction set: other vendors make chips that run it, and a Snapdragon X laptop is a Windows machine with neither company inside it.
A web prototype runs inside our sandbox and we are accountable for containing it. A native build runs on the visitor's own computer, where we have no such control, and the prototype page says so plainly rather than leaving people to assume otherwise.
We do not sign or notarize your build, and we do not broker anyone else doing it. Expect Windows SmartScreen and macOS Gatekeeper to warn people before opening an unsigned app, and expect the occasional antivirus false positive on engine builds. Signing is yours to arrange if you want those warnings gone.
The Unreal plugin adds Tools > Prototir > Publish to Prototir. It packages the project for the machine you are on with Unreal's own packaging, writes the build id into it, zips it, uploads it and opens the website with the build waiting. Development packaging is the default because Shipping removes the log the Console tool shows; choose in Project Settings > Plugins > Prototir.
A zip, not a bare executable: an executable on its own leaves its data folder behind, which is the most common way a download arrives broken.
A native build has no browser session, so it cannot know who is playing, and a sign-in inside an embedded browser is both refused by most providers and a bad idea anyway. Instead the build shows a short code and a QR, the tester approves it on prototir.com, and the build receives a token for that one prototype. They approve once per machine, not once per session, and they can revoke any build from their account settings.
Until that happens the build reports nothing and cannot send feedback, which is deliberate: there is nobody to attribute a play to. Draw the code however suits your game. The SDK hands you the code, the link and a ready-made QR and draws none of it, because it cannot know your art direction, your input model, or whether you are in VR.
You do not set the slug. It does not exist until the prototype does, so there was no value you could have put in the first export anyway. Prototir writes it into the .zip while you upload, and the build reads it on the machine it is downloaded to. Export once, upload once, done.
Set it by hand only when you need to override that: in Project Settings > Plugins > Prototir for a build you ship outside Prototir, or an installer we cannot write into. The injected slug wins wherever both exist, because it travelled with that exact download.
As the file arrives, Prototir looks for the SDK in it and writes your slug beside the executable. If it cannot find the SDK, it says so on the prototype page straight away, because a build without it can download perfectly and still report nothing, and there is no later moment when you would find that out.
Both of those are checks against a mistake, not against someone determined. A native build runs on someone else's machine where we can check nothing, and anyone who wanted to fake the reports could. We would rather say that than imply a guarantee we cannot make.
The slug can only be written into a .zip. An installer or a disk image gets uploaded as it is, and you set the slug in the SDK yourself.
prototir-build.json into the build, and Prototir records that id from the archive you upload. A running build reports
the same id when it pairs, so a mismatch tells you a tester is playing an older build than the
one on the page. That is all it does, and nothing depends on it: both sides come from a file
you control, so it is not verification, not security, and not anti-cheat.Adding builds also changes how people find you. Discover asks two separate questions: what device someone is holding, and how they want a prototype to reach them. A build for Windows, macOS or Linux puts you in the second one, under How you play › Native, and again under the operating systems you actually ship. Drop a platform in a later release and you leave that filter, because it matches the build on offer now rather than one you used to have.
Everything lives under Studio › your prototype › Builds: one collapsible panel per platform, the browser build among them rather than above them. Add a platform you did not ship at first, replace one, or remove one, at any time. If a browser build remains, removing the last native build leaves a browser-only prototype. Native builds have independent versions; replacing a browser build does not remove them.
Platforms drift apart in practice: a Windows crash gets fixed the same evening while macOS waits for the next build. One version for the whole prototype would have to be wrong about one of them, so each keeps its own and the page shows which is which.
Replacing your browser build does not touch the others, and neither does rolling back to an earlier one.
Comments and plays are recorded against the build they happened on, so "this crashes on launch" stays attached to the build it was true of. Two different files both called v1.2 would make that a lie, which is why Prototir asks you to move the number.
The build you replace is kept, so you can put it back at any time. Anything older than that is deleted for you, and there is nothing to decide or tidy up: once several platforms each have their own history, choosing per replacement means nobody can tell which builds are still taking up space. Records outlive the files either way, so the feedback on a build you replaced stays attached to it.
Because feedback knows which build it came from, the comments on a prototype page can be narrowed to one platform, and every comment says whether it came from the browser or from a particular build. A crash report from Windows v1.2 is a different fact from the same words typed in a browser, and the page no longer makes you guess which you are reading.
07 / Publish
Show what can be touched, clicked, typed, dragged, or controlled. Avoid an unexplained blank canvas or loader with no progress.
Fill the available player, react to resize and fullscreen changes, avoid fixed desktop-only dimensions, and honor the declared orientation.
Test keyboard, pointer, touch, focus, Escape, and visible controls using the APIs or input system of your selected runtime. Pointer lock must start from a visitor action and release cleanly.
Give visitors a restart path, useful empty states, and a clear response when an optional permission, storage call, or AI request is denied.
Compress exported assets, defer secondary content, cap rendering cost, and test the first load on a real phone and ordinary connection.
Use readable contrast, semantic or accessible controls, labels, keyboard access, reduced-motion handling, and alternatives to audio-only or color-only information.
The Unreal Engine input, device compatibility, packaging, and testing checks are in the setup section above. Change the platform selector to replace them without opening another guide.
08 / Publish
09 / Publish
Only publish files you own or are allowed to distribute. Keep third-party license and attribution files in each build. Browser source download and templates apply to the browser ZIP; compiled native builds do not provide an editable engine project. If you enable browser source download, choose a license that actually grants the permissions you intend.
Visitors can download the original browser ZIP under your stated license. Platform-generated provenance is added to the downloaded manifest.
Declare the source slug or re-upload a Prototir browser source download. The origin remains linked and conflicting lineage is rejected.
A template is a complete browser starter prototype with source download enabled. Its downloads carry template provenance into later uploads.
10 / Publish
Anything a browser renders is delivered to that browser. An authorized visitor can inspect network requests and save JavaScript, models, textures, audio, video, WebAssembly, and data. Private visibility prevents anonymous access, but it cannot stop an invited viewer from capturing files they are allowed to run. This is equally true for direct Web code, Unity WebAssembly, and Godot Web exports.
The browser publisher can rewrite served .js files into compact,
less-readable code. This deters casual copying; it is not encryption or DRM. It does
not transform WebAssembly, engine data files, .mjs, inline code, source
maps, models, textures, or other assets. Unity and Godot already compile/package much
of their runtime output, but that output is still downloadable. The retained original
ZIP remains unchanged. Native builds are delivered as uploaded; arrange code signing
or notarization yourself when required by the operating system.
Keep production masters outside the ZIP. Export a runtime derivative: remove editor data and source maps, reduce geometry and texture resolution, use formats such as GLB with Draco or Meshopt and KTX2 where appropriate, and consider a visible or forensic watermark. Compression and renamed files add friction, but do not make client-rendered assets secret.
Rule of thumb: if disclosure would cause serious harm, do not include that file in a browser-delivered prototype. Use a reduced derivative, a watermark, or a server-side rendering approach instead.
11 / Publish
A replacement is an internal build of the same prototype. It keeps the stable URL, comments, and aggregate analytics, and does not count as another Free, Pro, or Team prototype. For browser builds, the current version stays live while the candidate is tested. Native versions are managed independently for each platform and architecture.
Browser builds support rollback and cleanup after a replacement passes. Native builds keep their own versions, and replacing the browser build does not remove native builds. Comment attribution remains tied to the build used. Publish a separate public release only when you want another listing, URL, and prototype slot.
12 / Grow
Every build that uses the SDK gets a Feedback & tools control, with nothing for you to add: Screenshot, Comment, Console and Performance. Testers point at what they mean and send what they saw with their comment.
Captures the moment without the control on it. The tester places a pin on the image and writes what they mean, because a seed and a timestamp do not reproduce a procedural scene.
A plain comment on the prototype, with the same moderation and wall controls as any other.
Recorded from the moment the build starts, so the error a tester saw before opening the panel is already there. They can copy it or attach it to a comment, where it shows collapsed and capped to its last 200 lines.
A frame-rate chart with the slowest frame and memory, recorded only while the panel is open. A summary can be copied or attached to a comment.
A screenshot, a console log or a performance summary is always sent with a message: it is what the comment is about, never a comment on its own. Recording costs almost nothing while the panels are closed.
A native build shows the control in its bottom-left corner whenever it knows its prototype, which it does once uploaded to Prototir. Posting asks the tester to approve the build at prototir.com/link once, then comments post as that account. Testers can revoke a paired build from their account settings.
// Or untick Feedback Tools in Project Settings > Plugins > Prototir.
Prototir->SetFeedbackToolsVisible(false);
Prototir->ShowFeedbackScreen(); // the same comment screen, from your own button
FString Log = Prototir->GetConsoleText(); // what the Console tool records Turning comments off for a prototype turns feedback off with it.