← Back to Documentation

API Reference

The Codenames Game Server exposes a Connect RPC API. All endpoints use POST with a JSON body.

Services

BotService is implemented by Bots to play Codenames.

A Bot is expected to implement this interface and host their implementation at the port they use when registering. The Gamemaster VM calls these endpoints to coordinate gameplay.

Protocol Overview

This is a stateful protocol where bots must track game state locally.

When the game first starts each participating Bot is informed via the GameStarted method, which contains the initial game information:

  • The request tells the Bot what team they are on and what role they have.
  • The request contains the IDs of all participating Bots.
  • Guessers gets all cards and their words.
  • Spymasters gets all cards, their words, and their card types.

On each turn either GiveClue or MakeGuess is called on the appropriate Bot depending on whose turn it is. The request contains a list of moves that has happened in the game since the last time the Bot was called.

The game continues with GiveClue and MakeGuess calls until a team wins. All participating Bots are notified by this via the GameEnded method.

Strike System and Disqualification

Bots are expected to respond correctly and promptly to all requests. If they do not the Gamemaster will track this and potentially disqualify the Bot from the current game.

The following cases are treated as an error by the server:

  • Timeouts: not responding within the configured timeout period.
  • Connection errors: unable to reach the bot's endpoint.
  • Invalid responses: malformed response data.
  • Invalid actions: trying to do an illegal game action.
  • GameStarted failures: not able to acknowledge a GameStarted call.

If a Bot does any of these it will be counted as a strike for the Bot in the current game. After 3 strikes the Bot will be disqualified and the game will be ended with the opposing team winning.

Strikes are tracked per-bot and per-game. This means that strikes are not shared by a team, and strikes do not affect any other games. Strikes do however persist for the full game and across turns: if a Bot responds badly across three separate turns it is still treated as a disqualification. A bot disqualified in one game can still participate in future games.

After a strike a Bot will be allowed to retry their action. If for instance a Bot tries to reveal a card not on the board range it will count as a strike but will be allowed to retry immediately.

Bots can track their strikes and what error they did in the bot_context field sent in either the GiveClue or MakeGuess requests.

GameStarted #

POST codenames.v1.BotService/GameStarted( GameStartedRequest ) -> GameStartedResponse

GameStarted is called on each participating Bot when a new game starts.

GiveClue #

POST codenames.v1.BotService/GiveClue( GiveClueRequest ) -> GiveClueResponse

GiveClue is called for Spymaster Bots on their turns. Bots responds with the clue the want to give to their Guesser Bot.

MakeGuess #

POST codenames.v1.BotService/MakeGuess( MakeGuessRequest ) -> MakeGuessResponse

MakeGuess is called for Guesser Bots on their turns. Bots respond with the action they want to take: either reveal a card or end the turn.

GameEnded #

POST codenames.v1.BotService/GameEnded( GameEndedRequest ) -> GameEndedResponse

Called when a game ends to inform the Bot of the final result. Sent to all participating Bots once when the game ends.

GameService for managing the Gamemaster.

This is the primary management API for the Gamemaster, and is hosted by the Gamemaster VM. This service keeps track of:

  1. Teams that are participating in the Hackathon.
  2. Bots that are registered to these Teams.
  3. Games that the Bots play in.

Most of these methods are free for anyone to call. Methods for Bot registration and unregistrations requires a valid Team token though.

CreateGame #

POST codenames.v1.GameService/CreateGame( CreateGameRequest ) -> CreateGameResponse

Create a new game with the specified bot assignments, returning the Game ID which can be used to track the game.

The game starts immediately upon creation. All Bots that are references in this request must be registered. A Bot cannot be assigned to multiple roles in a single game: i.e. a Bot cannot play with or against itself in the same game.

GetGame #

POST codenames.v1.GameService/GetGame( GetGameRequest ) -> GetGameResponse

Get the current state of a game by ID.

ListGames #

POST codenames.v1.GameService/ListGames( ListGamesRequest ) -> ListGamesResponse

List all games, both ongoing and ended games.

This method is paginated, i.e. only a small list of all games will be returned in a single call. You need to call it repeatedly with new values to continue to list through the full set of games.

ListActiveGames #

POST codenames.v1.GameService/ListActiveGames( ListActiveGamesRequest ) -> ListActiveGamesResponse

