Example Game Use Cases
Updated: Mar 25, 2026
Copy for LLM
This page walks through practical examples of using overlay views in Zero Permissions games. Each example shows the XML markup, the JavaScript integration code, and the data structures involved. Use these as starting points for your own implementation.
For a complete reference of available XML components, see Overlay View Components. To experiment interactively, try the Overlay Preview Tool.
Unity developers: The JavaScript examples below show the underlying SDK calls. The Unity Plugin provides equivalent C# APIs — see its overlay views section for Unity-specific usage.
A repository of runnable sample code is available on GitHub: fbsamples/fbinstant-nezp-samples.
Displaying the Current Player’s Profile
The simplest overlay view shows the current player’s name and photo. This is useful for profile cards, game headers, and HUD elements.
XML (
overlays/profile_card.xml):<View className="profileCard"> <Image src="{{FBInstant.player.photo}}" className="avatar" /> <Text content="{{FBInstant.player.name}}" className="playerName" /> </View>
JavaScript:
var container = document.getElementById('profileCardContainer'); FBInstant.overlayViews.createOverlayViewAsync( 'overlays/profile_card.xml', container, 'width: 200px; height: 60px; border: none;', 'overlays/styles.css' ).then(function(overlay) { overlay.showAsync(); });
The
{{FBInstant.player.photo}} and {{FBInstant.player.name}} expressions are resolved by Meta at render time. Your game code never sees the actual name or photo URL.Rendering a Friend List
Friend lists are one of the most common overlay view use cases. There are three architectural approaches, each with different tradeoffs.
Approach 1: Single Overlay with a For Loop
Render the entire friend list inside one overlay iframe. This is the simplest approach and works well for static friend lists.
XML (
overlays/friend_list.xml):<View className="friendList"> <For source="{{FBInstant.player.connectedPlayers}}" itemName="friend" sortKey="name" order="ASC" limit="20"> <View className="friendRow" onTapEvent="selectFriend_{{friend.id}}"> <Image src="{{friend.photo}}" className="avatar" /> <Text content="{{friend.name}}" className="friendName" /> </View> </For> </View>
JavaScript:
var container = document.getElementById('friendListContainer'); FBInstant.overlayViews.createOverlayViewAsync( 'overlays/friend_list.xml', container, 'width: 100%; height: 400px; border: none;', 'overlays/styles.css' ).then(function(overlay) { overlay.showAsync(); }); // Handle taps on individual friends FBInstant.overlayViews.setCustomEventHandler(function(eventStr, overlayID) { if (eventStr.startsWith('selectFriend_')) { var playerID = eventStr.replace('selectFriend_', ''); handleFriendSelected(playerID); } });
Tradeoffs: Simple to implement. The entire list renders as one iframe, so layout is consistent. However, you have less control over individual row behavior from your game code.
The following diagram shows how to render everything in a single overlay view frame:

