

# Amazon GameLift Streams backend service and web client
<a name="sdk"></a>

 Amazon GameLift Streams enables you to stream applications through a web browser. With the Amazon GameLift Streams Web SDK, you can set up a backend streaming service. Then, end users connect to a stream through a web client. They can play your game or interact with your application all through the cloud. 

 The Amazon GameLift Streams Web SDK includes a sample backend server and a sample web client, which you can use to get started on creating a backend service. You can also use these samples to test how Amazon GameLift Streams streams, without additional development. To get started, refer to [Setting up a web server and client with Amazon GameLift Streams](setting-up-web-sdk.md). 

**Topics**
+ [Supported browsers and input](sdk-browsers-input.md)
+ [Required ports](required-ports.md)
+ [Setting up a web server and client with Amazon GameLift Streams](setting-up-web-sdk.md)
+ [Customize stream appearance](sdk-stream-appearance.md)
+ [Locale preference](sdk-locale-support.md)
+ [Mouse movement handling](sdk-mouse-movement.md)
+ [Data channel communication between an application and web client](data-channels.md)

# Supported browsers and input
<a name="sdk-browsers-input"></a>

The following lists the supported platforms and browsers for viewing Amazon GameLift Streams streams and their compatible input peripherals. Browsers must also be compatible with advanced video coding (AVC), also known as H.264.

Overall, we recommend Google Chrome, Microsoft Edge, or a custom Chromium-based desktop application for the best end-user experience and maximum compatibility, particularly with game controllers.

 To learn more about which controllers are compatible with which browsers, see the [Web Gamepad API](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API). Although some guidance may not apply to Amazon GameLift Streams, we expect most game controllers to connect successfully via Bluetooth. 

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/gameliftstreams/latest/developerguide/sdk-browsers-input.html)

## Known issues
<a name="sdk-browsers-input-known-issues"></a>

Following are known issues with browsers and input:
+ Safari will immediately exit fullscreen whenever `Esc` is pressed. This cannot be overriden.
+ “Embedded” or “in-app” browser views like those inside mobile apps such as LinkedIn, Yelp, Instagram, and others are not supported on iOS. These tend to disable the browser WebRTC support necessary for realtime interactive streaming. We recommend detecting non-standard browser strings and prompting the user to open in Safari.
+ If the screen resolution in your application is not set to 1080p, mouse tracking might be impacted. We recommend disabling the selection of any other resolution, if possible. We also recommend disabling windowed mode, and only run in full screen.
+ To support plug and play of game controllers on Proton, despite the lack of support for them in native Linux applications, games running in Proton runtime environments will *always* show a game controller connected, even if none are plugged in on the client. This could be an issue for games that prompt for controller input even when the controller is idle and unused. We recommend that games show input UI based on the last input method.