List all active games. Returns games in descending order by update time, newest game first.

GetGameMoves #

POST codenames.v1.GameService/GetGameMoves( GetGameMovesRequest ) -> GetGameMovesResponse

Get the move history for a game. Returns moves in chronological order: first move_number first.

This information can be useful if you want to inspect a game after it has finished.

RegisterBot #

POST codenames.v1.GameService/RegisterBot( RegisterBotRequest ) -> RegisterBotResponse

Register a Bot to participate in games.

Bots must be registered before they can participate in games. The first time you register a Bot for your Team with a given identity_key it will be created and immediately ready for games. If you call this method with an identity_key that has been unregistered the Bot will be reregistered and keep using its history of played games.

You cannot register a Bot that is already registered. You cannot register a Bot on a port that is already in use by another registered Bot.

This method requires a valid Team token, which should be passed in the Authorization header of the request.

ListBots #

POST codenames.v1.GameService/ListBots( ListBotsRequest ) -> ListBotsResponse

Lists all registered bots.

UnregisterBot #

POST codenames.v1.GameService/UnregisterBot( UnregisterBotRequest ) -> UnregisterBotResponse

Unregister a bot by ID.

When you unregister a Bot it will immediately go into an unregistering state. In this state the Bot can still finish playing any ongoing games it is participating in, but it can no longer start any new games. Once all active games are finished the Bot will be set to the unregistered state, and its port will be available for reuse.

This method requires a valid Team token, which should be passed in the Authorization header of the request.

GetBotGames #

POST codenames.v1.GameService/GetBotGames( GetBotGamesRequest ) -> GetBotGamesResponse

Getsthe active games for a specific bot.

GetBot #

POST codenames.v1.GameService/GetBot( GetBotRequest ) -> GetBotResponse

Get detailed information about a specific bot.

Returns the bot's current state, stats, and active games.

GetLeaderboard #

POST codenames.v1.GameService/GetLeaderboard( GetLeaderboardRequest ) -> GetLeaderboardResponse

Get the current state of the Bot leaderboard.

ListTeams #

POST codenames.v1.GameService/ListTeams( GameServiceListTeamsRequest ) -> GameServiceListTeamsResponse

List all teams participating in the Hackathon.

GetTeam #

POST codenames.v1.GameService/GetTeam( GameServiceGetTeamRequest ) -> GameServiceGetTeamResponse

Get detailed information about a specific team.

ListBotsByTeam #

POST codenames.v1.GameService/ListBotsByTeam( ListBotsByTeamRequest ) -> ListBotsByTeamResponse

List all bots belonging to a specific team.

ListGamesByBot #

POST codenames.v1.GameService/ListGamesByBot( ListGamesByBotRequest ) -> ListGamesByBotResponse

List all games for a specific bot, both active and completed.

This method is paginated, i.e. only a small list of all games will be returned in a single call. You need to call it repeatedly with new values to continue to list through the full set of games.

Messages

Board represents the 5x5 grid of cards.

Always contains exactly 25 cards: 9 Red, 8 Blue, 7 Neutral, 1 Assassin.

FieldTypeDescription
cardsCard []

The 25 cards on the board, indexed 0–24.

Represents a Bot.

FieldTypeDescription
bot_idstring

Unique identifier for this bot.

identity_keystring

Human-readable identifier chosen during registration.

A Bot that has been unregistered can be re-registered if the same identity_key is used in RegisterBot.

base_urlstring

Base URL where the bot's BotService is hosted.

registered_atstring

ISO 8601 timestamp when the bot was first registered.

last_updated_atstring

ISO 8601 timestamp when the bot was last updated.

active_gamesstring []

IDs of games this bot is currently participating in.

elo_ratingint32

Current ELO rating (rounded to integer for display). New bots start at the configured default 1500.

games_playedint32

Total number of games this bot has played.

winsint32

Number of games this bot has won.

lossesint32

Number of games this bot has lost.

team_idstring

ID of the Team this Bot belongs to.

portint32

Port number where the bot is listening on the team's VM.

The bot's base URL is constructed as http://[team.vm_ip]:[port]

For unregistered bots, this is 0 (port has been freed).

stateBotState

Current state of the bot in its lifecycle.

Determines whether the bot can participate in games and if its port is active.

unregistered_atstring

