Build and deploy
The development loop: validate, run against mock data, deploy. Then instances, settings, and versions.
An edge app is a web application plus a screenly.yml manifest. Everything below is done with the CLI.
The loop
screenly edge-app validate
screenly edge-app run --generate-mock-data
screenly edge-app deploy
Validate checks the manifest before anything reaches a screen. Run it first, and run it in CI.
Run starts the app locally against generated mock data, so you can develop without a device and without touching your workspace.
Deploy ships it. Every screen running the app picks up the new version on its next sync.
Creating and naming
edge-app create makes the app, rename changes its name, and delete removes it.
To start the project itself from a template, with a build set up, see The Edge Apps library.
Which app a deploy goes to
Every edge app in your workspace has an ID. The CLI reads it from the EDGE_APP_ID environment variable first:
export EDGE_APP_ID=your-edge-app-id
screenly edge-app deploy
Whatever runs the deploy decides where it lands: your own shell, or a secret in CI. The manifest stays the same for everyone who clones the repository, so 2 people with 2 accounts don't deploy over each other's app.
The id field in screenly.yml still works when EDGE_APP_ID isn't set. It is deprecated, and the CLI prints a warning each time it falls back to it.
create respects the variable too, including create --in-place. With EDGE_APP_ID set, create checks that the app exists and targets it instead of making a new one, and writes nothing into screenly.yml. A new name then gives you a new revision of the existing app, not a new app. Unset the variable when you want a new one.
Settings
edge-app setting list and edge-app setting set work with the fields your manifest declares.
Settings appear in the dashboard in the order your screenly.yml declares them. deploy works out each setting's position from the manifest and sends it along, without rewriting the file. Put the field somebody must fill in first.
Settings can also be conditionally visible, using depends_on, so an option only appears once a prior choice makes it relevant. That is worth using: a form with 8 fields where 3 are irrelevant is a form people get wrong.
Both go in the setting's help_text, as a schema instead of a plain string:
settings:
widget_type:
type: string
title: Widget type
optional: false
help_text:
schema_version: 1
properties:
help_text: What the widget shows.
type: select
options:
- label: Chart
value: chart
- label: Ticker
value: ticker
- label: News
value: news
symbol:
type: string
title: Symbol
optional: false
help_text:
schema_version: 1
properties:
help_text: Which symbol the widget follows, for example NASDAQ:AAPL.
display_order: 20
depends_on:
setting: widget_type
values: [chart, ticker]
depends_on names another setting and the values that make this one apply. Above, symbol appears only while widget_type is chart or ticker. A hidden setting is not validated and its value is not saved, so a required setting that doesn't apply to the chosen mode can't block an install.
display_order overrides the position a setting would get from the manifest. Settings sort ascending, within the basic and advanced groups separately. A setting without one sorts after every setting that has one. A secret gets an automatic position only if its help_text is a schema like the one above.
The help_text inside properties is the text shown under the field.
Both keys fail open. A help_text without schema_version is shown as plain help text, and a malformed depends_on shows the setting rather than hiding it, so a mistake in the schema can't make a setting unreachable.
Instances
edge-app instance list, create, update, delete.
An instance is the app plus one configuration, and it is the instance that goes in a playlist. One app can have many. See Instances.
Skipping a turn when there is nothing to show
A flight tracker with no planes overhead, or a meeting room app between bookings, has nothing worth showing some of the time. Call screenly.signalAbort() while the app is loading, and the player skips it and starts the next item in the playlist.
The app gets its turn again the next time the playlist comes round, and can decide again then. A call after the app is on screen is ignored, and the app plays for its full duration. A skip isn't counted as a failed play. This needs ScreenlyOS 26.9.0 or newer.
Deploying from GitHub
The Edge Apps GitHub Actions run checks, create the app in each environment, and deploy on every push. See Deploy with GitHub Actions.
Where it runs
On a Screenly player or Player Max, the app runs on the device. On some Screenly Anywhere platforms it is rendered on our infrastructure and sent as an image instead.
[!IMPORTANT] An app that depends on running locally, animating or reacting between refreshes, will not behave the same on Screenly Anywhere. Test on the hardware you are targeting. The local emulator or a player is the right place to develop a dynamic app.
See Where an app runs.
The full reference
The manifest schema, the JavaScript API available to your app, the branding values, and the deploy model are at developer.screenly.io.