Skip to main content
A playtest, the features it turns on and its feedback form are made on the playtest’s page in the Protokite dashboard (Getting started); this page is what the build does with them. Each of these runs only while the playtest turns it on in Protokite and the player has allowed it, and each has Blueprint nodes that are safe in every build: with no playtest running they answer false, empty or Turned Off and change nothing (all but Protokite Get Playtest Settings, which needs no playtest). Setting the build up is on the Unreal plugin page.

From Blueprint or C++

Every playtest node on this page is in the Protokite | Playtest category of the Blueprint action menu, and needs nothing more than the plugin turned on. Each finds the playtest from the graph that calls it. C++ calls the same functions on UProtokitePlaytestLibrary, passing any object in the game’s world (the actor or widget making the call, this) where a node finds the playtest by itself. Add the plugin’s module to your game module’s Build.cs and include its header:
That line makes the optional plugin required. Your game module no longer builds without Protokite Playtest installed and enabled, so the plugin stays in every build of the project, release builds included. If you would rather keep it optional, or your game is Blueprint-only, use the nodes: they need no Build.cs line.

What the player allowed

The build asks its player what this playtest may collect before it collects anything, and their answer decides what the rest of this page does: Protokite Is Playtest Feature Enabled already answers for both at once: a feature the playtest turns on and the player left out reads as off, everywhere. Protokite Get Playtest Consent gives the answer itself, and the question, how a game asks it in its own screens, and the setting that turns it off are on the Unreal plugin page.
The feedback form is not covered by that answer. It is sent only when a player fills it in and presses Send, which is their own doing either way — and a form an earlier launch could not send is still sent later, whatever they answered since.

Video recording

The game’s screen is recorded from the moment the playtest loads, one recording per launch, into a WebM file a browser plays. Background time is not recorded. The Video Recording settings in Protokite Playtest Settings set the size, frame rate and bitrate — 1280×720, 30 frames a second and Video Bitrate (kbps) 2000 by default — and two limits, whichever comes first: Recording Length Limit (Minutes), 60, and Recording Size Limit (MB), 1536. A recording is uploaded to its session:
  • when a length or size limit ends it;
  • when the game asks, with Protokite Stop And Upload Playtest Recording or the feedback form’s Upload your recording button;
  • when the game stops it for good, with Protokite Stop Video Recording;
  • and at the start of a later launch, for anything an earlier launch could not send: a failed upload, a quit, a crash.
Quitting does not upload. A whole recording cannot be sent inside a shutdown, so it is kept and the next launch sends it. A recording is deleted once uploaded, and one that no playtest session ever started for is deleted by the next launch, since it can never be sent.
Recordings wait under Saved/ProtokitePlaytest/Recordings/, inside Recordings Disk Budget (MB), 4096. When room is short the oldest test videos go first and recordings waiting to be uploaded go last. Offer a player a way to send their recording only while Protokite Can Send Playtest Recording is true. It is false when no session has started for the recording, and a button pressed then would stop the recording and send nothing.

Telling the player their recording was sent

Bind On Recording Upload Finished to tell the player how it went. It is raised once when the launch’s recording finishes, with two values:
  • Uploaded is true when the recording reached its session.
  • Why Not says why it was not uploaded, including when the upload could not begin at all (no Protokite session to send it to, the Flock SDK not running). A recording that was not uploaded is kept for a later launch, unless no session ever started for it.
It is not raised while the game is closing, for recordings an earlier launch left, or for test videos. The event belongs to the Protokite Playtest Subsystem, which lives on the game instance. In Blueprint, search the action menu for Get ProtokitePlaytestSubsystem (under GameInstance Subsystems); in the graph the node is titled Protokite Playtest Subsystem. Drag from its output and bind the event from there:
Event BeginPlay runs Bind Event to On Recording Upload Finished, whose Target is the Protokite Playtest Subsystem node, bound to a Recording Upload Finished custom event with Uploaded and Why Not; it branches on Uploaded, and the False branch prints Why Not

On BeginPlay, bind On Recording Upload Finished and print Why Not when Uploaded is false.

In C++ the handler must be a UFUNCTION(), because the event is a dynamic delegate (the module and header are in From Blueprint or C++):

Heavy analytics

The plugin sends these through the Flock SDK’s analytics, under the playtest category, and they read on Dashboards → Game Metrics:
  • performance_window for every ten seconds of play: median, 95th and 99th percentile frame time, hitches, and memory used and at its peak;
  • level_loaded for every level this game instance loads, with the level before it and, for a blocking load, how long it took;
  • your own events, with Protokite Record Playtest Event.