RFC 3339 timestamp when the bot was unregistered.

The timestamp this represents depends on the Bot's state:

  • In UNREGISTERING this is when unregistration was requested.
  • In UNREGISTERED this is when they finished all games.
  • In REGISTERED this is empty.

Card represents a single card on the game board.

Each card has a word and may have a type, visible only to spymasters.

FieldTypeDescription
wordstring

The word displayed on the card. Must be unique within a game.

typeCardType

The type of the card. Only visible to spymasters. Guessers see an empty type for unrevealed cards.

revealedbool

Whether the card has been revealed. Once revealed, the type becomes visible to all players.

CardReveal represents the action and result of a guesser bot revealing a card.

FieldTypeDescription
positionint32

Board position (0-24) of the revealed card.

typeCardType

The type that was revealed (red, blue, neutral, or assassin).

Clue represents a Spymaster's clue to their Guesser.

FieldTypeDescription
wordstring

The clue word. Should relate to one or more cards on the board and clue the Guesser Bot about which cards to reveal.

countint32

The number of cards this clue relates to.

Used as a signal to the Guesser about how many cards the clue word relates to. A Guesser may only revelal up to count+1 cards in a single round.

The Spymaster may use 0 here to let the Guesser get unlimited guesses for their turn, though then this cannot signal how many cards the word relates to.

ClueGiven represents the one and only action a spymaster can do: give a clue to its guesser.

FieldTypeDescription
clueClue

The clue that the spymaster gave.

Game represents the complete state of a game. Used by the game server to track progress and returned by GetGame.

FieldTypeDescription
game_idstring

Unique identifier for this game.

boardBoard

The game board with all cards.

current_teamTeam

Which team's turn it currently is.

stateGameState

Current phase of the game.

red_cards_leftint32

Number of Red cards remaining to be found.

blue_cards_leftint32

Number of Blue cards remaining to be found.

current_clueClue ?

Current clue. Only set during the guessing phase.

guesses_madeint32

Number of guesses made for the current clue. Resets to 0 when a new clue is given.

winnerTeam ?

Winner of the game. Only set when game has ended with a winner.

end_reasonGameEndReason

Reason why the game ended. Only set when the game has ended.

disqualified_bot_idstring

ID of the bot that was disqualified. Only set when end_reason indicates disqualification. Empty if game ended normally.

red_spymasterstring

Bot ID of the Red team's spymaster.

red_guesserstring

Bot ID of the Red team's guesser.

blue_spymasterstring

Bot ID of the Blue team's spymaster.

blue_guesserstring

Bot ID of the Blue team's guesser.

A GameMove represents a move taken by a bot and its effect on the game.

FieldTypeDescription
move_numberint32

Sequential move number in the game.

clue_numberint32

Sequential number representing the clue this move was performed for.

teamTeam

The team of the bot that made this move.

performed_atstring

RFC3339 timestamp representing the time at which this move was performed.

oneof move
clue_givenClueGiven

A spymaster gave a new clue.

card_revealCardReveal

A guesser revealed a card.

turn_endedTurnEnded

A guesser ended their turn.

TurnEnded represents the guesser action when it decided to no longer make any guesses for its turn.

This message is intentionally empty: there is no more extra data to represent here.

(no fields)

Context about the bot's current state in the game. Included in requests to give bots visibility into their strikes and errors.

Note: Strikes accumulate for the entire game and are NOT reset after successful turns. A bot that makes mistakes will retain those strikes throughout the game.

FieldTypeDescription
current_strikesint32

Number of strikes this bot has accumulated in this game.

last_errorstring

Error message explaining why the bot's previous response was rejected/invalid. Empty if the bot's previous response was valid/successful.

This helps bots understand what went wrong with their previos response. Errors might include:

  • "timeout: no response within configured timeout"
  • "invalid action: empty clue word"
  • "invalid action: clue word is a board word"
  • "invalid action: guess not in unrevealed cards"

Action: End the turn without making another guess.

This message is intentionally empty message. It just signals that the Bot wants to end their turn.

(no fields)

Request sent to all bots when a game ends.

FieldTypeDescription
game_idstring

Unique identifier for this game.

bot_idstring

ID of this bot (for verification).

winnerTeam

Which team won the game (TEAM_UNSPECIFIED if no winner).

red_cards_leftint32

