Docs
Everything the Godot and Unity plugins can do, and the HTTP API for any other engine. Use the key pxd_sandbox to try anything here: you get example cards and nothing is recorded.
Godot plugin
Project settings
Project, Project Settings, Pixeldoor.
| Setting | What it does |
|---|---|
api_key | Your game’s key. Empty means test mode with example cards. |
open_mode | overlay_store (default) opens the Steam overlay store page. overlay_webpage opens the tracked link in the overlay. browser always uses the browser. |
send_context | On by default. Turn off to stop sending platform, language and country. |
Card properties
Select the card in your scene and change these in the inspector.
| Property | What it does |
|---|---|
| Placement | Name of the screen, like menu or gameover. Shows up in your stats. |
| Source | network: games from other devs. mine: your other games, with your custom cards first. picks: the games you list in Picks. |
| Picks | Game slugs for picks, like my-friends-game. Ask the other dev for theirs. |
| Fill From Network | If your picks aren’t available, show a network game instead of hiding the card. |
| Header Text / Button Text | Anything you want. Empty uses the defaults. |
| Auto Load | Load a game when the card appears. Turn off for screens that open later and call refresh(). |
| Hide When Empty | Hide the card when there’s nothing to show, like when the player is offline. |
Ready-made scenes
All in addons/pixeldoor. Drag one into your scene and change its settings in the inspector. See where to put them for ideas.
| Scene | What it is |
|---|---|
promo_card.tscn | One game. Turn on Compact for pause menus (smaller art, no tagline). |
recommended_button.tscn | A “Recommended games” button. Opens a popup with 4 games (set Count). Esc or Close shuts it, and it works while your game is paused. |
promo_shelf.tscn | A heading and a row of 2 to 6 games. Call refresh() for new picks. |
thanks_screen.tscn | “Thanks for playing” with a row of games and a button back to your menu. Loads new games each time it’s shown. Connect finished to go back to your menu. |
demo_end_screen.tscn | “Thanks for playing the demo” with a wishlist button. Set Full Game App Id; it works even if the full game isn’t in the network. Add Full Game Slug too if it is, and the clicks show up in your dashboard. |
loading_screen.tscn | A loading screen with a card. It loads your next scene in the background and switches the moment it’s ready, whether or not the card has shown up. The card is loaded ahead of time so it appears instantly, and only counts as seen after a second on screen. |
world_poster_2d.tscn | A poster for a 2D world, like a board in town. The player walks up and presses E (the interact action, added for you if your project doesn’t have one), or clicks it. Put your player’s body in the player group. |
world_poster_3d.tscn | The same for a 3D world: a poster, a billboard, or the screen of an arcade cabinet (turn on Glow so it lights up). Counts as seen after a second on screen within 15 meters. Have your own interaction system? Call interact(). |
Each one has its own wording settings (title, message, button text) and the same card settings as above: Placement, Source and Picks.
# Show the loading screen, load the level in the background,
# and switch the moment it's loaded. The card never holds it up.
PixeldoorLoadingScreen.change_scene("res://levels/level_2.tscn")
# Your own loading code instead:
var screen := PixeldoorLoadingScreen.open()
screen.set_progress(0.5) # 0.0 to 1.0 as you go
screen.close() # the moment you're doneCustom cards
Make cards for your own news in your dashboard: a Kickstarter, your next game, a sale, your Discord or soundtrack. Run as many as you like, each on the screens you choose, and A/B test the wording. Any card with Source set to mine shows them first while they’re running, then your other games. Nothing to change in your game, and no patch when you change a card. Plugin 0.5.0 and later shows each card’s label and button text.
Script functions
The plugin adds a Pixeldoor autoload. The card uses these, and so can you:
| Call | What it does |
|---|---|
await fetch_feed(count, placement, source, picks, fallback) | Returns an array of games to show. Empty if offline or nothing matches. |
await load_image(url) | Downloads card art as a texture. Cached. |
prefetch(count, placement, ...) | Loads games and their art ahead of time, for a screen that opens later. |
take_prefetched(placement) | The games prefetch loaded, or an empty array. Each set is handed out once. |
report_impression(game) | Call once the card is visible. |
open_store(game) | Logs the click and opens the store page. |
send_context | Set to false from code, for example from your game’s privacy setting. |
request_failed(what, detail) | Signal for network problems, if you want to log them. |
# Build your own card with the plugin's functions
func _ready() -> void:
var games: Array = await Pixeldoor.fetch_feed(1, "pause", "mine")
if games.is_empty():
return # offline or nothing to show: just don't show a card
var g: Dictionary = games[0]
$Title.text = g.name
$Art.texture = await Pixeldoor.load_image(g.image_url)
Pixeldoor.report_impression(g) # once it's actually visible
$Button.pressed.connect(func(): Pixeldoor.open_store(g))Unity plugin
Unity 2021.3 or newer, any render pipeline. Download pixeldoor-unity-0.1.0.tgz, then Window, Package Manager, +, Add package from tarball. Text uses TextMeshPro when your project has it set up.
| Where | What |
|---|---|
| Project Settings, Pixeldoor | API key, Open Mode, Send Context. Also under Tools, Pixeldoor, Settings. |
| GameObject, Pixeldoor | Promo Card (and compact), Recommended Games Button, Shelf, Thanks for Playing Screen, Demo End Screen. Each one is plain uGUI with the same Inspector settings as the Godot card. |
| Tools, Pixeldoor, Create Demo Scene | Every ready-made piece wired up with test cards. Press Play. |
card.Refresh() | For screens that open later: turn off Auto Load and call it when the screen shows. |
using PixeldoorSdk;
// Loads the scene in the background and switches the moment it's ready.
PixeldoorLoadingScreen.ChangeScene("Level2");
// Or with your own loading code:
var screen = PixeldoorLoadingScreen.Open();
screen.SetProgress(0.5f); // 0 to 1 as you go
screen.Close(); // the moment you're doneBuild your own card with Pixeldoor.FetchFeed, LoadImage, ReportImpression and OpenStore. With Steamworks.NET or Facepunch.Steamworks in your game, clicks open the Steam overlay; with IL2CPP stripping on, add the link.xml from the package’s README.
using PixeldoorSdk;
var games = await Pixeldoor.FetchFeed(1, "pause", PromoSource.Mine);
if (games.Count == 0) return; // offline or nothing to show
myRawImage.texture = await Pixeldoor.LoadImage(games[0].image_url);
Pixeldoor.ReportImpression(games[0]); // once it's on screen
myButton.onClick.AddListener(() => Pixeldoor.OpenStore(games[0])); // also logs the clickHTTP API
Base URL https://pixeldoor.app. Send your key in the X-Promo-Key header.
GET /api/v1/feed
| Parameter | What it does |
|---|---|
count | 1 to 6 games. Default 1. |
placement | Screen name, like menu. |
source | network, mine or picks. |
picks | Comma-separated slugs for source=picks. |
fallback | 1 (default) fills from the network when picks are empty. 0 returns nothing. |
platform, lang | Optional context, like windows and en. Send ctx=0 to skip context and country. |
{
"serve_id": "9d75be5b-3fb5-488a-b093-dd570e4ba0fb",
"source": "network",
"games": [
{
"id": "a1b2…",
"slug": "their-game",
"name": "Their Game",
"tagline": "One short line.",
"steam_app_id": 1234560,
"image_url": "https://…/header.jpg",
"link_url": "https://store.steampowered.com/app/1234560/?utm_source=pixeldoor&…"
}
]
}source tells you what you actually got, which is network if a fallback happened. Custom cards come back first on source=mine with "kind": "custom" and optional label and button_text; report their impressions and clicks the same way. steam_app_id is 0 for games that aren’t on Steam.
POST /api/v1/events
Send impression once a card is on screen and click when it’s clicked. Batch up to 50 and send every few seconds, plus right away on a click. Duplicates are ignored.
{
"events": [
{ "serve_id": "9d75…", "game_id": "a1b2…", "kind": "impression" },
{ "serve_id": "9d75…", "game_id": "a1b2…", "kind": "click", "ms_since_shown": 4200 }
]
}Opening the store
| Engine | Call |
|---|---|
| Godot (GodotSteam) | Steam.activateGameOverlayToStore(app_id, 0) |
| Unity (Steamworks.NET) | SteamFriends.ActivateGameOverlayToStore(new AppId_t(id), EOverlayToStoreFlag.k_EOverlayToStoreFlag_None) |
| Unity (Facepunch) | SteamFriends.OpenStoreOverlay(id) |
| Unreal (C++) | SteamFriends()->ActivateGameOverlayToStore(id, k_EOverlayToStoreFlag_None) |
| GameMaker | steam_activate_overlay_store(id) |
No overlay? Open steam://openurl/ followed by link_url if Steam is installed, or link_url in the browser if it isn’t.