Recording an event of your own

Protokite Record Playtest Event takes an event name and its properties. Start the properties with Make Flock Event Properties (nothing to wire in), add one Flock Event Property node per property (Integer, String, Float, Boolean or String Array), each feeding the next, and wire the last into Properties:
A Boss Defeated custom event into Protokite Record Playtest Event with the name boss_defeated and properties built by Make Flock Event Properties and Flock Event Property (Integer) seconds 95

When the boss falls, record boss_defeated with how many seconds the fight took.

In C++ (the module and header are in From Blueprint or C++):
It returns false, and records nothing, when:
  • no playtest is running, or it leaves heavy analytics off (or the player left play data out);
  • the name is one the plugin sends itself, performance_window or level_loaded;
  • the Flock SDK refuses the event: its analytics are off, consent is withheld, the name is empty, or it is longer than 200 characters.
Nothing is sent while the Flock SDK’s Analytics Enabled is off; the log says so once. See Analytics & events for how the category and the dashboards fit together.

Exceptions

Exceptions stay the Flock SDK’s. It captures error lines, failed ensures, Blueprint script errors such as Accessed None, and crashes, with its own settings under Analytics | Exceptions, and reports them on Diagnostics → Errors. A playtest’s exception switch never turns that on or off; when a playtest asks for exceptions and Analytics Capture Exceptions is off, the log warns once as the session starts. To check that exceptions reach the dashboard, type Flock.RaiseTestException error or Flock.RaiseTestException blueprint 100 in the console of a Development build. A hundred of the same fault arrive as one report, then one repeat report counting the other ninety-nine once the repeat window closes.

The feedback form

The form’s questions are written on the playtest’s Feedback form page in Protokite. When the playtest publishes a form, players open it with Feedback Form Key (F9 by default; set it to none to turn the key off), or your game opens it with Protokite Open Feedback Form — from a pause menu, for example. Check Protokite Can Open Feedback Form first: it is false when the playtest published no form, so your game can leave its own entry out rather than offering nothing. In a pause menu built as a Widget Blueprint, put these nodes on the On Clicked event of its Send feedback button; the custom event in the picture stands for that event.
A custom event Open Feedback From Pause Menu into Protokite Can Open Feedback Form, a Branch, and on True Protokite Open Feedback Form

A pause menu's Send feedback entry: open the form only when there is one.

In C++ (the module and header are in From Blueprint or C++):
Protokite Close Feedback Form closes it without sending, and Protokite Is Feedback Form Open says whether it is up.
A playtest feedback form over the game, with a rating, a choice, text answers, and an Upload your recording button

A published form, drawn from the playtest: every question, and the button that sends the recording.

While the form is open the mouse shows and typing goes to it; closing or sending it puts both back as they were. Pause The Game While The Form Is Open is off by default, because pausing does nothing in a multiplayer game and loses what a single player was about to describe. Your own images can sit on the form as well. Set them in Project Settings → Plugins → Protokite Playtest Settings, under Feedback Form, or from a Blueprint with Protokite Get Playtest Settings: every one is read each time the form opens. To import an image for the form:
  1. Import it as a texture, for example by dragging it into the Content Browser. Images with transparent backgrounds suit the form’s dark panel.
  2. Open the texture and set Padding and Resizing to None. Otherwise it is stretched to a power of two and drawn soft, or padded and drawn squeezed above a band of padding.
  3. Keep its mipmaps, so it stays smooth when drawn smaller: Mip Gen Settings anything but NoMipmaps, and not FromTextureGroup when the Texture Group is UI.
  4. Save it, and pick it in Feedback Form Logos or Feedback Form Footer Logo.
Every question comes from the playtest, so editing the form in Protokite changes what players see with no new build. Answers are checked before they are sent, with every problem shown against its question. A form that cannot be sent is kept and sent by a later launch, and sending again in the same session replaces the earlier answers.

A form of your own

