Skip to main content
Version: 5.x

Turn Based

Turn Based is a component for building turn-based game flows using Snapchat's Turn Based Dynamic Response API. It enables two-player, asynchronous Lenses where users take sequential actions and share game state between turns.

Turn Based Lens

This feature doe not support image/texture transfer.

To use a published Turn Based Lens with other users, you must set the visibility of the Lens to Public.

The Turn Based component extends the standard Dynamic Response system to support back-and-forth responses for turn-based games and experiences:

  1. User 1 opens the Lens with the Turn Based component and begins the session. On the initial turn, they make a move that sets the turn data. When the turn is complete they must capture a Snap, and send it to User 2.
  1. User 2 receives the Snap, taps a Tappable Area or the Your Turn CTA to enter the Lens.
  2. User 2 loads the turn data to set the current state of the game. They make their move, set the turn data, take a Snap, and send it back to User 1.
  3. The game alternates until the turn limit is reached or the Lens logic ends the game using setIsFinalTurn(true).

Unlike standard Dynamic Response (one-way data), Turn Based creates a bidirectional loop where each user's turn becomes the starting state for the next. Game state, turn history, and user data are serialized and transferred via associatedData.

The component handles turn management, data serialization, user role detection, and scene object toggling—so you can focus on game logic instead of the underlying Dynamic Response plumbing.

Common use cases include:

  • Word games – players take turns adding letters or words
  • Strategy games – chess, checkers, or custom board games
  • Quiz games – players answer questions in sequence
  • Puzzle games – build or solve puzzles together

Turn Data

Turn data lets Lenses share interactive state across Snaps. It's serialized automatically and passed using associatedData.

Turn data includes:

  • tappableAreas – Array of tappable areas; each entry has a key and a Screen Transform. Disabled transforms are skipped.
  • globalVariables – Persistent variables shared by both user.
  • userVariables – Persistent variables scoped to a specific user index (0 or 1).
  • turnVariables – Temporary variables you set this turn to pass to the next user.
  • previousTurnVariables – Temporary variables from the prior turn.
  • turnHistory – Historical record of previous turns (if enabled).

Understanding Data Flow

Data can propagate in several ways: Global Storage, User Storage, and Turn Variables.

It is recommended to primarily use Global and User Storage/Variables for game data as it is persistent. Turn Variables are temporary variables you set in a single turn to pass to the next user.

  • Global Storage: Per-session key/value storage shared by both users. Use getGlobalVariable(key) and setGlobalVariable(key, value) for shared data. For example, round number, game rules, or game state.

  • User Storage: Per-session key/value storage scoped to a specific user index (0 or 1). Use getUserVariable(userIndex, key) and setUserVariable(userIndex, key, value) (or getCurrentUserVariable() / setCurrentUserVariable() and getOtherUserVariable() / setOtherUserVariable()) for per-user data like scores or selections.

  • Turn Variables: During your turn, set values with setCurrentTurnVariable(). When endTurn() is called, a Snap is taken and these values are sent and will become the next user's previous turn variables.

    • Previous Turn Variables: When your turn begins, you receive previous turn variables, the temporary data the other user sent. Inspect with getPreviousTurnVariable() or getPreviousTurnVariables().
    • Auto Restore Turn: If this option is enabled, changing turn data or calling endTurn() saves a cache of current turn variables. If the Lens is reopened before the Snap is sent to the other user, these cached values restore automatically as the current turn variables.
  • Passing Data Forward: Previous turn variables are read-only and don't persist automatically. If you want them available next turn, copy them into current turn variables explicitly or alternatively use Global Variables.

Turn variables do not persist by themselves. To persist a value, read it with getPreviousTurnVariable() and write it back with setCurrentTurnVariable().

Installing the Component

The Turn Based Custom Component is available in the Asset Library. Press Install/Update, then add it to the Asset Browser via the + button by searching for "Turn Based".

