Build apps
Secrets
Keep your app’s own API keys out of its code.
On this page
A secret is a value your app needs that must not be in its code, such as the API key of a service
it reads. You declare its name in ledable.json, set its value once with the CLI, and read it
from ctx.secrets when the app draws. The value never enters the bundle you upload, and no
command shows it again.
A secret belongs to your app, so every display that runs the app uses the same value. Anything that belongs to one person, such as their own token for a service, is a setting instead: see Accounts and credentials.
Declare it
List the names in secrets. A name is upper-case letters,
digits and underscores, and does not start with a digit.
{
"app_id": "air-quality",
"version": "1.0.0",
"entry": "./index.tsx",
"name": "Air Quality",
"description": "The air quality where your display is.",
"category": "weather",
"secrets": ["AIR_API_KEY"],
"network": { "allowed_hosts": ["api.example.com"] }
}Only the names a version declares reach it. Declaring a secret also means the version cannot run without it: until the secret has a value, every render of that version fails.
Read it
ctx.secrets holds each declared name with its value. render reads it, and so do settings and
verifyCredential, which have their own ctx.secrets. preview has none, since a preview reads
nothing that can change.
const response = await fetch("https://api.example.com/v1/air?city=Berlin", {
headers: { Authorization: `Bearer ${ctx.secrets.AIR_API_KEY}` },
});If your app reports an error or throws one, the platform replaces the values of its secrets with
*** in the message before it leaves the app. Still, do not put a secret in a message, a cache
tag or anything you draw.
Set the value
Run the secret commands in the project's folder; they act on the app ledable.json names. At a
terminal, secret set asks for the value without showing
it. In a script, pipe the value in as one line of stdin instead:
ledable secret set AIR_API_KEY
printf '%s\n' "$AIR_API_KEY" | ledable secret set AIR_API_KEYThe CLI seals the value on your machine before it sends it, and the store keeps it sealed: only the servers that run your app open it. A value may not be empty and holds at most 4096 bytes.
To change a value, set it again. Renders pick up the new value within about a minute; there is no new version to upload, because the value belongs to the app, not to a version.
See what is set
secret list shows the secrets that have a value, the
published versions that declare each one, and under missing the names your ledable.json
declares that have no value yet. A name in missing fails your next upload.
{
"secrets": [
{
"name": "AIR_API_KEY",
"updated_at": 1791216000,
"declared_by": ["1.0.0"]
}
],
"missing": []
}Uploading a version that declares one
Set every declared secret before you run developer upload.
The store runs the version's settings, preview and a render before it publishes anything, and
a declared secret without a value makes that run fail, starting with the settings check. Set
the value and upload the same version number again. The checks are described in
Publishing checks.
Delete one
secret delete removes a secret that no published
version declares, such as one you set for a version you never shipped. A secret that a published
version declares cannot be deleted, because displays keep playing the versions they have and that
version would stop working. Replace its value instead.
ledable secret delete OLD_API_KEYIn the local preview
developer dev and
developer render never reach the store, so they
read secrets from ledable.dev.json next to ledable.json. Put your own key there, and keep the
file out of version control; developer init lists it
in the project's .gitignore.
{
"secrets": { "AIR_API_KEY": "your-own-key" }
}A declared secret the file does not have fails the render, as it would on LEDABLE's servers. The rest of the file is described in Local preview.