## Limitations
<a name="sdk-browsers-input-limits"></a>
+ Most runtime environments support game controllers, except for Ubuntu 22.04 LTS. If you need game controller support, consider creating the game using another runtime environment. For a list of other runtime environments, refer to [Runtime environments](configuration-options.md#configuration-options-runtime).
+ The PlayStation 5 and Luna game controllers are not supported in Firefox.
+ Haptic feedback support:
  + Haptic feedback on the PlayStation 4 and Xbox Series S/X controllers are supported in Chrome, Edge, and Safari.
  + Haptics on the PlayStation 5 DualSense controller is only supported in the Safari browser.
  + Firefox does not support haptic feedback on any controller.
  + Android and iOS devices do not support haptic feedback on any controller.
+ The **Test stream** feature in the Amazon GameLift Streams console does not support microphones.

## IPv6 support
<a name="sdk-browsers-input-ipv6-support"></a>

Streaming to IPv6-only clients is supported only with Windows runtime applications.


| Runtime | Streaming over IPv4 | Streaming over IPv6 | 
| --- | --- | --- | 
| Microsoft Windows Server 2022 Base | Yes | Yes | 
| Ubuntu 22.04 LTS | Yes | No | 
| Proton runtimes | Yes | No | 

# Required ports
<a name="required-ports"></a>

 To integrate Amazon GameLift Streams, ensure that your network infrastructure has the necessary ports open and accessible. The following is a list of the ports you should plan to have open on your network to communicate with Amazon GameLift Streams. 


| Port | Protocol | Purpose | 
| --- | --- | --- | 
|  443  |  (HTTPS) TCP  |  AWS APIs, including Amazon GameLift Streams  | 
|  33435-33465  |  UDP  |  Web RTC  | 

# Setting up a web server and client with Amazon GameLift Streams
<a name="setting-up-web-sdk"></a>

 In this tutorial, you will set up a web client application that integrates Amazon GameLift Streams' streaming service. Then, you will use the Amazon GameLift Streams Web SDK, a JavaScript library, and sample code that you can start with. The sample code includes a simple Amazon GameLift Streams backend web server and a simple web client. By the end of this tutorial, you can start a stream by using the sample code. 

 If it's your first time using Amazon GameLift Streams, we highly recommend starting with the [Starting your first stream in Amazon GameLift Streams](streaming-process.md) tutorial, which walks you through uploading a game to Amazon S3 and testing streaming it from within the Amazon GameLift Streams console in your browser. 

## Prerequisites
<a name="setting-up-web-sdk-prereq"></a>
+ An AWS account with proper credentials for programmatic access. For more information, see [Setting up Amazon GameLift Streams as a developer](setting-up.md).
+ The AWS SDK.
+ An Amazon GameLift Streams-supported web browser — see [Supported browsers and input](sdk-browsers-input.md).
+ Node.js — see [Node.js downloads](https://nodejs.org/en/download) page.

## Download the Web SDK
<a name="setting-up-web-sdk-materials"></a>

For this tutorial, you will need to download the following materials from the Resources section of the [Getting Started product page](https://aws.amazon.com/gamelift/streams/getting-started/):
+ **Amazon GameLift Streams Web SDK bundle**: This includes sample code for a simple backend service and web client.
+ **Amazon GameLift Streams Web SDK API Reference**: This API reference documents Amazon GameLift Streams API wrappers for JavaScript.

## Set up your streaming resources
<a name="setting-up-web-sdk-resources"></a>

You must have stream resources—an application and a stream group—to start a stream. Specifically, you must have:
+  An application in **Ready** status. 
+  A stream group in **Active** status with available stream capacity. 
+  For streaming in locations other than the primary location, the application must have finished replicating to that location. 

 To set up an application and a stream group using either the Amazon GameLift Streams console or Amazon GameLift Streams CLI, refer to [Prepare an application in Amazon GameLift Streams](applications.md) and [Manage streaming with an Amazon GameLift Streams stream group](stream-groups.md), respectively. Alternatively, for an end-to-end walkthrough in the Amazon GameLift Streams console, refer to [Starting your first stream in Amazon GameLift Streams](streaming-process.md). 

## Set up a backend server
<a name="setting-up-web-sdk-backend"></a>

 The backend server is responsible for handling tasks such as authenticating users, configuring stream parameters, and performing Amazon GameLift Streams service API calls on behalf of end-users. Review the sample code and the Amazon GameLift Streams Web SDK API Reference to learn more about setting this up. Specifically, see the server.js file in the Amazon GameLift Streams Web SDK package. 

**Important**  
 This code is example code for testing and evaluation purposes only and should not be used in a production capacity. 

**To run the sample backend service**

1.  Open a terminal or command prompt and navigate to the folder `AmazonGameLiftStreamsWebSDK\GameLiftStreamsSampleGamePublisherService\`. 

1.  Run the following commands: 

   ```
   npm install
   node server.js
   ```

 With the sample backend service running, end-users can connect to a stream through the web client. Test the web client in the next step. 

## Launch a web client
<a name="setting-up-web-sdk-client"></a>

The web client application is responsible for receiving and decoding Amazon GameLift Streams streams, streaming to end-users, and providing the web browser UI for end-users to engage with the application. Review the sample code and the Amazon GameLift Streams Web SDK API Reference to learn more about how to integrate the JavaScript Amazon GameLift Streams Web SDK into your own web client application. Specifically, see `public/index.html` in the Amazon GameLift Streams Web SDK package. You can also look at the web page source when you launch a web client in your browser.

**Note**  
The Windows runtime in Amazon GameLift Streams supports stream sessions over IPv4 or IPv6. However, Linux and Proton runtime environments only support streaming over IPv4.

**To launch a web client application**

1.  Open a web browser and navigate to `http://localhost:port/`. The port number is set by the backend server; by default, this is HTTP port 8000. 

1. Play the game or use the software.

   1. To attach input, such as your mouse, choose **Attach input**.

   1. To exit the game, choose the **Esc** key.

   1. To stop the server process, choose **Ctrl\$1C** key.

## Clean up streaming resources
<a name="setting-up-web-sdk-cleanup"></a>

**Warning**  
 A stream group incurs costs when it has allocated streaming capacity, even if that capacity is unused. To avoid unnecessary costs, scale your stream groups to your required size. We suggest during development that you scale always-on capacity and target-idle capacity in your stream groups to zero when not in use. For more information, refer to [Scale stream groups to zero capacity](pricing.md#pricing-pause-stream-groups).

After you complete the tutorial and no longer need to stream your application, follow these steps to clean up your Amazon GameLift Streams resources.

**Deleting a stream group**

 When you delete a stream group, Amazon GameLift Streams works to release all stream capacity. 

**To delete a stream group using the Amazon GameLift Streams console**

1.  Sign in to the AWS Management Console and open the [Amazon GameLift Streams console](https://console.aws.amazon.com/gameliftstreams/). 

1.  To view a list of your existing stream groups, in the navigation pane, choose **Stream groups**. 

1.  Choose the name of the stream group that you want to delete. 

1.  On the stream group detail page, choose **Delete**. 

1.  In the **Delete** dialog box, confirm the delete action. 

 Amazon GameLift Streams begins releasing compute resources and deleting the stream group. During this time, the stream group is in **Deleting** status. After Amazon GameLift Streams deletes the stream group, you can no longer retrieve it. 

**Deleting an application**

 You can only delete an application that meets the following conditions: 
+  The application is in the **Ready** or **Error** state. 
+  An application is not streaming in any ongoing stream session. You must wait until the client ends the stream session or call [TerminateStreamSession](https://docs.aws.amazon.com/gameliftstreams/latest/apireference/API_TerminateStreamSession.html) in the Amazon GameLift Streams API to end the stream. 

 If the application is linked to any stream groups, you must unlink it from all associated stream groups before you can delete it. In the console, a dialog box will walk you through this process. 

**To delete an application using the Amazon GameLift Streams console**

1. Sign in to the AWS Management Console and open the [Amazon GameLift Streams console](https://console.aws.amazon.com/gameliftstreams/).

1. In the navigation bar, choose **Applications** to view a list of your existing applications. Choose the application you want to delete. 

1. In the application detail page, choose **Delete**. 

1. In the **Delete** dialog box, confirm the delete action. 

 Amazon GameLift Streams begins deleting the application. During this time, the application is in `Deleting` status. After Amazon GameLift Streams deletes the application, you can no longer retrieve it. 

# Customize stream appearance
<a name="sdk-stream-appearance"></a>

## Loading screen
<a name="sdk-loading-screen"></a>

When a customer opens a web browser to view a stream, the web client starts establishing a connection to the Amazon GameLift Streams stream session. While the stream session loads, you can display a custom background and logo to the customer's screen.

The Amazon GameLift Streams Web SDK sample client, in the `GameLiftStreamsSampleGamePublisherService/public/LoadingScreen/loadingscreen.js` file, demonstrates how you can implement an animated logo in your front-end web client. The default loading screen consists of 2 images: background and foreground. The foreground image is positioned in the middle and has a pulse animation. The animation plays only while the stream session is connecting.

**To enable a loading screen**

1. In the Amazon GameLift Streams Web SDK sample client, navigate to the `GameLiftStreamsSampleGamePublisherService/public/LoadingScreen/` folder.

1. Add your background and foreground images using the default names, `Background.png` and `LoadingLogo.png`. If you want to rename them or use a different image format, you must update the code in `GameLiftStreamsSampleGamePublisherService/public/loadingscreen.js`.

1. (Optional) In `GameLiftStreamsSampleGamePublisherService/public/loadingscreen.js`, update the JavaScript code to implement different animations.

# Locale preference
<a name="sdk-locale-support"></a>

 In Amazon GameLift Streams, you can set the locale preference per stream. This is useful if your application retrieves location-specific information from the end user's operating system, such as time or currency. 

 Amazon GameLift Streams supports the following languages: 


| Value | Description | 
| --- | --- | 
|  `en_US`  |  U.S. English (default)  | 
|  `ja_jp.UTF-8`  |  Japanese  | 

 **To change the locale setting** 

 When you call [StartStreamSession](https://docs.aws.amazon.com/gameliftstreams/latest/apireference/API_StartStreamSession.html) using the Amazon GameLift Streams API, add `LANG=<language>` to your `AdditionalEnvironmentVariables`. Since locale preference is unique per user, you set this at the stream-session level. If you don't set this, the stream uses U.S. English by default. 

**Example**  

```
aws gameliftstreams start-stream-session \
   --identifier arn:aws:gameliftstreams:us-west-2:123456789012:streamgroup/1AB2C3De4 \
   --protocol WebRTC \
   --signal-request "[webrtc-ice-offer json string]" \
   --user-id xnshijwh \            
   --additional-environment-variables '{"LANG": "ja_JP.UTF-8"}'
```

# Mouse movement handling
<a name="sdk-mouse-movement"></a>

Mouse movement handling is critical for delivering responsive and intuitive user experiences in streamed applications. Amazon GameLift Streams automatically optimizes mouse input transmission based on your application's cursor behavior, ensuring that mouse movements feel natural whether the cursor is hidden or visible. Understanding how Amazon GameLift Streams processes mouse events helps you design applications that work seamlessly with the streaming service and provide the best possible user experience.

## Mouse input modes
<a name="sdk-mouse-input-modes"></a>

Amazon GameLift Streams uses two distinct modes for transmitting mouse events to your application, automatically selecting the appropriate mode based on cursor visibility:

Relative mode  
In relative mode, mouse updates are transmitted as small, incremental differences from the previous position. This mode is ideal for applications that require precise, continuous mouse movement tracking, such as first-person shooter (FPS) games or interfaces that use 3D orientation. Amazon GameLift Streams uses relative mode when the operating system cursor is hidden or fully transparent.

Absolute mode  
In absolute mode, the mouse cursor position is transmitted as an exact screen coordinate. This mode works well for applications that rely on precise cursor positioning, such as point-and-click games or any UI with clickable elements. Amazon GameLift Streams uses absolute mode when the operating system cursor is visible, even if your application displays a custom cursor image.

This automatic selection ensures optimal performance for different application types without requiring manual configuration.

## Pointer lock
<a name="sdk-pointer-lock"></a>

Pointer lock is a web API feature that captures the mouse cursor within a specific element, hiding the cursor and preventing it from leaving the designated area. This feature is particularly valuable for games that require unrestricted mouse movement for camera control or aiming, without the distraction of a visible cursor or the limitation of reaching window edges.

Amazon GameLift Streams provides automatic pointer lock functionality through the `autoPointerLock` property in the Web SDK's `InputConfiguration` interface. This feature integrates with the [requestPointerLock API](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestPointerLock) to provide intuitive and context-aware mouse capture.

### Automatic pointer lock behavior
<a name="sdk-pointer-lock-behavior"></a>

Amazon GameLift Streams automatically enables pointer lock when the application is fullscreen and the remote cursor is invisible on the stream host. This behavior aligns well with common game development patterns:
+ **FPS/TPS games and 3D orientation control** - The pointer is automatically locked and the cursor is hidden, providing unrestricted camera control essential for FPS gameplay.
+ **Point-and-click games and UI control** - When games make the cursor visible for menu interactions or strategy gameplay, the pointer remains visible and unlocked, preserving the intended user experience.

### Configuration options
<a name="sdk-pointer-lock-configuration"></a>

The `autoPointerLock` property accepts the following values:

`true`  
The mouse is always captured when the remote cursor is invisible.

`false`  
The mouse is never captured, regardless of cursor visibility.

`'fullscreen'` (default)  
The mouse is only captured when the video element is in fullscreen mode and the remote cursor is invisible.

**Important**  
`autoPointerLock` has no effect in the Safari browser or on iOS platforms due to platform limitations.

## Best practices
<a name="sdk-mouse-best-practices"></a>

To ensure optimal mouse handling in your streamed applications:
+ **Always stream fullscreen** - Your application should already be running in fullscreen mode to work properly on our service. In addition, we recommend using browser support to make the stream a fullscreen element for the best end-user experience. This will help avoid problems such as alignment issues between the system cursor and software cursor.
+ **Hide the cursor for relative motion** - If your application expects relative mouse motion (such as FPS-style camera controls or drag-based interactions), hide the operating system cursor during those interactions. In some scenarios, you might need to hide the cursor on mouse-down and show it again on mouse-up.
+ **Show the cursor for absolute positioning** - When your application needs precise cursor positioning for UI interactions, ensure the operating system cursor remains visible to enable absolute coordinate mode.
+ **Test different input scenarios** - Verify that your application handles both relative and absolute mouse modes correctly, as Amazon GameLift Streams may switch between modes based on your cursor visibility changes.
+ **Test different window modes** - Test your application's mouse handling in both windowed and fullscreen modes, if applicable. Determine which `autoPointerLock` setting is best for your input configuration.

# Data channel communication between an application and web client
<a name="data-channels"></a>

 Data channels allow you to securely communicate arbitrary messages between your Amazon GameLift Streams application and the web client (the JavaScript code running in the end-user's web browser). This allows end-users to interact with the application that Amazon GameLift Streams is streaming, via the web browser where they're viewing the stream. 

Here are some example use cases of data channels in Amazon GameLift Streams:
+ Users can open URLs in the application in their local browser.
+ Users can pass content in the clipboard back and forth to the application.
+ Users can upload content from their local machine to the application.
+ Developers can implement UI in the browser that sends commands to the application.
+ Users can pass schemas to control display of visualization layers.

## Features
<a name="data-channels-features"></a>

**Message size limits**  
Amazon GameLift Streams Web SDK imposes a maximum size limit of 64 KB (65536 bytes) per message. This ensures that the message size limits are compatible with most browsers, and that the communication has low impact on the total bandwidth of the stream.

**Metrics**  
 Metrics on your data channel usage are sent to your AWS account when a stream session ends. For more information, refer to [Data channels](monitoring-cloudwatch.md#monitoring-data-channels) in the *Monitoring Amazon GameLift Streams* section. 

## Using data channels
<a name="data-channels-using"></a>

The Amazon GameLift Streams Web SDK provides the `sendApplicationMessage` function that sends a message as a byte array to the application. The message is processed by a callback function, `clientConnection.applicationMessage` that you define.

If the client sends messages before the application connects to the data channel port, the messages are queued. Then, when the application connects, it receives the messages. However, if the application sends messages before the client connects to the data channel port, the messages are lost. The application must check the connection state of the clients before sending a message.

## On the client-side
<a name="data-channels-using-client"></a>

Write the following code in your web client application.

1.  Define the callback function to receive incoming messages from the application. 

   ```
   function streamApplicationMessageCallback(message) {
       console.log('Received ' + message.length + ' bytes of message from 
       Application');
   }
   ```

1.  Set `clientConnection.applicationMessage` to your callback function. 

   ```
   clientConnection: {
       connectionState: streamConnectionStateCallback,
       channelError: streamChannelErrorCallback,
       serverDisconnect: streamServerDisconnectCallback,
       applicationMessage: streamApplicationMessageCallback,
   }
   ```

1.  Call the `GameLiftStreams.sendApplicationMessage` function to send messages to your application. You can call this any time, as long as the stream session is active and the input is attached. 

As an example, refer to the Amazon GameLift Streams Web SDK sample client, which demonstrates how to set up a simple data channel on the client-side.

## On the application-side
<a name="data-channels-using-application"></a>

Write the following logic in your application.

### Step 1. Connect to the data channel port
<a name="data-channels-using-application-1"></a>

When your application starts, connect to port `40712` on `localhost`. Your application should maintain this connection for the entire duration of execution. If the application closes the connection, it cannot be reopened.

### Step 2. Listen for events
<a name="data-channels-using-application-2"></a>

An event starts with a fixed-size header, followed by variable-length associated data. When your application receives an event, parse the event to retrieve the information.

**Event format**
+ **Header**: A 4-byte header in the form `abcc`
  +  `a` : Client id byte. This identifies a specific client connection, in the case of multiple connections (due to disconnection and reconnection).
  +  `b` : Event type byte. `0` - the client connected, `1` - the client disconnected, `2` - a message is sent from the client. Other event types may be received with future Amazon GameLift Streams service updates, and should be ignored.
  +  `cc` : Length of the associated event data. This is represented as 2 bytes with big-endian ordering (first byte is the most significant). If the event type is 2, the event data represents the message contents from the client.
+ **Data**: The remaining bytes contain the event data, such as a client message. The length of the data is indicated by `cc` in the header.

**To listen for events**

1. Read the four header bytes to retrieve the client id, event type, and length of the event data.

1. Read the variable-length event data, regardless of the client id and event type, according to the length described in the header. It's important to read the data unconditionally so that event data is never left in the buffer, where it could be confused with the next event header. Do not make assumptions about the length of the data based on event types.

1. Take appropriate action based on the event type, if recognized by your application. This action might include logging an incoming connection or disconnection, or parsing the client message and triggering application logic.

### Step 3. Transmit messages to the client
<a name="data-channels-using-application-3"></a>

The application should transmit messages with the same four-byte header format used by incoming events.

**To transmit a message to the client**

1. Write the header with the following properties:

   1. `a` : Client id byte. If your message is in response to a client message, it should reuse the same client id as the incoming client message, to avoid race conditions such as delivering a response from an old client connection to a newly reconnected client. If your application is sending an unsolicited message to the client, it should set the client id to match the most recent "client connection" event (event type 0).

   1. `b` : The event type of outgoing messages must always be 2. The client ignores messages with other event types.

   1. `cc` : Length of the message, in bytes.

1. Write the message bytes.

The message delivers to the specified client, unless the client disconnects. When a disconnected client reconnects, a new client ID is assigned via a client connected event. Any undelivered messages for the old client ID are discarded.

**Example**  
The following pseudo-code demonstrates the logic to communicate messages in the application-side. For a complete example using Winsock, refer to [Complete Winsock Client Code](https://learn.microsoft.com/en-us/windows/win32/winsock/complete-client-code) in the Windows Sockets 2 documentation.  

```
connection = connect_to_tcp_socket("localhost:40712")
loop:
    while has_pending_bytes(connection):
        client_id = read_unsigned_byte(connection)
        event_type = read_unsigned_byte(connection)
        event_length = 256 * read_unsigned_byte(connection)
        event_length = event_length + read_unsigned_byte(connection)
        event_data = read_raw_bytes(connection, event_length)
        if message_type == 0:
            app_process_client_connected(client_id)
        else if message_type == 1:
            app_process_client_disconnected(client_id)
        else if message_type == 2:
            app_process_client_message(client_id, event_data)
        else:
            log("ignoring unrecognized event type")
    while app_has_outgoing_messages():
        target_client_id, message_bytes = app_next_outgoing_message()
        message_length = length(message_bytes)
        write_unsigned_byte(connection, target_client_id)
        write_unsigned_byte(connection, 2)
        write_unsigned_byte(connection, message_length / 256)
        write_unsigned_byte(connection, message_length mod 256)
        write_raw_bytes(connection, message_bytes)
```