Basic Setup

  1. Add the Turn Based component to a Scene Object (or drag it into the Scene Hierarchy from the Asset Browser).
  2. Configure component inputs: turn limit, tappable areas, and turn variables.
  3. Call the component API from your game logic to control flow.

Component Inputs

Game Configuration

InputDescription
Use Turn LimitIf true, enables a maximum number of turns for the session. The game ends when the limit is exceeded.
Turn LimitMax number of turns (used if Use Turn Limit is enabled).
Save Turn HistoryIf true, turn history data is serialized.
Turns Saved LimitMax number of entries stored in turn history.
Turn VariablesArray of initial variables for turn data storage.
Auto Restore TurnIf true, restores current turn variables if endTurn() is called and the Lens is reopened before sending the Snap.

Interactive Areas and Scene Objects

InputDescription
Tappable AreasArray of tappable areas consisting of key and Screen Transform. Disabled areas are skipped.
User 1 Scene ObjectsScene objects enabled for User 1's turn.
User 2 Scene ObjectsScene objects enabled for User 2's turn.
Game Over Scene ObjectsScene objects shown when the game ends (if Require Turn Submission is enabled).
On Turn Start ResponsesConfigurable Component API or Behavior responses triggered when a turn starts.
On Turn End ResponsesConfigurable Component API or Behavior responses triggered when a turn ends.
On Game Over ResponsesConfigurable Component API or Behavior responses triggered when the game ends.

Tappable Areas limitations Excess tappable areas or values outside these limits are skipped:

  • Max tappable areas sent: 16
  • Max total screen coverage by tappable areas: 0.4
  • Max key length: 24 characters
  • Center position limits (screen coords): 0.05 < x < 0.95, 0.05 < y < 0.95
  • Min aspect ratio (min side / max side): 0.125

Debug Settings

InputDescription
Debug ModeChoose: None, Single Turn, or Simulate Turns.
Tapped KeyKey of tappable area for testing in editor.
Reset Simulate TurnsReset the simulated game session in editor (Simulate Turns mode).
Turn CountTurn count for debug (Single Turn mode).
Test Data TypeInput type for test data: JSON String or Studio Inputs (Single Turn mode).
Test Is Turn CompleteMarks the editor turn as complete (Single Turn mode).
Test DataDebug previous turn variables input (Single Turn mode).
Test Turn HistoryDebug turn history input (Single Turn mode).
Print LogsIf true, prints debug logs.
Logger SettingsConfigure on-screen/console logger (font size, levels). Visible if Print Logs is enabled.
Show Debug ViewDisplays a real-time overlay with current game state.

Enable Show Debug View to see a live overlay of current user, turn count, tapped key, variables, and tappable areas.

Component API

Methods

