JavaScript injection

Attach a script to a web content item and the player runs it after the page loads: dismissing banners, hiding chrome, or completing a login form.

Attach JavaScript to a web content item and the player runs it against the page once the page has finished loading, every time that item plays.

It is the escape hatch for pages you do not control. A cookie banner covering the dashboard, a navigation bar wasting the top third of the screen, a login form that basic auth cannot satisfy: all of them are a few lines of DOM manipulation, and none of them are a Screenly setting.

Note

There is no dashboard control for this. It is set through the API, the CLI, or the MCP server, and nowhere else.

Setting it

The CLI takes a local file or a URL, which makes the script itself a reviewable file in your repository rather than a blob pasted into a form.

screenly asset inject-js <asset-uuid> ./dismiss-banner.js
screenly asset inject-js <asset-uuid> https://example.com/scripts/login.js

Over the API it is the js_injection field on the asset.

curl -X PATCH \
  'https://api.screenlyapp.com/api/v4.1/assets?id=eq.<asset-uuid>' \
  -H "Authorization: Token $SCREENLY_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"js_injection": "document.querySelector(\".cookie-banner\")?.remove();"}'

An assistant can set it too, through the MCP server’s asset update tool. See Tools.

When it runs

The script runs after the page reports itself fully loaded, so the DOM is in place and you do not need to wait for DOMContentLoaded yourself. It runs on every load, not once per item, so a script that logs in runs again each time the page comes round in the playlist.

It has no way to signal back. Whatever the script returns is logged on the device and discarded; the page plays regardless of whether your code threw.

Write once, read never

js_injection is write-only. Reading the asset back does not return your code, it returns a placeholder:

{ "js_injection": "<hidden; sha256 a1b2c3...>" }

An empty string means nothing is set. The placeholder is derived from the script, so it changes when the script changes, which is enough to detect drift in a pipeline. It is not enough to recover the script, so keep the source in version control. There is no way to read it back out of Screenly.

Limits

The field holds up to 65,536 characters. That is generous for DOM manipulation and small for a bundle: if you are approaching it, host the real script and inject a loader, or build an edge app instead.

Edge apps do not use this field. An app ships its own screenly_inject.js alongside its manifest, and the player runs that instead.

Worked examples

The Screenly Playground holds working injectors for common cases. Test a script in a normal browser console against the same page before you attach it, because debugging one on a wall is slow.

Type to search the documentation