Number of Red cards remaining when game ended.

blue_cards_leftint32

Number of Blue cards remaining when game ended.

total_movesint32

Total number of moves made in the game.

remaining_movesGameMove []

List of remaining moves in this game that this bot did not see yet until the end of the game.

end_reasonGameEndReason

Reason why the game ended.

disqualified_bot_idstring

ID of the bot that was disqualified. Only set when end_reason indicates disqualification.

Response to GameEnded.

This message is intentionally empty: the Bot just needs to acknowledge.

(no fields)

Sent once to all bots when a game starts.

Bot should initialize local state from the board field.

FieldTypeDescription
game_idstring

Unique identifier for this game.

bot_idstring

ID of the Bot this is called for. Bots should verify that this is correct.

your_teamTeam

Which team this bot is playing for.

your_roleRole

Which role this bot plays.

boardBoard

The game board with all 25 cards.

  • For spymasters: card types are fully populated.
  • For guessers: card types are CARD_TYPE_UNSPECIFIED, i.e. hidden.

All cards have revealed = false at game start.

Response to GameStarted.

This message is intentionally empty. Bots do not need to send any data here: they just need to acknowledge that the game has started.

(no fields)

Action: Give a clue to the Guesser.

FieldTypeDescription
wordstring

The clue word. Should relate to one or more cards on the board and clue the Guesser Bot about which cards to reveal.

countint32

The number of cards this clue relates to.

Used as a signal to the Guesser about how many cards the clue word relates to. A Guesser may only revelal up to count+1 cards in a single round.

The Spymaster may use 0 here to let the Guesser get unlimited guesses for their turn, though then this cannot signal how many cards the word relates to.

Request sent to the spymaster bot when it's their turn to give a clue.

FieldTypeDescription
game_idstring

ID of the current game.

bot_idstring

ID of this bot (for verification).

current_teamTeam

Which team's turn it currently is.

moves_since_last_turnGameMove []

A list of game moves that has occurred since this bot's last turn, sorted by move_number ascending.

red_cards_leftint32

Number of Red cards remaining to be found.

blue_cards_leftint32

Number of Blue cards remaining to be found.

clue_numberint32

Incrementing clue number (1, 2, 3...), separate from move_number. Increments each time a clue is given in this game.

bot_contextBotContext

Bot's current state (strikes, errors from previous response).

Response from the Spymaster with their clue.

FieldTypeDescription
oneof action
give_clueGiveClueAction

The single action a Spymaster can make: give a clue to the Guesser.

Action: Guess a specific word on the board.

FieldTypeDescription
wordstring

The word to guess. Must match a card on the board (case-insensitive).

Request sent to the guesser bot when it's their turn to guess.

FieldTypeDescription
game_idstring

ID of the current game.

bot_idstring

ID of this bot (for verification).

current_teamTeam

Which team's turn it currently is.

moves_since_last_turnGameMove []

A list of game moves that has occurred since this bot's last turn, sorted by move_number ascending.

clueClue

The current clue from the spymaster.

guesses_madeint32

Number of guesses already made for this clue.

guesses_remainingint32

How many more guesses the bot can make. -1 means unlimited (when clue.count is -1 or 0). Otherwise calculated as: clue.count + 1 - guesses_made

clue_numberint32

The clue_number for this turn. Same value for all guesses within this turn. Distinguishes this clue from previous clues even if the word/count are the same.

bot_contextBotContext

Bot's current state (strikes, errors from previous response).

Response from the guesser with their action.

FieldTypeDescription
oneof action
guess_wordGuessWordAction

Set by the Guesser if they want to reveal a card.

end_turnEndTurnAction

Set by the Gueser if they want to end the turn.

Bot statistics for the leaderboard.

FieldTypeDescription
bot_idstring

Unique identifier for the bot.

identity_keystring

Human-readable identifier for the bot.

elo_ratingint32

Current ELO rating (rounded to integer).

games_playedint32

Total number of games played.

winsint32

Number of games won.

lossesint32

Number of games lost.

p99_latency_msint32

Average P99 latency in milliseconds (lower is better).

-1 means no latency data available yet.

team_idstring

Team ID of the bot

Request to create a new game.

All four bot roles must be assigned to unique bots.

FieldTypeDescription
wordsstring []

Deprecated field: this does nothing.

red_spymasterstring

