Second Screen
Over 30% of Overwolf users have multiple screens and is often unused during gameplay. This creates a great opportunity to enhance user experience and increase engagement without disrupting the game. Since many users keep the second screen open throughout gameplay, you can leverage it for better monetization by boosting ad visibility leading to more revenue.
Types of second Screens and when to use them
- Main window (Typical size)—similar in size to a desktop window. It’s ideal for displaying extensive information or large item lists. This window also provides better monit options (i.e., larger ad placements).
- Companion screen (Compact Size)—this is a smaller, more condensed window and is best used for displaying limited yet essential information. without overwhelming the user.
- Multi-app screens—multiple windows in your app can display specific types of data. When you display multiple windows on a second monitor you make more content accessible at the same time providing more monetization opportunities and increased content visibility. Keep in mind that:
- Users cannot interact with this screen during gameplay, so ensure all the content is viewable at a glance.
- Excessive content may feel overwhelming or spammy to users, so prioritize value-driven information.
Building a second window experience is just as simple as creating a normal window which communicates with GEP and has a transparent background window.
Accessibility and customization
Accessability and customization of your app on a second screen is important. Use the following guidelines:
- Second screen windows should launch automatically.
- Second screen windows should include a hotkey or a close button at the top.
- Allow users to adjust screen size for comfort and flexibility. If resizing isn't supported, design the window to fit the most common screen sizes, using 1920X1080 as the default.
- Enable hotkey support for quick toggling.
Implement second-screen functionality early in the development of your app. This will help if you want to add monetization options later in your app's lifecycle.
Second screen guidelines
When building the second screen window, follow these recommendations:
- Keep the window location of your app in the same place on the screen.
- Keep your app window on the desktop.
- Create a desktop only window (which improves performance).
- If you app runs on a second screen with the game, disable any kind of hardware acceleration on the GPU. This helps improve app performance.
- Identify which screen is the second screen so that you can properly calculate where you can display your app's window.
- Use the transparent background window to share data and have your app windows communicate.
Setting up second screen support
As a best practice when adding second screen support, you should give users explicit control over which display the app appears on, handle the multi-monitor layout automatically when a game launches, and ensure the window looks correct regardless of the target display's resolution and DPI scaling. In practice this means:
- Display picker—populate the display list at runtime from the OS, not hardcoded values, and let the user select their preferred screen from settings.
- Persisted choice—save the selected display ID across sessions and fall back silently to the primary display if that monitor is disconnected.
- Game-aware relocation—use the Overwolf overlay package to detect which display the game is running on and automatically move the app to a different screen.
- DPI-aware sizing—calculate window dimensions in physical pixels so the window occupies the same visual proportion on every monitor, regardless of scale factor.
Display Detection and Screen Selection
Use Electron's screen module (screen.getAllDisplays(), screen.getPrimaryDisplay()) to enumerate connected displays, and expose the results to the renderer via two ipcMain handlers: one that returns the display list alongside the currently saved selection, and one that accepts a display ID, moves the window to that display, and persists the choice. The display list should include each display's id, label, bounds (width/height), scaleFactor, and primary status. Everything the renderer needs to build a meaningful dropdown label. Pair these handlers with matching contextBridge entries in the preload script.
On the renderer side, call getDisplays() on mount to populate the list and pre-select the saved display (falling back to the primary). Each option label should surface the display name, resolution, and scale factor so users can identify their screens at a glance. When the selection changes, call setWindowDisplay(id) immediately. No save button needed, the window moves in real time.
Auto-Detection on Game Launch
Use the Overwolf overlay package to read GameWindowInfo.screen retrieving the Electron Display the game is running on, and move the app to a different display automatically.
private _gameScreenDetected = false;
// Primary: available immediately after injection via getActiveGameInfo()
this._overlayApi.on('game-injected', async (gameInfo) => {
const active = this._overlayApi.getActiveGameInfo();
if (!this._gameScreenDetected && active?.gameWindowInfo?.screen) {
this._gameScreenDetected = true;
this.emit('game-screen-detected', active.gameWindowInfo.screen);
}
});
// Fallback: game-window-changed always carries screen info (since overlay v1.5.11)
this._overlayApi.on('game-window-changed', (window, game, reason) => {
if (!this._gameScreenDetected && window.screen) {
this._gameScreenDetected = true;
this.emit('game-screen-detected', window.screen);
}
});
this._overlayApi.on('game-exit', (info) => {
this._gameScreenDetected = false;
this.emit('game-exit', info);
});
In the main window controller, listen for the emitted 'game-screen-detected' event. Use Electron's screen.getDisplayNearestPoint() against the center of the current window bounds to determine which display the app is on, then compare it to the game's display ID. If they match, pick any other display from screen.getAllDisplays() and move it to there without updating selectedDisplayId, so the user's saved preference is preserved. On 'game-exit', resolve the target display from the saved preference and move back.
Auto-Sizing for Screen Resolution and Scaling
BrowserWindow bounds are in logical pixels (physical px ÷ scaleFactor), so a fixed window size looks different across monitors with varying DPI settings. To keep the window visually proportional on every display, calculate the target size in physical pixels against a known reference resolution (e.g. 1920×1080), then divide back by the target display's scaleFactor to get the logical pixel dimensions to pass to setBounds. Clamp the result to 96% of the display's workArea and enforce a minimum size to keep the UI usable.
When moving across monitors with different DPI settings, avoid calling setBounds directly since Windows interprets the coordinates in the source display's DPI context, which produces incorrect sizing on the target display. Instead, first call setPosition with a point clearly inside the target display's workArea to switch the window's per-monitor DPI context, then immediately follow with setBounds for the final position and size. Also call unmaximize() before either call, since maximized windows silently ignore setBounds.
Persisting the Display Choice
Write the selected display ID as JSON to a file in app.getPath('userData'). On startup, read that file and look up the saved ID in screen.getAllDisplays(). If the display is found, use it; if not (e.g. it was unplugged since the last session), clear the saved value and fall back to screen.getPrimaryDisplay(). Load the settings inside createAndShow() rather than the constructor so that app.getPath('userData') is available since it requires app.whenReady() to have resolved first.