To draw the questions in your own UI instead of the built-in form, read the form, record the player’s answers, check them, and send them:
  1. Read the form. Protokite Get Feedback Form returns false, with an empty form, when the playtest published none. Its Form holds the title, the description and Fields, one per question. Each field has an Id, a Type (its kind), a Label, Help Text, Options (for a select) and Required.
  2. Pick a control by the question’s kind. Break the field, and compare its Type with Equal Exactly (String) against the Protokite Feedback Question Kind node for each kind (Text, Text Area, Rating, Select, Checkbox) rather than typing the kind: kinds match letter for letter. Treat a kind you do not know as text, which is how the server reads it.
  3. Record each answer under the question’s Id with the node for its kind. Leave the first node’s Answers unwired, as in the picture: it starts from no answers. These four nodes have no execution pins: each returns a new Answers value with that answer added, and leaves the Answers it was given unchanged. Feed each node’s Answers output into the next one’s Answers input, and keep the last output in a variable (of type Protokite Playtest Form Answers). An answer whose output is not kept is lost.
  4. Check the answers with Find Feedback Form Problems (Answers, Form). It lists every question the server would turn them away over, each with its Field Id and a Message to show the player beside that question. An empty list means they would be taken.
  5. Send them with Protokite Send Feedback Form Answers. It returns false, with a warning in the log, when the playtest has no form or there is nobody to send the answers for. Answers that cannot go now are kept on disk and sent by a later launch.
Success is a return value of true: the answers are kept on disk and on their way. The log, under LogProtokitePlaytest, then says Sending the feedback form. and, once Protokite has taken them, The feedback form was sent. (or The feedback form is kept until the Flock SDK is running. when the Flock SDK has not started). A refusal logs The feedback form was not sent, with Protokite’s reason, the question it refused when it names one, and the fix. In the picture, fun and comments are the Ids of two questions in the playtest’s form, a rating and a text question. Use the Id of each question your own form has.
A Send My Feedback custom event into Protokite Get Feedback Form and a Branch; Set Feedback Rating Answer for fun 4 feeds Set Feedback Text Answer for comments; the result is set into an Answers variable; Find Feedback Form Problems, Length, equals 0 and a Branch lead to Protokite Send Feedback Form Answers

Rate the form 4 for fun, add a comment, keep the result in Answers, and send it only when nothing is missing.

The same in C++ (the module and header are in From Blueprint or C++). In C++ the answers are recorded on one FProtokitePlaytestFormAnswers value in place, and a field’s kind is checked with IsOfKind and the ProtokitePlaytestFormFieldTypes names:
The ids fun, comments, would_play_again and platform stand for your own form’s questions: use the Ids the form hands you.
Two rules are easy to miss. Set every checkbox, ticked or not: the server counts an unticked box as an answer, and a needed checkbox that was never set is missing. And a chosen option must match letter for letter — the server compares options exactly, so crash is not Crash.

Blueprint nodes

All under Protokite | Playtest. Each finds the playtest from the calling graph. Every name starts with “Protokite” except the answer nodes: Set Feedback … Answer, Set Feedback Chosen Option and Find Feedback Form Problems.

Trying it in the editor

Before any playtest exists, tick Record Video In Play In Editor in Project Settings → Plugins → Protokite Playtest Local Settings and press Play, or type ProtokitePlaytest.RecordTestVideo 30 in a Development build’s console. Test videos are saved under Saved/ProtokitePlaytest/Recordings/TestVideos/ and never uploaded. Against a real playtest, press Play with the settings from the setup page and sign in with Flock.LoginWithDevice. Then, in a Development build’s console: The waits exist because every -ExecCmds command runs on the first frame, before anything has been recorded or a session has started.

Checking a playtest build

ProtokitePlaytest.SelfTest checks everything a playtest build does against your real Protokite in one go, and logs a line per step and a count at the end: Playtest self-test finished: 16 passed, 0 failed, 1 skipped. Development builds only. Each check sits beside a request Protokite must refuse: a wrong API key, a missing one, a version no playtest is linked to, a session start that names no player, a form missing a needed answer or choosing an option that is not on the list, and a form, upload link and end for a session that does not exist. A check that only ever succeeds cannot tell a working build from a broken one, so a refusal passes only with its own HTTP status and, for a form, the question it names. It signs nobody in, so sign in first. From a script:
  • It ends the launch’s session as its last step, so run it in a launch of its own. A session a refusal should have prevented is ended at once, so a run leaves nothing open.
  • It leaves a trace on your dashboards: one filled-in form on its session, one playtest_self_test event, one Blueprint fault raised twice so its repeat is counted, and the launch’s recording.
  • A step is skipped, saying why, when nobody has answered what the playtest may collect (answer it first with ProtokitePlaytest.AnswerConsent video_and_play_data); when the playtest does not turn its feature on; when the build has no video encoder, which is every platform but 64-bit Windows; when the launch cannot draw (-nullrhi), since nothing is recorded; when Analytics Cache Failed Events is off, since a report sent the moment it is made cannot be watched; and for a closed playtest unless you name one.

What stays on the player’s machine