Bot ID for Red team's spymaster.

This bot will receive GiveClue requests when it's Red's turn.

red_guesserstring

Bot ID for Red team's guesser.

This bot will receive MakeGuess requests when Red is guessing.

blue_spymasterstring

Bot ID for Blue team's spymaster.

This bot will receive GiveClue requests when it's Blue's turn.

blue_guesserstring

Bot ID for Blue team's guesser.

This bot will receive MakeGuess requests when Blue is guessing.

Response from CreateGame.

FieldTypeDescription
game_idstring

Unique identifier for the created game. Use this ID with GetGame to track the game's progress.

Request to get a specific team.

FieldTypeDescription
team_idstring

Team ID.

Response containing team details.

FieldTypeDescription
teamTeamInfo

Team information.

Request to list all teams.

(no fields)

Response containing all teams.

FieldTypeDescription
teamsTeamInfo []

List of teams, sorted by name.

Request to get a bot's active games.

FieldTypeDescription
bot_idstring

The bot ID to get games for.

Response containing the bot's active games.

FieldTypeDescription
game_idsstring []

IDs of games where this bot is currently playing.

Request to get a specific bot.

FieldTypeDescription
bot_idstring

The bot ID to get.

skip_active_gamesbool

Skip fetching active games for this bot. Use this to improve performance when active games are not needed (e.g., on game detail pages that only need bot metadata).

Response containing the bot details.

FieldTypeDescription
botBot

The bot information.

Request to get move history for a game.

FieldTypeDescription
game_idstring

The game ID to get moves for.

Response containing the move history.

FieldTypeDescription
movesGameMove []

Chronological list of moves in the game. Sorted by move_number ascending.

Request to get a game's current state.

FieldTypeDescription
game_idstring

The ID of the game.

Response containing the game state.

FieldTypeDescription
gameGame

The complete game state.

Request to get the ELO rating leaderboard.

FieldTypeDescription
limitint32

Maximum number of bots to return (default: 100, max: 1000).

sort_byLeaderboardSortBy

How to sort the leaderboard.

Response containing the leaderboard.

FieldTypeDescription
botsBotStats []

List of bots sorted by the requested criteria.

  • Win rate: highest win rate first, with higher number of games played as a tiebreaker.
  • P99 latency: faster bots first, with number of wins as a tiebreaker.

Request to list active games.

FieldTypeDescription
include_boardbool

Whether to include the full board state in the response (default: true). Set to false for lightweight list views.

Response containing active games.

FieldTypeDescription
gamesGame []

List of active games (non-ended).

Request to list bots for a team.

FieldTypeDescription
team_idstring

Team ID.

Response containing team's bots.

FieldTypeDescription
botsBot []

List of bots belonging to the team.

Request to list all bots.

This message is intentionally empty.

(no fields)

Response to ListBots.

FieldTypeDescription
botsBot []

List of all bots.

Request to list games for a specific bot.

FieldTypeDescription
bot_idstring

Bot ID to get games for.

limitint32

Maximum number of games to return (default: 50, max: 1000).

offsetint32

Number of games to skip for pagination (default: 0).

include_boardbool

Whether to include the full board state in the response (default: false). Set to false for lightweight list views.

role_filterBotRoleFilter

Filter games by the bot's role (default: ALL).

Response containing games for a bot.

FieldTypeDescription
gamesGame []

List of games this bot has participated in. Ordered by updated_at descending (newest first).

total_countint32

Total number of games available for this bot (for pagination UI).

Request to list all games.

Supports pagination for large result sets.

FieldTypeDescription
limitint32

Maximum number of games to return. Default: 100, max: 1000. Leave this unset, 0, or negative to use the default.

offsetint32

Number of games to skip for pagination. Default: 0.

include_boardbool

Whether to include the full board state in the response. Default: true. Set to false for lightweight list views.

Response containing games.

FieldTypeDescription
gamesGame []

List of games. May include both active and completed games.

total_countint32

Total number of games available (for pagination UI).

Request to register a new bot.

FieldTypeDescription
identity_keystring

Human-readable identifier for the bot (e.g., "spymaster-v1"). Must be unique within the team.

portint32

Port number where the bot is listening on the Team's VM.

This port must be one of the available ports on the Team's VM: one of 8001, 8002, 8003.

Response from registering a bot.