MethodReturn TypeDescription
getCurrentUserIndex()Promise<number>Returns index of current user, starting from 0.
getTappedKey()stringKey of tappable area tapped before the Lens opened. Empty string if none.
addTappableArea(key: string, screenTransform: ScreenTransform)voidAdd a tappable area described by Screen Transform with a key.
removeTappableArea(key: string)voidRemove a tappable area by key.
clearTappableAreas()voidClear all tappable areas.
getTurnCount()Promise<number>Current turn count, starting from 0.
getPreviousTurnVariable(key: string)Promise<UserDefinedGameVariable | undefined>Get a previous turn variable by key. UserDefinedGameVariable is number, string, boolean, or a dictionary/array of these.
getPreviousTurnVariables()Promise<UserDefinedGameVariablesMap>Get previous turn variables (data received with the Snap) as a dictionary. Empty {} on the first turn.
getCurrentTurnVariable(key: string)UserDefinedGameVariable | undefinedGet the current turn variable (data to be sent). If value is an object/array, call setCurrentTurnVariable after updating it to ensure changes are handled.
setCurrentTurnVariable(key: string, value: UserDefinedGameVariable)voidSet a current turn variable.
setScore(score: number | null)voidSets score for the current turn. Pass null to clear the score. The score will be included in the turn data.
getScore()number | nullReturns currently set score or null if no score is set.
endTurn()voidCompletes the turn, automatically captures a Snap for the user to send, and caches the current turn data to be restored if "Auto Restore Turn" is enabled.
setIsFinalTurn(isFinalTurn: boolean)voidMarks the current turn as the last in the session when true.
isFinalTurn()Promise<boolean>Returns true if the current turn is the final turn (limit reached or manually set).
getCacheTurnDataForRestore()booleanReturns whether making changes to the turn data will cache it for restore if user closes the lens without sending snap.
setCacheTurnDataForRestore(value: boolean)voidSets whether making changes to the turn data will cache it for restore if user closes the lens without sending snap. Data that is already cached will not be affected.
showRetryDisclaimer()Promise<void>If the user has played their turn but did not send the snap back, use this method to show a disclaimer prompting the user to send the snap to continue the game. The promise is rejected if there was an error.
getCurrentUserDisplayName()Promise<string>Get the current user's display name.
getOtherUserDisplayName()Promise<string>Get the other user's display name.
getTurnHistory()Promise<TurnHistoryEntry[]>Get an array of recent turn history entries ordered by turn count. Empty on the first turn. The last entry always matches previous turn variables. TurnHistoryEntry: turnCount: number; userDefinedGameVariables: UserDefinedGameVariablesMap; isTurnComplete: boolean.
getTurn(turnCount: number)Promise<TurnHistoryEntry | null>Get turn history entry for a specific turn, or null if it doesn't exist.
getPreviousTurn()Promise<TurnHistoryEntry | null>Get the previous turn's history entry (same data as previous turn variables) or null.
getUser(index: number)Promise<SnapchatUser | null>Returns the Snapchat user for the provided index; returns null for the current user. Can be used to load Bitmoji. Promise rejects on load error.
getUserVariable(userIndex: number, key: string)UserDefinedGameVariable | undefinedGet a per-session variable for a specific user.
setUserVariable(userIndex: number, key: string, value: UserDefinedGameVariable)voidSet a per-session variable for a specific user.
getGlobalVariable(key: string)UserDefinedGameVariable | undefinedGet a per-session variable for the entire game session.
setGlobalVariable(key: string, value: UserDefinedGameVariable)voidSet a per-session variable for the entire game session.

Object/array variables If a turn variable is an object or array, call setCurrentTurnVariable after mutating it to ensure changes are saved. For example:

turnBased.getCurrentTurnVariable('throw_data').force = 100; // may not be saved
// correct usage:
const throwData = turnBased.getCurrentTurnVariable('throw_data');
throwData.force = 100;
turnBased.setCurrentTurnVariable('throw_data', throwData);

User loading getUser(index: number) returns null for the current user and rejects the promise if a load error occurs.

Events

EventTypeDescription
onTurnStartEvent<>Fired when prompt data has loaded and the turn starts. Callback provides: currentUserIndex: number (0 or 1), tappedKey: string, turnCount: number, previousTurnVariables: IUserDefinedGameVariablesMap.
onTurnEndEvent<>Fired when endTurn is called and it's not the last turn.
onGameOverEvent<>Fired when endTurn is called and it's the last turn.
onErrorEvent<>Fired if an error occurs. Callback provides: code: string (INCOMPLETE_TURN_DATA_SENT, INCOMPLETE_TURN_DATA_RECEIVED), description: string.

Usage Example

LoadOtherUserBitmoji

Loads the other user's Bitmoji avatar using the Bitmoji 3D component. Ensure the "Auto Download" option is disabled on Bitmoji 3D.

