Upload Bundle
Updated: Apr 24, 2026
Copy for LLM
Your Instant Game is delivered to players as a bundle -- a ZIP file containing all of your game’s client-side assets.
Preparing your bundle
Bundle Structure
Your game bundle is a standard ZIP file that must contain an
index.html file at its root. When a player opens your game, Facebook loads this index.html file, which is the entry point for your game.A typical bundle structure looks like this:
my-game.zip
|-- index.html (required - game entry point)
|-- fbapp-config.json (required - Instant Games configuration)
|-- game.js (your game code)
|-- style.css (your styles)
|-- assets/
| |-- sprites.png
| |-- background.jpg
| |-- sounds/
| |-- music.mp3
| |-- sfx-jump.mp3
|-- lib/
|-- phaser.min.js (or any game framework you use)
Required files
index.html
Your
index.html file must be at the root of the ZIP file (not inside a subdirectory). This is the file Facebook loads when a player opens your game.Your
index.html must include the Instant Games SDK script tag:<script src="https://connect.facebook.net/en_US/fbinstant.8.0.js"></script>
Note: Always use the latest SDK version available. Check the SDK Reference for the current version number.
A minimal
index.html looks like this:<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <title>My Game</title> <script src="https://connect.facebook.net/en_US/fbinstant.8.0.js"></script> </head> <body> <script src="game.js"></script> </body> </html>
fbapp-config.json
The
fbapp-config.json file must also be at the root of the ZIP file. It contains configuration settings that Facebook reads when serving your game.A basic
fbapp-config.json file looks like this:{ "instant_games": { "platform_version": "8.0" } }
The
platform_version field specifies which version of the Instant Games platform your game targets.You can also include additional configuration in this file, such as navigation menu settings:
{ "instant_games": { "platform_version": "8.0", "navigation_menu_enabled": true } }
Upload methods
There are two ways to upload your game bundle to Facebook: manually through the App Dashboard, or programmatically through the Graph API.
Method 1: App Dashboard (manual upload)
This is the simplest method and is recommended for most developers, especially during initial setup and testing.
- Go to your app on the App Dashboard.
- In the left sidebar, navigate to Instant Games > Web Hosting (or Instant Games > Bundle Upload, depending on the current dashboard layout).
- Click the Upload Bundle button (shown as an upload icon with “+” or “Upload Version”).
- Select your ZIP file from your computer.
- Wait for the upload to complete. Depending on the file size and your internet connection, this may take a few seconds to several minutes.
- Once uploaded, the new version will appear in the version list with a version number and upload timestamp.
After uploading, you can select a version to push to production (see Managing Versions below).
Method 2: Graph API (programmatic upload)
For automated workflows, CI/CD pipelines, or frequent uploads, you can upload bundles programmatically using the Facebook Graph API. This is a two-step process: first you request an upload session ID, then you upload the ZIP file using that session ID.
Choosing your upload endpoint
There are two upload endpoints, and the one you use depends on your access token type. The upload endpoints differ only in Step 2 (the binary upload URL). Steps 1 and 3 are identical regardless of which endpoint you use, and both endpoints produce the same result -- your bundle is uploaded and processed the same way.
| Your access token | Token prefix | Upload namespace (Step 2) |
|---|---|---|
User access token from the Gaming domain (from the App Dashboard) | GG | gg_graph_api |
User access token from the Facebook domain | EAA | fb_game_bundle |
System User access token (from Meta Business Suite) | EAA | fb_game_bundle |
Note: If you are not sure which token type you have, check the token prefix. Tokens starting withGGuse thegg_graph_apinamespace. Tokens starting withEAAuse thefb_game_bundlenamespace.
If you are setting up automated uploads for a CI/CD pipeline, use a System User access token with the
fb_game_bundle endpoint. System User tokens do not expire, so your pipeline will not break when a personal token expires. See Setting up a System User access token for CI/CD below.Prerequisites
- A user access token or System User access token with admin or developer permissions on the app. To get a user access token, go to the Instant Games > Web Hosting section of the App Dashboard and click the Get Asset Upload Access Token button. You can also find your tokens at https://developers.facebook.com/tools/accesstoken -- your App Access Token appears as
GG|{app-id}|{app-access-token}, and your User Token appears above it. If you do not see your User Access Token listed, request one using the link provided, which takes you to the Graph API Explorer tool. - An app access token (needed only for pushing to production via Graph API).
- curl or any HTTP client.
Setting up a System User access token for CI/CD
For automated workflows, you can use a System User access token instead of a personal user access token. System User tokens do not expire, which makes them ideal for CI/CD pipelines. System User tokens are Facebook-domain tokens (prefixed with
EAA), so they use the fb_game_bundle upload namespace in Step 2.To create a System User access token:
- Go to Meta Business Suite and open Business settings.
- In the left sidebar, click Users > System users.
- Click Add to create a new System User. Enter a descriptive name (for example,
game-deploy-bot) and select the Admin role. - After creating the System User, click its name in the list to open its details.
- Click Assign assets. Select Apps, find your game app, and grant the System User the Manage app permission. Click Save changes.
- Click Generate new token. In the dialog, select your game app. For token expiration, select Never to create a non-expiring token. You do not need to select any additional permissions for bundle uploads.
- Click Generate token. Copy the token immediately -- you will not be able to view it again.
Important: Treat System User tokens like passwords. Store them in a secrets manager or CI/CD environment variable. Do not commit them to version control.
Note: System User access tokens work with Step 1 (getting an upload session ID) and Step 2 (uploading the bundle via thefb_game_bundlenamespace). For Step 3 (pushing to production), use an app access token ({app-id}|{app-access-token}).
Step 1: Get an upload session ID
Request an upload session ID by calling the Graph API:
curl -i -X POST \
"https://graph.facebook.com/v24.0/{app-id}/uploads?file_name={file-name}&file_length={file-length-in-bytes}&file_type=application/zip&access_token={user-access-token}"
On success, the API returns a JSON response containing the session ID:
{ "id": "upload:{session-id}" }
Replace the following placeholders:
| Placeholder | Description |
|---|---|
{app-id} | Your Facebook app ID (found on the App Dashboard under Settings > Basic). |
{file-name} | The name of your ZIP file (for example, my-game.zip). |
{file-length-in-bytes} | The size of your ZIP file in bytes. |
{user-access-token} | A valid user access token or System User access token with admin or developer permissions on the app. |
This step works the same way regardless of whether you use a GG-domain token or an FB-domain token. The API routes internally based on your token type.
Step 2: Upload the Bundle
Use the session ID from Step 1 to upload your ZIP file. The upload URL depends on your token type -- see Choosing your upload endpoint for details. This call returns a playable link and the bundle instance ID.
curl -i -X POST "https://rupload.facebook.com/{upload-namespace}/upload:{session-id}" \
-H "Authorization: OAuth {access-token}" \
-H "Offset: 0" \
-H "X-Entity-Length: {file-length-in-bytes}" \
-H "content-length: {file-length-in-bytes}" \
-H "type: BUNDLE" \
-H "comment: Optional bundle upload comment" \
-H "name: {file-name}" \
--data-binary @./{file-name}
| Placeholder | Description |
|---|---|
{upload-namespace} | gg_graph_api if your token starts with GG, or fb_game_bundle if your token starts with EAA (including System User tokens). |
{access-token} | Your user access token or System User access token. |
After the upload completes, your game version appears in the list of uploaded bundles on the Web Hosting tab of the App Dashboard.
Step 3: Push to production via Graph API (optional)
To push an uploaded bundle version to production programmatically, use the following API call with the
{bundle-instance-id} returned from the upload in Step 2:curl -i -X POST "https://api.facebook.com/instant-games/assets/{app-id}/push-to-production" \
-H "Content-Type: application/json" \
-H "Authorization: OAuth {app-id}|{app-access-token}" \
-H "X-API-Version: 1.0.0" \
-d '{"bundle_instance_id": "{bundle-instance-id}"}'
Note: The bundle must finish processing before you can push it to production. Allow a few minutes after upload before making this call.
Full example: Automated upload script
Here is a complete example of a shell script that uploads a bundle:
APP_ID="<APP_ID>" ACCESS_TOKEN="<ACCESS_TOKEN>" BUNDLE_COMMENT="<BUNDLE_COMMENT>" FILENAME="<FILE_NAME>" # Set to "gg_graph_api" for GG-domain tokens (prefix: GG) # Set to "fb_game_bundle" for FB-domain tokens (prefix: EAA), including System User tokens UPLOAD_NAMESPACE="gg_graph_api" FILE_LENGTH=$(stat -f%z "./$FILENAME") echo "FILE_LENGTH: $FILE_LENGTH" # Get Session Id SESSION_RESP=$(curl -X POST \ "https://graph.facebook.com/v24.0/$APP_ID/uploads?file_name=$FILENAME&file_length=$FILE_LENGTH&file_type=application/zip&access_token=$ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -s) SESSION_ID=$(echo $SESSION_RESP | jq -r '.id') echo "SESSION_ID: $SESSION_ID" # Upload Bundle curl -v -X POST "https://rupload.facebook.com/$UPLOAD_NAMESPACE/$SESSION_ID" \ -H "Authorization: OAuth $ACCESS_TOKEN" \ -H "Offset: 0" \ -H "X-Entity-Length: $FILE_LENGTH" \ -H "content-length: $FILE_LENGTH" \ -H "type: BUNDLE" \ -H "comment: $BUNDLE_COMMENT" \ -H "name: $FILENAME" \ --data-binary @"./$FILENAME"
Security note: Do not hard-code your access token in scripts that are committed to version control. Use environment variables or a secrets manager instead.
Managing versions
How versioning works
Each time you upload a bundle, Facebook creates a new version of your game. Versions are numbered sequentially (1, 2, 3, and so on) and are independent of each other. Uploading a new version does not automatically make it the live version -- you must explicitly select which version is live.
This versioning system allows you to:
- Test new versions before pushing them to production.
- Roll back to a previous version if you discover issues in a new release.
- Keep a history of all uploaded versions for reference.
Selecting the live version
To choose which version players see:
- Go to Instant Games > Web Hosting on the App Dashboard.
- You will see a list of all uploaded versions, each with a version number and a timestamp.
- Find the version you want to make live.
- Click the Push to Production button (shown as a star icon or “Push to Production” link) next to the version.
- Confirm the action.
The selected version will become the live version within a few minutes. Players who start new game sessions will load the new version. Players who are currently in an active session will continue using the previous version until they start a new session.
Testing a version before going live
Before pushing a version to production, you can test it by selecting the version and clicking the Stage for Testing button. This makes the version available only to users with roles on your app (admins, developers, and testers) without affecting the live version that regular players see.
Testing workflow:
- Upload a new bundle version.
- Stage the version for testing.
- Open the game as a tester and verify everything works.
- If everything looks good, push the version to production.
- If there are issues, upload a fixed version and repeat.
Upload size limits
| Limit | Value |
|---|---|
Maximum bundle size | 200 MB |
Recommended initial load | Under 5 MB |
Maximum single file size | 200 MB (the ZIP file itself) |
While the maximum bundle size is 200 MB, keep in mind that larger bundles take longer to download and can significantly increase load times for players, especially those on slower connections. The platform evaluates load time during Quality Review, and games that take too long to load may be rejected.
Strategies for staying under the limit:
- Use compressed image and audio formats.
- Implement lazy loading for assets that are not needed immediately.
- Consider hosting large assets on your own CDN and loading them at runtime rather than including them in the bundle.
- Remove unused assets, test files, and development tools from the bundle.
Bundle best practices
- Keep the bundle small. The maximum bundle size is 200 MB, but smaller bundles load faster and provide a better player experience. Aim for the smallest bundle possible -- ideally under 5 MB for the initial load, with additional assets loaded progressively.
- Compress images and audio. Use optimized image formats (WebP where supported, compressed PNG/JPG otherwise) and compressed audio formats (MP3, OGG). Avoid uncompressed BMP or WAV files.
- Minify your JavaScript. Use tools like Terser, UglifyJS, or your bundler’s built-in minification to reduce JavaScript file sizes.
- Do not include unnecessary files. Remove development files, source maps, documentation, node_modules, and any files that are not needed at runtime.
- Use progressive loading. Load only the assets needed for the first screen immediately. Load additional assets (such as later levels, optional content, or high-resolution textures) asynchronously after the game starts.
- Test the ZIP file locally. Before uploading, extract the ZIP file to a temporary directory and open
index.htmlin a browser to verify it works correctly.
Common upload issues
“index.html not found”
The most common upload error. Ensure that
index.html is at the root of the ZIP file, not inside a subdirectory. If you create the ZIP from a folder named build/, make sure you zip the contents of the folder, not the folder itself.Correct:
my-game.zip
|-- index.html
|-- game.js
Incorrect:
my-game.zip
|-- build/
|-- index.html
|-- game.js
“File too large”
Your ZIP file exceeds the 200 MB limit. Optimize your assets or use progressive loading to reduce the bundle size.
Upload fails silently
Check your internet connection and try again. If the problem persists, verify that your access token is valid and that you have the appropriate role (admin or developer) on the app.
Version does not appear after upload
Allow a few minutes for the version to process. If it still does not appear, try refreshing the App Dashboard page.
If you receive a
400 Bad Request or 401 Unauthorized error during Step 2 (the binary upload), check that your token type matches the upload namespace in the URL:- If your token starts with
GG, usegg_graph_api. - If your token starts with
EAA, usefb_game_bundle.
Using a GG-domain token with the
fb_game_bundle endpoint, or an FB-domain token with the gg_graph_api endpoint, will fail with an authorization error. See Choosing your upload endpoint for details.Next steps
After uploading your bundle:
- Test your game by staging the version and playing it as a tester.
- Submit for review -- see Reviews to understand the review process and prepare your submission.
- Go live -- once your game passes all reviews, push the version to production. See Game Launch for the full launch process.