FieldTypeDescription
botBot

The registered bot including its assigned ID.

Represents a team in the public API.

FieldTypeDescription
idstring

Unique identifier for the Team.

namestring

The name of the Team

vm_ipstring

IP address of the Team's VM.

bot_countint32

Number of registered bots.

total_games_playedint32

Number of games played by Team's bots.

top_bot_rankint32

Best rank on leaderboard (1-based, 0 if no bots on leaderboard).

top_bot_eloint32

Top bot's ELO rating (0 if no bots).

top_bot_identitystring

Top bot's identity key (empty if no bots).

top_bot_idstring

Top bot's ID (empty if no bots).

Request to unregister a bot.

FieldTypeDescription
bot_idstring

The bot ID to unregister.

Response from unregistering a bot.

This message is intentionally empty.

(no fields)

Enums

BotState represents the lifecycle state of a bot.

ValueNumberDescription
BOT_STATE_UNSPECIFIED0
BOT_STATE_REGISTERED1

Bot is registered and can participate in games. This is the normal active state.

BOT_STATE_UNREGISTERING2

Bot has been scheduled for unregistration and is waiting for active games to complete. The bot cannot join new games but continues in existing ones. The port is still occupied until the bot reaches the UNREGISTERED state.

BOT_STATE_UNREGISTERED3

Bot has been unregistered. It can no longer participate in games and its port is freed. The bot is still visible in leaderboards and can be re-registered.

CardType represents the type of card on the board.

Each card has a type that determines what happens when it is revealed by a Guesser.

ValueNumberDescription
CARD_TYPE_UNSPECIFIED0
CARD_TYPE_RED1

Red card. Revealing this helps Red win.

CARD_TYPE_BLUE2

Blue card. Revealing this helps Blue win.

CARD_TYPE_NEUTRAL3

Neutral card. Revealing this type of Card immediately ends the Guesser's turn, but does not help either team.

CARD_TYPE_ASSASSIN4

Assassin card. If revealed immediately ends the game with the guessing team losing.

GameEndReason indicates why a game ended.

This helps bots understand if the game ended normally or due to disqualification.

ValueNumberDescription
GAME_END_REASON_UNSPECIFIED0
GAME_END_REASON_NORMAL1

Game ended normally: all cards found for a team or the assassin was revealed.

GAME_END_REASON_RED_DISQUALIFIED2

Red team was disqualified due to bot misbehavior.

GAME_END_REASON_BLUE_DISQUALIFIED3

Blue team was disqualified due to bot misbehavior.

GAME_END_REASON_FAILED_GAME_START_NOTIFYING4

Game failed because bots did not respond to the game start notification.

GAME_END_REASON_ABORTED5

Game was aborted by the server due to some unexpected error.

GameState represents the current phase of the game.

Games cycle through spymaster and guessing phases until ended.

ValueNumberDescription
GAME_STATE_UNSPECIFIED0
GAME_STATE_SPYMASTER1

Waiting for spymaster to provide a clue.

GAME_STATE_GUESSING2

Waiting for guesser to make guesses.

GAME_STATE_ENDED3

Game has ended.

Role represents which position a bot plays in a game.

ValueNumberDescription
ROLE_UNSPECIFIED0
ROLE_SPYMASTER1

Spymaster role. This Bot gives clues to their Guesser team mate.

ROLE_GUESSER2

Guesser role. This Bot uses the Spymaster clues and reveals cards.

Team represents one of the two teams playing the game.

Red goes first and has one extra card (9 vs 8 for Blue).

ValueNumberDescription
TEAM_UNSPECIFIED0
TEAM_RED1
TEAM_BLUE2

Role filter for bot games.

ValueNumberDescription
BOT_ROLE_FILTER_UNSPECIFIED0

All roles (default).

BOT_ROLE_FILTER_SPYMASTER1

Spymaster role only.

BOT_ROLE_FILTER_GUESSER2

Guesser role only.

How to sort the leaderboard.

ValueNumberDescription
LEADERBOARD_SORT_BY_UNSPECIFIED0
LEADERBOARD_SORT_BY_ELO_RATING1

Sort the leaderboard by Bot win rate (despite the naming of the enum).

LEADERBOARD_SORT_BY_P99_LATENCY2

Sort the leaderboard by Bot P99 reponse latency.