@component
export class LoadOtherUserBitmoji extends BaseScriptComponent {
@input('Component.ScriptComponent')
turnBased: TurnBased;

@input('Component.ScriptComponent')
bitmojiComponent: ScriptComponent & {
downloadAvatarForUser: (user: SnapchatUser) => void;
};

onAwake() {
this.createEvent('OnStartEvent').bind(() => {
this.loadAvatarForOtherUser().catch((e) =>
print('Error loading avatar for other player: ' + e)
);
});
}

private async loadAvatarForOtherUser(): Promise<void> {
const turnCount = await this.turnBased.getTurnCount();
// We can only load the avatar for the other user if there is at least one turn
if (turnCount > 0) {
// Get the index of the current user and the other user
const currentUserIndex = await this.turnBased.getCurrentUserIndex();
const otherUserIndex = currentUserIndex === 0 ? 1 : 0;

// Retrieve the other user by index
const otherUser = await this.turnBased.getUser(otherUserIndex);
if (otherUser) {
// Download the avatar for the other user
this.bitmojiComponent.downloadAvatarForUser(otherUser);
}
}
}
}

Debugging and Testing

Debug Modes

Debug settings only work in Lens Studio editor and have no effect in published lenses.

The component provides three debug modes for testing:

  • None – Normal operation (use in production)
  • Single Turn – Test specific turn scenarios in editor
  • Simulate Turns – Full turn sequence simulation in editor

Simulate Turns in Lens Studio


When debugMode is set to Simulate Turns, the Turn Based Component simulates a full game loop in Lens Studio using persistent editor memory. This allows you to test turn-by-turn logic without publishing or sending real Snaps.

Each time the Snap Capture button is pressed in the preview:

1. Current Turn is Serialized The current session data is saved internally as if a Snap was sent:

  • All data set with setCurrentTurnVariable()
  • Any updates to setGlobalVariable() or setUserVariable()

This mimics sending a Snap to the other player.

2. Turn Advances After capturing:

  • Close the Snap preview (tap the X in the upper left corner)

    Required for Lens Studio 5.13 and earlier Turn progression only occurs after a manual preview reset.

3. Role Swaps The user role alternates automatically:

  • Even turns: User 1
  • Odd turns: User 2

Scene elements like user1SceneObjects and user2SceneObjects will toggle accordingly.

4. Variable Propagation

Data flows forward between turns as follows:

  • Global Variables and User Variables are persisted automatically across all turns
  • Use getGlobalVariable() and getUserVariable(index) to confirm expected state
  • setTurnVariable() values → become getPreviousTurnVariables() on the next turn

Preview Reset Required for Lens Studio 5.13 and below. You must reset the preview after capturing a Snap to advance to the next turn.

5. Reset Simulate Turn Count To reset the turn count to 0, open “Additional Options” (gear icon) in the upper right corner of the Preview Window and select “Clear Turn Based State”.

Best Practices

  • Provide clear visual feedback for whose turn it is.
  • When the turn is complete, prompt the user to take a Snap to send to the other user.
  • Use Global Variables first to manage persistent game data.
  • Include previous turn replay for complex games.

Error handling

  • Always listen for onError events and provide user feedback.
  • Validate game state before calling endTurn().
  • Call endTurn() to capture the Snap and complete the turn.

Previewing Your Lens

To preview your Turn Based Lens in Snapchat, follow the Pairing to Snapchat guide. Suggested testing flow:

  1. Push the Lens to your device to test User 1
  2. Take a Snap after making your first move
  3. Send the Snap to yourself to simulate sending to User 2
  4. Open the Snap to test User 2 and make the next move
  5. Take another Snap and send it back to yourself to continue
  6. Repeat steps 4–5 to exercise the full flow

During development, send Snaps to yourself; others won't be able to interact with your Lens while using push-to-device.


Publishing Your Lens

Turn Based functionality requires your Lens to be published as Public. Hidden or Offline Lenses cannot properly share turn data between users, which will cause the turn-based gameplay to fail.


  • Turn Based Player Info – Load and display specific players' Bitmoji and display names in a Turn Based session.
Was this page helpful?
Yes
No