Skip to main content
7 min read

Inputs & configuration

Inputs are the settings a person fills in when they add your app in the Glance app: a zip code, a color, a team. Each input you declare in the manifest becomes a control the user sees on the app's setup screen, and its value shows up in your code through ctx.inputs.

What the user actually sees

When someone adds your app in the Glance app, each input you declare becomes a control they fill in. For example, the Traffic Tracker's two free-text inputs (a start and an end zip code) look like this in the app:

Traffic Tracker setup screen in the Glance app: two zip-code text boxes and a Save button
Two free-text inputs become the two text boxes here. This is what your users see when they add your app.

The manifest that produces those two boxes:

inputs:
- key: depart_zip # your code reads ctx.inputs["depart_zip"]
app_input_type: free-text # a plain text box
type: string
label: Depart Zip Code # the label the user sees
default: "34102"
help: Where your drive starts.
- key: arrive_zip
app_input_type: free-text
type: string
label: Arrive Zip Code
default: "33901"
help: Where your drive ends.

Anatomy of one input

- key: zip # the name your code reads: ctx.inputs["zip"]
app_input_type: free-text # the control the user sees (see below)
type: string # the data type
label: Zip code # the label next to the box
default: "90210" # pre-filled value
help: A US zip code. # hint shown under the box

Read it in app.star

Use .get(key, fallback). It returns the fallback if the value is missing, so your app never renders a blank panel:

def main(c, ctx):
depart = ctx.inputs.get("depart_zip", "34102")
c.text(depart, 4, 12, font="5x7", color="green")

Two habits worth building:

  • Always pass a fallback. ctx.inputs["zip"] works too, but .get() with a default means a blank or missing value degrades gracefully instead of erroring.
  • Uppercase text before drawing. The bitmap fonts have no lowercase letters, so use c.text(city.upper(), ...). Otherwise a user who types "boston" sees nothing.

Pick the right control

app_input_type decides the widget. There are eight: a text box, a dropdown, a multi-select, a checkbox, two date pickers, a color wheel, and a dedicated API-key field.

A dropdown needs a choices list:

- key: units
app_input_type: dropdown
type: choice
label: Units
default: metric
choices: [metric, imperial]

API keys

Some apps pull from a data provider that needs a key (a traffic or weather service, for example). An API key is not a free-text input: it has its own setting, app_input_type: api-key. That setting is what tells Glance to encrypt the key — a key collected through a free-text input is not encrypted and may not work at all:

- key: apikey # no underscores or hyphens in an api-key key name
app_input_type: api-key # required for keys — this is what encrypts the value
type: string
label: API key
help: Paste the key from your provider account.

Name the key without underscores or hyphensapikey, not api_key or api-key. Those two characters are the delimiters of the descriptor GDN wraps around an api-key value on its way into http, so they can't appear in the key name itself. A guard enforces this: validation rejects an api-key input whose key contains _ or - before the app can ever ship.

The name is not what protects the key, though — only app_input_type: api-key does. GDN has checks in place to work out whether a value handed to http came from an api-key input or a free-text one, but it is your responsibility to select api-key when you add the input.

Your code reads it like any other input and passes it to http.get as a header or query parameter, whichever your provider expects:

def main(c, ctx):
key = ctx.inputs.get("apikey", "")
resp = http.get("https://api.example.com/v1/data",
headers = {"x-api-key": key})
Where API keys live

A key a user enters into an api-key input is encrypted on entry and stays encrypted in transit and at rest: the encrypted key is sent to the GLANCE, and it is decrypted only on Glance's servers, at render time, when the GDN host makes the network request on your app's behalf. It is never written into your app code. None of this protection applies to a key entered through a free-text input.

See the Bitcoin price example for a full app that uses an API key and parses a live JSON response.

Adding a setting to an app you already made

You picked your starting settings when you created the app, but you're not stuck with them. In Glance Dev Studio, the Your app's settings card has a + Add setting button: give the setting a name, a label, and a type, and Studio writes the YAML into manifest.yaml, saves, and the new control appears in the panel below — no hand-editing.

Two things the button enforces:

  • Names are letters and digits, starting with a letter. tzoffset, not tz_offset. Underscores and hyphens are the delimiters GDN uses internally, so the button won't accept them.
  • Names must be new. If a setting with that name is already in your manifest, the button refuses it rather than quietly overwriting what's there. That's usually a sign you want the next section.

You can always edit manifest.yaml directly instead — it's one of the two tabs in Studio, right next to your code, with the live preview beside it. Changing an existing setting's label, default, or choices is a manifest edit; there's no dialog for it.

Re-using a setting you took out of your code

A common tangle: the setting is still declared in manifest.yaml, you deleted the line that read it from app.star, and now you want it back. + Add setting won't help — it'll tell you the setting already exists, because it does.

Nothing is broken, and nothing needs re-declaring. A setting is connected to your app by one thing only: your code reading its key. Put that line back and the setting is live again:

def main(c, ctx):
team = ctx.inputs.get("team", "LAL") # this line is the whole connection
c.text(team.upper(), 4, 12, font="5x7", color="amber")

You don't have to type it from memory:

  • Studio writes it for you. A setting your code doesn't read is marked not used in code in the settings panel, with a Use it in my code button that inserts the ctx.inputs.get(...) line at the top of your first page function. See See it live.
  • Autocomplete. Type ctx.inputs.get(" in the editor and Studio offers every setting your manifest declares. (Tick Autocomplete in the toolbar if it's off.)
A setting your code never reads fails validation

If you meant to drop the setting rather than re-use it, delete it from manifest.yaml too. Leaving it declared but unread is an error, not a warning:

setting `team` is declared but never used in app.star
(read it with ctx.inputs.get("team"), or remove it from the manifest)

Validate fails on it and so does the publish check, because a setting a user fills in that changes nothing on the panel looks like a broken app.

Next