Skip to content

Configuration

All settings are accessible from the plugin's QAM panel. Open the Quick Access Menu (... button), navigate to the Tender plugin, and pick Settings from the menu at the bottom of the panel.

The Settings page

Settings is a wide page split in two: a list of six sections on the left, and the focused section's controls on the right. Move onto a section in the list and the right-hand side changes at once — there is nothing to confirm.

Section What is in it
Connections the services Tender talks to: RomM (server URL, account, Sign out, Allow Insecure SSL) and SteamGridDB (the API key)
Save Sync the save-sync switch and its settings (device, before launch, after exit, default slot, history limit, Sync All Saves Now) and the list of registered devices
Controller Steam Input Mode, Apply to All Shortcuts, and the RetroArch input_driver fix
Steam Library preferred region, collection games in platform groups, collection types in Steam names
Updates the version you have and the release the last successful check found, the daily update check, and Check now
Advanced log level

If you used an earlier version, everything is still here — the eight blocks the panel used to stack are grouped into five of those six; Updates is new. Registered Devices is now inside Save Sync, the SteamGridDB key is inside Connections, and the section that used to be called Library is now Steam Library: the Library page is about what gets synced out of RomM, this section is about how it looks once it is in Steam.

Signing in to RetroAchievements is not here yet. When it arrives it will live under Connections, with the other accounts.

Getting there from a notice

Three of the notices on the plugin's main panel are doors into a section, and the action they are about lives only behind that door:

The notice says Its button Where it takes you
RetroArch: input_driver issue Open Controller Settings › Controller
Cross-device playtime Open Connections Settings › Connections
Tender X is available Open Updates Settings › Updates

The main panel only names the condition — it no longer carries a Fix button, so there is one place to do each of these and no chance of two of them disagreeing. B takes you back to the main panel from anywhere on the page.

Where the sections below say "in Connection Settings", read it as Settings › Connections.

Connection Settings

