| name | create-an-edge-app |
| description | Use when scaffolding a new Screenly Edge App — covers the template, manifest, integrations/auth, tests, and the pre-PR checklist |
Creating an Edge App
When Creating an Edge App
Integrations and Authentication
When the app shows data from a third-party service, do not hand-roll an auth flow — that is where things go wrong. Screenly delivers credentials through one runtime call, and your job is only to feed that call locally.
To develop locally (real credentials aren't present), set up a super simple way to supply them — pick the lighter of these two:
- Read a secret (CLI is fine). Declare an
access_token secret marked "for testing only", set it with screenly edge-app setting set access_token=... (or in mock-data.yml), and read it with getSettingWithDefault('access_token', ''). See Screenly/google-calendar-app (src/main.ts).
- Handle the OAuth flow with a tiny companion app. A small Express + Bun server that runs the flow, stores the tokens, refreshes them, and exposes
GET /access_token/ returning { token, metadata } — mimicking the Screenly OAuth service. Wire it in via mock-data.yml's screenly_oauth_tokens_url. See the mock-authenticator/ in Screenly/salesforce-app for a complete, minimal example.
Both paths feed the same getCredentials() — the Edge App code does not change between them.
Error Reporting (Sentry)
New Edge Apps should support optional Sentry error reporting, gated behind a sentry_dsn setting that no-ops when unset.
- Add a
sentry_dsn setting to screenly.yml/screenly_qc.yml as a global secret that no-ops when unset:
settings:
sentry_dsn:
type: secret
title: Sentry DSN
optional: true
is_global: true
help_text:
schema_version: 1
properties:
advanced: true
help_text: Sentry DSN for reporting errors. Leave empty to disable.
type: string
- Call
setupSentry from @screenly/edge-apps/utils once, near the top of src/main.ts, before other startup logic, passing the app name and any settings or metadata useful as context:
setupSentry('app-name', { 'app-name': { screenName: screenly.metadata.screen_name } })
- Report failures with
reportError(error, { source: 'short-context' }) from @screenly/edge-apps/utils at meaningful failure points (credential refresh, content load, API errors) — not for expected or already-handled states.
- Dedupe repeated consecutive failures of the same kind (e.g. only report the first of a run of identical background-refresh errors) so retry loops don't spam Sentry.
- Requires
@screenly/edge-apps or later.
Testing
- Write tests before the feature, then make them pass. Every app ships an
e2e/ directory (Playwright); add cases there for the behavior you build.
- For integration apps, test against mock credentials (the secret or the companion authenticator above), not a live account.
Before Opening a PR
- Generate and commit screenshots:
bun run screenshots (builds the app and captures all Screenly resolutions). This is required — see edge-apps/CONTRIBUTING.md.
- Keep
screenly_qc.yml in sync with the app's settings and behavior.
- Confirm
bun run lint and the tests pass.
Reference Apps
Most Edge Apps have migrated to standalone repos under the Screenly org. For reference on more complex implementations, consult:
All apps depend on the @screenly/edge-apps NPM package and use edge-apps-scripts for tooling.
About the Manifest Files
About index.html
- Organize HTML code into templates and Web Components as the app grows in complexity.
- Use HTML content templates first for simpler structures.
- Consider using Web Components for more complex UI components that require encapsulation and reusability.
About README.md
- Include instructions on how to create, build, test, format, lint, and deploy the app.
- Do not add details like the directory structure, as the code frequently changes.