Appearance
Secrets ProPart of the Pro plan and up
A scene's scripts can call an API that needs a key – an AI model, a weather service, your own backend – without the key being part of the experience. You store the key once on your account, give it a name, and a script asks for it by name. Scenery makes the request from its own servers and adds the key on the way out.
That matters because a script is readable by anyone who can open the experience. A key written into a script is a key you have given away. A key stored as a secret never reaches a viewer's device at all.
You pay the API, not Scenery
The key is yours, so every charge the API makes lands on your account with that vendor. Scenery carries the request; it does not pay for it. Set a spend cap with the vendor as well as a daily limit here.
Where it lives
Library → Secrets, in two tabs.
My Secrets is your account's keys, grouped by the service each one is for. These belong to you and follow you between experiences.
In Use is every name this experience's scripts call, and which key is behind each one. This is where a copied experience shows that it needs a key, and where a teammate's key shows up as theirs.
Adding a key
Under My Secrets, choose Add Secret and give it:
- Name – what a script will call it. Pick something a script can read, like
openaiorweather. - Value – the key itself. It is stored encrypted and cannot be read back afterwards, so keep your own copy.
- Daily limit – how many calls a day this key may make. The default is 1000.
Once added, Test makes one real call so you can see the key works before you build around it. A test spends one call against the daily limit.
Using it in an experience
Adding a key to your account does not let an experience spend it. That is a separate step, so a key cannot be used by an experience you did not mean to use it in.
Select the key under My Secrets and turn on Use in This Experience. It then appears under In Use, and scripts in this experience can call it:
js
var response = await http.request('https://api.openai.com/v1/models', {
secret: 'openai'
});The name in secret is the binding's name under In Use, not the key's value and not the service's name. Rename the binding and the script has to say the new name.
One key can be used in up to 100 experiences.
Replacing a key
Select it under My Secrets and choose Replace Value. The key's identity does not change, so every experience and every script using it keeps working. Nothing needs editing anywhere.
This is the reason to reach for secrets even on an experience only you will ever open: rotating a key is one field, not a search through your scripts.
The daily limit
The limit counts calls, not money, and it is shared by everyone who opens an experience that uses the key. A thousand visitors asking one question each is a thousand calls against the same number.
When a key has spent its limit, further calls are refused until it resets. A script can tell that apart from other failures and say something useful rather than going quiet:
js
try {
var response = await http.request(url, { secret: 'openai' });
} catch (error) {
if (error.reason === 'ceiling_reached') {
// error.details.limit and error.details.resetAt say what and when
}
}Three refusals are worth handling separately. ceiling_reached means the limit is spent and details.resetAt says when it returns. owner_busy is momentary and worth retrying shortly. owner_not_entitled means the plan of the account the key belongs to no longer covers secrets, so no viewer can spend it until that account subscribes again.
Note that the API's own refusal is not an error here. A vendor answering 429 or 400 arrives as an ordinary response carrying that status, so a script that only wraps the call in try will miss it. Check response.status.
Working as a team
A key belongs to one account, never to a team or an experience. What is shared is permission to spend it.
So when you use your key in an experience and a teammate opens that experience, their calls go out on your key and against your daily limit. They cannot see it, copy it, or change it. Under In Use it is marked as yours, its name is fixed, and the key itself is not shown.
A teammate can also bring their own key for an experience they author. Both can be true in one experience: some names on your key, some on theirs.
If a teammate wants an experience to use their own key instead of yours, they can Replace Key – Scenery asks first and says whose key it is replacing, because the experience stops working for everyone if the new key is for a different API. Remove Key likewise asks, because only you can put yours back.
Copies and templates
A copy of someone else's experience, or one started from a template, keeps the names its scripts call and drops the keys behind them. Nobody inherits a key by duplicating.
Such a binding reads as needing your own key: the name is there, the key is not, and you pick one of yours to fill it. Until you do, scripts calling that name are refused with a reason that says the key is not set rather than one that looks like a typo.
Duplicating your own experience keeps its keys, since they were already yours to spend.
What secrets cannot do yet
Request and response only
A secret works for an ordinary request and its reply, with the key in a header. Three things are outside that:
- Responses are capped at 5 MB. A larger reply is refused with the reason
response_too_large. For speech that is roughly 80 seconds of audio at the usual quality, which is ample for a spoken line and not enough for a long passage. - No streaming and no sockets. The request completes and returns; there is nothing to subscribe to.
- Realtime sessions are not available.
secrets.mint, which would hand a short-lived credential to the device for a realtime voice session, refuses withmint_not_supported.
Any API that takes its key in a header and answers in one reply works, whichever service it is.
See also
- Fetch data from an API – worked examples, including when a call fails
- HTTPClient – the
secretoption in full