The Connections section manages your RomM server connection.

  • RomM URL — the full URL of your RomM server, including port if needed (e.g. http://192.168.1.100:8080). Tap Edit to change it; the URL saves automatically.
  • RomM Account — shows Signed in once a token is stored, or Not signed in otherwise. Tap Sign in to open a one-time prompt. The prompt offers three sign-in methods, chosen from the Sign-in method dropdown:

    • Username & password (default) — enter your RomM username and password once. The plugin exchanges them for a RomM Client API Token and stores only the token; your password is discarded after the token is minted and never saved. If your account cannot create API tokens, the status reports that.
    • API token — paste a Client API Token you created in RomM's web UI. This is one of the two paths for accounts that have no password to mint from, such as OIDC / SSO logins. See Sign in with an API token (OIDC) below.
    • Pairing code — the other, recommended OIDC path: instead of copying the token, enter the short-lived 8-character code RomM shows when you Pair a token. The plugin fetches the token itself, so nothing is copied or pasted. See Sign in with an API token (OIDC) below.

    Both the credentials and the pasted token are write-only — they are never pre-filled or shown back to you.

    Once you are signed in, this button reads Sign in again and a Sign out button appears below it (see Sign out).

  • Custom headers — extra HTTP headers sent with every request to your RomM server. Shows how many are configured, or (none). Only needed when your server sits behind a proxy that authenticates requests itself — see Custom headers for an authenticating proxy below.

  • Allow Insecure SSL — shown only for https:// URLs; skips certificate checks for a self-signed server. Anyone who can intercept the connection can then read what the plugin sends — your RomM token, your password when you sign in with it, and any custom headers — and use your account, so turn it on only on a network you trust. While it is on, every start of the backend writes a warning to its log saying certificate verification is off.

The plugin checks the connection for you — there is no manual "Test Connection" button. The Connection row on the plugin's main QAM panel shows the live status whenever you open it, and names the problem when it can't connect (for example Sign-in rejected, Server unreachable, or No server URL).

Custom headers for an authenticating proxy

If your RomM server sits behind a proxy that authenticates requests before they reach RomM — Pangolin, Cloudflare Access, Authelia, Authentik forward-auth — the proxy rejects the plugin's requests and you cannot connect at all. A browser gets past it because you logged in to the proxy there; the plugin has no such session.

The way through is a header the proxy accepts. Tap Edit on the Custom headers row, add a row per header, enter its name and value, and save. From then on every request the plugin sends to your RomM server carries them — including the sign-in itself, since the proxy sits in front of that too.

Where they go. The plugin puts them on the requests it sends to the RomM server you configured, and on no other request it sends — they are credentials for your front door. The plugin does reach other hosts: SteamGridDB for artwork, and a metadata provider's CDN for a cover image RomM has no local copy of. Neither carries them.

One case is outside the plugin's hands: if your server answers with a redirect to a different host, the HTTP library carries the headers along to it, the same way it already carries your RomM API token. That is worth knowing if your RomM URL is plain http://, where anyone on the network between you and the server could insert such a redirect. Over https:// to a server you control it is not a practical concern.

What they cannot be. These names are refused when you save, so nothing you enter can quietly replace a header the plugin or its HTTP library already sets: Authorization, User-Agent, Content-Type, Content-Length, Host, Accept-Encoding, Range, If-None-Match and If-Modified-Since.

Authorization is the one worth explaining. Proxy documentation often suggests it — Pangolin documents a Basic-auth Authorization header — but that is exactly the header your RomM API token travels in. One request cannot carry both, so the plugin refuses it rather than silently sending one and dropping the other. A proxy built for non-browser clients usually offers a header of its own as well; use that one.

Worked example — Pangolin. Issue a resource access token in Pangolin, then enter its two parts as rows:

Name Value
P-Access-Token the token Pangolin generated
P-Access-Token-Id the token's id

Save, then check the Connection row on the main QAM panel — it should stop reporting a rejection.

Values are write-only. A saved value is never sent back to the plugin's UI: reopening the editor shows each header's name with an empty value field marked •••• stored. Leave it empty to keep the stored value, or type to replace it. Removing a row and saving deletes that header. Values are never written to the plugin's log.

Sign out

The Sign out button (shown only while signed in) forgets the stored token on this device: it clears the token, its server-side id, its origin, and its provenance from the plugin's settings, but keeps the server URL and the SSL setting so you do not have to re-enter them. It asks for confirmation first.

Signing out never deletes or revokes the token in RomM — the token stays valid on the server. A token the plugin minted from your username and password can only be deleted during a same-server re-sign-in (the stored token deliberately lacks the permission to delete itself), and a token you supplied (pasted or paired) is yours to manage. To revoke a token for good, delete it in RomM's web UI under Settings → API Tokens.

If you just want to switch accounts or re-authenticate, prefer Sign in again over signing out and back in. For username/password accounts, re-signing in on the same server revokes the token the plugin minted before — a path that a sign-out then sign-in cannot take, since sign-out has already forgotten the old token's id. RomM caps the number of Client API Tokens per user, so avoiding stranded minted tokens matters.

Sign in with an API token (OIDC)

If you log in to RomM through an identity provider (OIDC / SSO), your RomM account has no password, so the plugin cannot mint a token for you. Instead you create a Client API Token yourself in RomM's web UI and hand it to the plugin. There are two ways to do that — pairing code (recommended) and pasting the token — and both grant the same scopes and carry the same warnings (see Required scopes below).

Start the same way for either method:

  1. In RomM's web UI, open Settings → API Tokens (also called Client API Tokens) and create a new token.
  2. Grant the scopes listed below — make sure the write scopes are included. Without them, downloads work but save upload, device sync, and playtime tracking fail with a permissions error.

Pairing hands the device the token over a short-lived one-time code, so you never copy or type the token itself.

  1. Create the token with the scopes above (steps 1–2).
  2. On that token in RomM's web UI, click Pair. RomM shows an 8-character pairing code, valid for 60 seconds.
  3. In the plugin's Connection Settings, tap Sign in, switch the Sign-in method dropdown to Pairing code, enter the code, and confirm — within the 60-second window. The plugin exchanges the code for the token itself.

Pairing rotates the token's secret. Exchanging a pairing code hands the device a freshly rotated secret for that token — any raw token value you copied earlier stops working. Use one token per device so pairing a new device never invalidates another.

Paste the token

  1. Create the token with the scopes above (steps 1–2).
  2. Copy the token value (RomM shows it only once).
  3. In the plugin's Connection Settings, tap Sign in, switch the Sign-in method dropdown to API token, paste the token, and confirm.

Both methods validate the token at sign-in with an authenticated probe against your RomM profile: a wrong, revoked, or expired credential is rejected there with an actionable message. Sign-in only confirms that the token authenticates, though — the plugin cannot verify the token's granted scopes, so double-check that you granted the write scopes (assets.write, devices.write, roms.user.write) when creating it. A missing write scope is not caught at sign-in; it surfaces later as a permissions error on the affected action (save upload, device sync, or playtime).

Required scopes

Scope Access What it is used for
me.read read Your RomM profile — validates the token at sign-in and reads your RetroAchievements username
platforms.read read Listing your platforms
roms.read read Listing and reading ROM metadata (the library)
roms.user.read read Your per-user ROM data — native play-session history
collections.read read Reading your collections (user, smart, virtual)
firmware.read read Listing and downloading BIOS / firmware
assets.read read Downloading save files
devices.read read Reading your registered devices (device sync)
assets.write write Uploading save files
devices.write write Registering this device and opening device-sync sessions
roms.user.write write Writing your per-user ROM data — playtime ingest

All eleven scopes are within RomM's Viewer role, so a token created by any account (including OIDC accounts) can carry them. me.write is deliberately not requested — a pasted token cannot mint or delete tokens.

The plugin never deletes a pasted token. Signing out of or back into the plugin, or switching servers, leaves your token untouched on the RomM server — you manage its lifecycle in RomM's web UI. (This differs from the username/password method, where the plugin revokes the token it minted when you re-sign-in on the same server.)

Note the reverse case too: if you previously signed in with your username and password and then switch to a pasted token on the same server, the token the plugin minted earlier is left behind on RomM — it can only revoke that during a same-server password re-sign-in (it has no password once you switch to a token). Revoke the old token manually in RomM's web UI if you no longer want it.

SteamGridDB API Key

Under Settings › Connections, below the RomM group — SteamGridDB is one of the two services Tender talks to.

The plugin uses SteamGridDB to fetch additional artwork for your games — hero banners, logos, and wide grid images. RomM provides cover art, but SteamGridDB fills in the rest so your games look like first-class Steam titles.

To set this up:

  1. Create a free account at steamgriddb.com
  2. Go to your API preferences and copy your API key
  3. In Settings › Connections, tap Edit next to API Key under "SteamGridDB" and paste your key
  4. Tap Save — the key is checked against SteamGridDB first, so an invalid key is rejected inline and only a working key is stored

Without an API key, games will still have cover art from RomM but the hero banner, logo overlay, and wide grid image will be missing.

Steam Input Mode

Controls how Steam handles controller input for ROM shortcuts. Found in Settings › Controller.

Mode Description
Default (Recommended) Uses your global Steam Input settings. Works well with RetroDECK's default configuration.
Force On Explicitly enables Steam Input wrapping. Normalizes the controller as standard XInput, which RetroArch autoconfig expects.
Force Off Raw HID passthrough. Only for advanced users — may break RetroArch menu navigation.

After changing the mode, tap Apply to All Shortcuts to update all existing ROM shortcuts. The button reads Applying to all shortcuts… and stops responding while the run is going — a second tap is refused rather than starting a second pass over the same shortcuts.

Preferred region

A dropdown in Settings › Steam Library. When a game exists in your RomM library as several regional dumps (versions), this decides which region the plugin prefers when it picks the version to bind and the name it gives the Steam shortcut.

Option Effect
Default (World > USA > Europe) Prefer World, then USA, then Europe, then Japan, then any other region alphabetically (fixed order)
a specific region (World, USA, Japan, …) Put that region at the top of the order; everything else keeps the default order behind it

"Default" is a fixed order, not auto-detection. It always prefers World > USA > Europe > Japan (then other regions alphabetically, then dumps with no region); the plugin never looks at your language or system region.

The dropdown's options are the fixed anchors — Default, World, USA, Europe, Japan — followed by every other region actually present in the games you have already synced (read from the local database, sorted alphabetically; no server request). If your synced library has no other regions, only the anchors are shown.

When you change it, a short modal explains the effect and asks you to confirm. The choice is saved immediately, but it takes effect on the next sync and only affects games synced from then on. It never switches the version or renames an existing shortcut — shortcut names are fixed when the shortcut is first created, to protect its artwork, collections and playtime. Already-synced games keep their bound version and name; run a sync to apply the new preference to new games. See Multiple versions of a game for the full picture.

Log Level

A dropdown in Settings › Advanced. Controls how much detail the plugin logs.

Level Description
Error Only errors — minimal output
Warn (default) Errors and warnings
Info General operational messages
Debug Verbose output for troubleshooting

Leave this at Warn unless you're investigating an issue. Switch to Debug when reporting bugs or diagnosing problems.

Updates

Each time Steam loads Tender, it asks GitHub whether a newer release is out — at most once a day. When there is one, a notice on the main panel says Tender X is available and names the version you have; Open Updates takes you to Settings › Updates, and Dismiss puts the notice away for that version only — the next release brings it back.

Settings › Updates shows:

  • Installed — the version you are running.
  • Available — the release the last successful check found, None newer when you already have it, Not known yet before a check has found anything, or Not checked — the daily check is off while the check is switched off.
  • Check for updates daily — on by default. Switch it off and Tender asks GitHub nothing at all, not even when you press Check now.
  • Check now — asks straight away rather than waiting for the day to pass, and brings back a notice you dismissed. The line under the button says what it found: a newer release, that you have the newest one, or that GitHub gave no usable answer.

A release counts as out only once its download is attached together with GitHub's checksum for it, which happens a few minutes after the release is published; until then Tender says nothing about it. A release whose download comes without a valid checksum does not count as out while it has none, because it could not be verified.

What the check sends where. When Steam loads Tender and a day has passed since the last check, and whenever you press Check now, Tender asks GitHub's public API for the newest release of danielcopper/romm-tender. The request names the program and its version (for example romm-tender/1.0.0), and GitHub sees your IP address, as it does for any request. Nothing about your library, your RomM server or your accounts is sent. If the check gets no usable answer — you are offline, GitHub is down, or it refuses the request — nothing changes: whatever the last successful check found stays as it was, and Tender tries again the next time it loads, once a day has passed.

Settings › Updates tells you a newer release is out; it does not install it.

RetroArch Input Driver Fix

If the plugin detects that RetroArch is using the x input driver (which causes controller issues in menus on Wayland systems), a notice appears on the main panel with an Open Controller button. The fix itself is in Settings › Controller: Fix input_driver to sdl2 modifies your RetroArch config to use sdl2 instead, which fixes controller navigation in RetroArch menus. The result is reported under the button, and the warning goes away once the config has been changed.

The button asks before it acts — it opens a confirmation naming the change, and only Apply Fix writes anything; Cancel leaves your config exactly as it was. The confirmation is there because the change is written straight into your config and the plugin keeps no copy of the file it replaces, so if you have hand-edited your retroarch.cfg and want a copy, take one before confirming.


Previous: Getting Started | Next: Syncing Your Library