Approach 2: Individual Overlay per Friend
Create a separate overlay iframe for each friend row. This gives your game full control over row layout and behavior, since each overlay is embedded within your own HTML structure.
XML (
overlays/friend_row.xml):<View className="friendRow"> <Image src="{{FBInstant.players[{{playerID}}].photo}}" className="avatar" /> <Text content="{{FBInstant.players[{{playerID}}].name}}" className="friendName" /> </View>
JavaScript:
FBInstant.player.getConnectedPlayersAsync().then(function(players) { players.forEach(function(player) { var rowContainer = document.createElement('div'); rowContainer.className = 'friendRowWrapper'; document.getElementById('friendList').appendChild(rowContainer); FBInstant.overlayViews.createOverlayViewAsync( 'overlays/friend_row.xml', rowContainer, 'width: 100%; height: 50px; border: none;', 'overlays/styles.css', { playerID: player.getID() } ).then(function(overlay) { overlay.showAsync(); }); // Add your own game buttons alongside the overlay var challengeBtn = document.createElement('button'); challengeBtn.textContent = 'Challenge'; challengeBtn.onclick = function() { challengePlayer(player.getID()); }; rowContainer.appendChild(challengeBtn); }); });
Tradeoffs: Maximum flexibility — you can mix overlay iframes with your own UI elements. However, creating many iframes can impact performance, so this approach works best with smaller friend lists (under ~20 rows).
The following diagram shows how to render each row in its own overlay view iframe:

Approach 3: Single Overlay with Custom Player List
Pass a custom list of player IDs as
initialData and iterate over them. This approach is useful when you want to display a filtered or custom-ordered list rather than all connected players.XML (
overlays/custom_friend_list.xml):<View className="friendList"> <For source="{{players}}" itemName="entry"> <View className="friendRow" onTapEvent="SendCoins_{{entry.playerID}}"> <Image src="{{FBInstant.players[{{entry.playerID}}].photo}}" className="avatar" /> <Text content="{{FBInstant.players[{{entry.playerID}}].name}}" className="friendName" /> <Button content="Send Coins" className="actionBtn" /> </View> </For> </View>
JavaScript:
// Get connected players, then filter or reorder as needed FBInstant.player.getConnectedPlayersAsync().then(function(connectedPlayers) { var playerList = connectedPlayers.slice(0, 10).map(function(p) { return { playerID: p.getID() }; }); var container = document.getElementById('friendListContainer'); FBInstant.overlayViews.createOverlayViewAsync( 'overlays/custom_friend_list.xml', container, 'width: 100%; height: 400px; border: none;', 'overlays/styles.css', { players: playerList } ).then(function(overlay) { overlay.showAsync(); }); }); FBInstant.overlayViews.setCustomEventHandler(function(eventStr, overlayID) { if (eventStr.startsWith('SendCoins_')) { var playerID = eventStr.replace('SendCoins_', ''); sendCoinsToPlayer(playerID); } });
The following diagram shows how to render friend info in separate overlay view frames:

Building a Custom Leaderboard
Since the built-in Global Leaderboards API is deprecated for Zero Permissions games, build leaderboards using your own backend and render player profiles with overlay views. See Global Leaderboards for the full guide.
XML (
overlays/leaderboard.xml):<View className="leaderboard"> <For source="{{entries}}" itemName="entry"> <View className="leaderboardRow"> <Text content="#{{entry.rank}}" className="rank" /> <Image src="{{FBInstant.players[{{entry.playerID}}].photo}}" className="avatar" /> <Text content="{{FBInstant.players[{{entry.playerID}}].name}}" className="playerName" /> <Text content="{{entry.score}}" className="score" /> </View> </For> </View>
JavaScript:
// Fetch leaderboard from your own backend fetch('https://yourserver.com/api/leaderboard/top?limit=10') .then(function(res) { return res.json(); }) .then(function(data) { // data.entries = [{ rank: 1, playerID: '123', score: 5000 }, ...] var container = document.getElementById('leaderboardContainer'); return FBInstant.overlayViews.createOverlayViewAsync( 'overlays/leaderboard.xml', container, 'width: 100%; height: 500px; border: none;', 'overlays/styles.css', { entries: data.entries } ); }) .then(function(overlay) { overlay.showAsync(); });
Sorting by Dynamic Keys
When your score data is stored in a separate object keyed by player ID, use nested template expressions in the
sortKey attribute to sort dynamically:XML:
<View> <For source="{{players}}" itemName="player" sortKey="{{scores[{{player.id}}]}}" order="DESC"> <View className="row"> <Text content="{{player.name}}" /> <Text content="Score: {{scores[{{player.id}}]}}" /> </View> </For> </View>
Data structure (passed as
initialData):{ "players": [ { "id": 1, "name": "Alice" }, { "id": 2, "name": "Bob" }, { "id": 3, "name": "Carol" } ], "scores": { "1": 101, "2": 222, "3": 313 } }
This renders Carol first (313), then Bob (222), then Alice (101).
Conditional Rendering
Use
If, ElseIf, and Else to display different content based on player data or game state:XML (
overlays/game_over.xml):<View className="gameOver"> <Image src="{{FBInstant.player.photo}}" className="avatar" /> <Text content="{{FBInstant.player.name}}" className="playerName" /> <If> <Condition lhs="{{score}}" operator="GREATER_THAN" rhs="{{highScore}}" /> <View className="newRecord"> <Text content="New high score: {{score}}!" className="celebration" /> </View> <Else> <View> <Text content="Score: {{score}}" /> <Text content="Best: {{highScore}}" className="muted" /> </View> </Else> </If> </View>
JavaScript:
var container = document.getElementById('gameOverContainer'); FBInstant.overlayViews.createOverlayViewAsync( 'overlays/game_over.xml', container, 'width: 300px; height: 200px; border: none;', 'overlays/styles.css', { score: currentScore, highScore: previousHighScore } ).then(function(overlay) { overlay.showAsync(); });
Context Actions from Overlays
You can trigger context switches directly from overlay view buttons, without going through your game’s JavaScript:
<View className="friendList"> <For source="{{FBInstant.player.connectedPlayers}}" itemName="friend"> <View className="friendRow"> <Image src="{{friend.photo}}" className="avatar" /> <Text content="{{friend.name}}" className="friendName" /> <Button content="Play" action="{{FBInstant.action.contextCreate({{friend.id}})}}" className="playBtn" /> </View> </For> </View>
When a player taps “Play”, the platform creates a context with that friend and switches to it. To handle the context change in your game code, register a callback:
FBInstant.onContextChange( function(contextID) { console.log('Switched to context:', contextID); // Reload game state for the new context }, function(error) { console.log('Context switch failed:', error); } );
Next Steps
- Overlay View Components — Full reference for all XML elements and attributes.
- Overlay Preview Tool — Build and test overlays in the browser without deploying a bundle.
- Social Features — Guides for specific social features like connected players, leaderboards, and notifications.
- Sample Code on GitHub — Runnable examples you can clone and modify.