How LibreSignage works
LibreSignage separates preparation from delivery. You add reusable
items to the content library, arrange them in playlists, optionally
control when they play with schedules or where they appear with
layouts, and then assign the result to managed screens.
{% for title, description in [
("Content", "The individual images, videos, PDFs, messages, web pages, feeds, clocks, and QR codes."),
("Playlist", "An ordered sequence of content with timing, transitions, and looping settings."),
("Schedule", "A rule that activates a playlist by date, weekday, local time, and priority."),
("Layout", "A fixed multi-zone design in which each zone plays its own playlist."),
("Screen", "A registered display with a stable player URL, profile, assignment, and published revision."),
("Publish", "The action that delivers all staged screen changes to the players.")
] %}
{{ title }}
{{ description }}
{% endfor %}
Draft versus published: assignment changes are staged
first. Screens keep showing their last published revision until an
administrator selects Publish.
Install the LibreSignage server
The server hosts the CMS, media library, and public player URLs. Use
the local setup for development or a trusted private network. Use the
remote setup when screens connect over the internet.
Server requirements: Python 3.10 or newer, Node.js
20 or newer, uv, and FFmpeg when video uploads are
enabled. The host also needs enough persistent storage for the SQLite
database and uploaded media.
Local server
This path runs directly from a source checkout and is suitable for
evaluating LibreSignage on one computer or a trusted LAN.
-
Get the source and install locked dependencies.
git clone <repository-url> libresignage
cd libresignage
uv sync --locked --group dev
npm ci
npm run build
-
Create the local configuration.
cp .env.example .env
python -c "import secrets; print(secrets.token_hex(32))"
Put the generated value in LIBRESIGNAGE_SECRET_KEY
and review the database, upload folder, timezone, and FFmpeg
settings in .env. Do not commit that file.
-
Start the development server.
uv run flask --app libresignage run --debug
Open http://127.0.0.1:5000/auth/setup and create the
first administrator. To test from another device on the same
trusted network, bind to the LAN interface:
uv run flask --app libresignage run --host 0.0.0.0 --port 5000
Flask's development server is not a production internet server. Do
not expose port 5000 directly to the public internet.
Offline caching requires HTTPS
A player can stream content while connected to a plain HTTP LAN
address such as http://192.168.1.50:5000, but browsers
generally block the service worker needed for offline caching on
that insecure origin.
Serve LAN deployments over HTTPS and make sure every client trusts
the certificate. Plain HTTP is eligible only for the browser's
localhost/127.0.0.1 development exception,
when the server and player run on the same computer.
Remote production server
A remote deployment uses the same application behind a production
WSGI server and an HTTPS reverse proxy. The following example assumes
a Linux host and a checkout at /opt/libresignage.
-
Install and build the application.
cd /opt
git clone <repository-url> libresignage
cd /opt/libresignage
uv sync --locked
npm ci
npm run build
-
Configure production paths and secrets.
Copy .env.example to .env, restrict it
to the service account, and set at least these values:
LIBRESIGNAGE_CONFIG=production
LIBRESIGNAGE_SECRET_KEY=<generated-random-secret>
LIBRESIGNAGE_DATABASE=/var/lib/libresignage/libresignage.sqlite
LIBRESIGNAGE_UPLOAD_FOLDER=/var/lib/libresignage/uploads
LIBRESIGNAGE_TIMEZONE=America/Chicago
LIBRESIGNAGE_TRUSTED_PROXY_COUNT=1
Create the data directories with write access for the dedicated
service account. Back up both the database and uploads together.
Set the trusted proxy count only to the exact number of proxies
controlled by your deployment; it lets login throttling use the
original client address safely.
-
Run a production WSGI server.
uv run --with gunicorn gunicorn \
--workers 2 \
--bind 127.0.0.1:8000 \
'libresignage:create_app()'
Manage this command with the host's service manager so it starts
after reboot and restarts after failure. Keep its working
directory set to /opt/libresignage so the
project-level .env is loaded.
-
Put HTTPS in front of the service.
Configure Nginx, Caddy, or an equivalent reverse proxy to
terminate TLS and forward requests to
http://127.0.0.1:8000. Preserve the original
Host and forwarding headers, allow uploads up to the
configured LIBRESIGNAGE_MAX_CONTENT_LENGTH, and use
a publicly trusted certificate for internet-connected clients.
-
Finish setup and verify access.
Open https://signage.example.com/auth/setup, create
the first administrator, sign in, and register a test screen.
From the display network, confirm that the server URL and the
screen's public status URL are reachable without a VPN login or
proxy authentication prompt.
Before going live: allow only HTTPS through the
firewall, persist and back up application data, enable automatic
service startup, verify FFmpeg, and test a complete upload, publish,
playback, and offline-cache cycle.
Install the LibreSignage screen client
Install one client on each display computer. A client needs the base
URL of a reachable LibreSignage server and the stable slug of a
screen registered in the CMS. The server can be local, elsewhere on
the LAN, or remotely hosted over HTTPS.
Install from source
-
Install the client environment.
cd libresignage/client
uv sync --locked
On Debian or Ubuntu, the bundled Qt renderer also needs the
standard X11/XCB desktop libraries:
sudo apt install libxcb-cursor0 libxcb-icccm4 libxcb-image0 \
libxcb-keysyms1 libxcb-render-util0 libxcb-xkb1 libxkbcommon-x11-0
Windows uses WebView2 and macOS uses the system WKWebView. Install
the client on the same operating system on which it will run.
-
Register this physical display.
Sign in to LibreSignage, open Screens, add the
display, and copy its complete authenticated setup command. The
command contains both the screen slug and its private token.
Assign content and publish it before provisioning the client.
-
Configure the server connection.
For an HTTPS server on the same trusted LAN:
uv run libresignage-client configure \
--server-url https://signage.lan \
--screen-slug lobby-display-a1b2c3d4 \
--screen-token YOUR_SCREEN_TOKEN
LAN security notice: the client must trust this
HTTPS certificate for offline caching to work. A plain HTTP LAN
IP may play while connected, but it is not a secure origin and
cannot be relied on to register the offline service worker.
For a remotely hosted server:
uv run libresignage-client configure \
--server-url https://signage.example.com \
--screen-slug lobby-display-a1b2c3d4 \
--screen-token YOUR_SCREEN_TOKEN
Supply only the server's base URL—not the complete player URL.
Reverse-proxy subpaths such as
https://example.com/signage are supported.
Security upgrade: clients configured before
screen authentication do not have a token and will report
offline after upgrading. Reconfigure every existing client with
the command now shown in CMS → Screens. Treat
the token like a password; rotating it immediately invalidates
the old client configuration.
-
Verify and start the player.
uv run libresignage-client show
uv run libresignage-client diagnose
uv run libresignage-client run
The diagnostic command must report the screen's published
revision before kiosk deployment. Use
configure --windowed --not-on-top while testing if
you do not want a fullscreen always-on-top window.
Build a standalone client
Build on each target operating system; PyInstaller does not
cross-compile the client for another platform.
cd libresignage/client
uv sync --locked --group dev
uv run pyinstaller libresignage-client.spec --clean --noconfirm
The build writes the graphical libresignage-client and
terminal libresignage-client-cli executables below
client/dist/libresignage-client/. Double-clicking an
unconfigured graphical client opens its first-run connection screen.
Prepare for unattended playback
- Configure the operating system to sign in to a restricted signage account and launch the client after login.
- Keep the client's persistent browser profile; private sessions cannot retain offline media.
- Open the player while online and wait for Offline playlist ready.
- Disconnect the network, restart the client, and reboot the device to verify cached playback.
- On Linux Qt clients, use the server-normalized WebM/VP9 video output rather than assuming H.264 support.
Never reuse one screen slug on several physical displays. Each client
needs its own registered screen so revisions, health reports, and
remote commands are attributed correctly.
Quick start: put content on one screen
{% for number, title, description, endpoint, link_text in [
(1, "Add content", "Upload a file or create a text, clock, QR, feed, or web item. Give it a clear title and duration.", "content.index", "Open Content"),
(2, "Build a playlist", "Create a playlist, open it, add library items, and arrange their playback order.", "content.playlists", "Open Playlists"),
(3, "Register a screen", "Add the display, record its location, and set its resolution and media-scaling preference.", "dashboard.screen_inventory", "Open Screens"),
(4, "Stage the assignment", "Choose Direct playlist as the screen playback source and select the playlist.", "dashboard.screen_inventory", "Assign content"),
(5, "Preview and publish", "Preview the draft, correct anything unexpected, then publish the staged changes.", "dashboard.index", "Open Dashboard"),
(6, "Open the player", "Open the screen player URL on the display and wait until the offline playlist reports ready.", "dashboard.screen_inventory", "Find player URL")
] %}
{{ number }}
{% endfor %}
Manage the content library
Go to Content to add and
organize everything that can appear on a display.
Supported content
| Type | What to provide | Important behavior |
| Image | An image file | Uses the screen's fit, crop, or stretch setting. |
| Video | A video file | Processes in the background and is skipped until ready. |
| PDF | A PDF file | Displayed for the item's configured duration. |
| Text | A message | Rendered locally and available offline. |
| Clock | An IANA timezone, such as America/Chicago | Continues updating offline. |
| QR code | A website or contact details | Generated locally; contact codes can include a structured address. |
| Web page | An HTTPS URL | The site must allow iframe embedding and requires connectivity. |
| Feed | An RSS or Atom URL | Refreshes periodically and keeps the last successful result. |
Organize and maintain assets
- Set the default duration; a playlist entry can override it.
- Use one folder and up to ten comma-separated tags for filtering.
- Set an expiry date for temporary campaigns. Expired items remain visible but are skipped during playback.
- Search by title, text, URL, folder, or tag, and use the folder filter for a narrower view.
- Use Edit / replace to update an asset without losing its playlist positions.
- Check the usage badge before deleting. An in-use item requires explicit confirmation and is removed from its playlists.
Video uploads show Video processing… while the server
prepares them. Do not expect a new video to appear in players until
its status is ready. A conversion failure is shown in the library.
Create designs from templates
Templates provide
accessible announcement, promotion, and information-notice designs
without requiring design software.
Restaurant and food-truck presets include a six-item menu board,
daily special, combo deal, and current-stop announcement. Menu rows
keep item names, descriptions, and prices aligned; special and combo
layouts give the price a prominent treatment.
- Choose the template that best matches the message.
- Enter its labeled text, duration, brand color, and text color.
- If you upload an image, provide alternative text that describes it.
- For menu boards, enter a name and price for every row you use; descriptions are optional.
- Review the live preview, then create the item.
Reuse your brand
Administrators can open Brand kits
to save a logo, accessible primary/secondary/text colors, and locally hosted
WOFF2 heading and body fonts. Editors can apply a kit and adjust colors for a
specific design. Existing designs retain the brand snapshot they were saved with.
Bind menu rows
Menu boards can read up to six rows from CSV, JSON, or a publicly published
Google Sheets CSV URL. Map columns to name, description, and price; every used
row needs a name and price. Remote sheets refresh every five minutes and keep
showing the last successful rows if the source is temporarily unavailable.
Repeat and recover changes
- Use Duplicate as next week's special to review a prefilled copy dated for the following Monday before creating it.
- Every template save records the operator, time, metadata, design values, assets, and data binding.
- Open Version history to inspect or restore a prior snapshot; restoration itself creates a new version.
LibreSignage checks text contrast for accessibility. The finished
design becomes a normal content item and can be reused anywhere.
Build and arrange playlists
Go to Playlists,
create a named playlist, and open it to add items from the library.
- Place entries in the exact order they should play.
- Keep an entry's default duration or set an override for this playlist only.
-
Choose none, fade, slide left, slide up, or soft zoom. Each option is
brief and restrained for signage; players also honor the device's
reduced-motion preference.
- Enable looping for continuous signage, or disable it for one-time playback.
- Use the playlist player to review the complete sequence.
A player automatically moves past media that fails. Expired and
not-yet-ready items are excluded from the playable sequence.
Control playback with schedules
Use Schedules when
screens should switch playlists automatically.
- Choose a playlist and give the schedule a descriptive name.
- Target all scheduled screens or one screen group.
- Select its IANA timezone. All date and time rules use that local timezone.
- Optionally limit the rule to a start date, end date, and selected weekdays.
- Choose all-day playback or enter a start and end time. Overnight ranges are supported.
- Set its priority and leave it enabled.
When several rules match, the enabled schedule with the highest
priority wins. If priorities are equal, the newest matching rule
wins. Assign the screen to Scheduled channel for
these rules to take effect.
Holidays and one-off exceptions
Open Date rules
to create an inclusive, whole-date exception in a specific timezone.
A blackout plays nothing for closed days. A
playlist override temporarily replaces normal
schedules, such as a holiday menu from December 24 through 26.
- Target every scheduled screen or a single screen group.
- When date rules overlap, highest priority wins; newest wins a tie.
- The winning date rule takes precedence over every recurring schedule.
- Groups in use cannot be deleted until their rules are retargeted or removed.
Calendar view
Use the schedule calendar
to switch between month and week views. Filter by timezone and target.
Blue entries are schedules, yellow entries are overrides, and dark
entries are blackouts.
Use multi-zone layouts
Layouts divide a
display into independently playing zones. Available presets include a
70/30 split, main content with a ticker, and a 70/30 split with a
ticker.
- Create a layout and choose a preset.
- Open the layout and assign one playlist to each zone.
- Preview the layout and confirm that each zone has useful content.
- Stage the layout as a screen's playback source, then publish.
Each zone advances independently. On portrait displays, split zones
stack vertically. All local media used by the layout is included in
the screen's offline cache.
Register and organize screens
Use Screens
to manage each physical display.
Screen profile
- Use a recognizable name, physical location, and operator notes.
- Select a common resolution or enter custom dimensions.
- Fit with letterboxing shows the whole image; Fill and crop fills the screen; Stretch changes the media proportions to match.
- Add screens to reusable groups such as “Front of house” or “North campus.”
Assign playback
Choose Scheduled channel, Direct playlist, or Multi-zone layout.
Assign one screen directly, select several screens, target a group,
or target the whole fleet. Bulk targeting resolves the current
members when you stage the change.
Connect the display
Select Open player to obtain the permanent managed
player URL. A native PyWebView deployment can use the configuration
command shown under PyWebView client setup for that
screen. Keep each device on its own screen URL so health and commands
are attributed correctly.
Preview drafts and publish safely
- Stage the desired assignment on the dashboard or screen inventory.
- Select Preview draft and check the content at the screen's saved resolution.
- Temporarily compare another resolution or scaling mode if needed.
- Return to the dashboard and select Publish.
- Confirm that the screen reports the new published revision and remains online.
Publish delivers all staged screen assignments as one fleet batch.
Connected players normally detect a new revision within two seconds
and switch to it atomically.
Previewing does not publish, advance a revision, or count as device
contact. An external web page may also refuse to appear in Preview
because of that website's embedding policy.
Monitor screens and offline playback
The Dashboard labels
screens as online, degraded, offline, or never connected. It also
shows last contact, cache readiness, service-worker state, storage
use, revision, last played item, and the latest cache error.
- After the first publish, open the player while online and wait for Offline playlist ready.
- Local images, videos, PDFs, text, templates, and player assets can then survive a connection loss.
- RSS feeds cache their last successful publish-time snapshot for outages.
- Web items can opt into static screenshots when the optional server capture service is enabled; other live pages show an offline message.
- The player warns when a revision approaches available browser storage and refuses updates that cannot fit, while preserving the last complete revision.
- A failed cache update keeps the last complete published revision.
- Administrators can request Sync now, restart the browser player, or clear LibreSignage caches.
- Run
uv run libresignage-monitor beside the server for email, signed webhook, and Telegram transition, recovery, and digest notifications.
The native client can opt into operating-system reboot with
configure --allow-os-reboot. The action appears only
while its independent agent is connected, and the local account must
have reboot permission.
Verify playback history
Open Proof of play
to answer when an asset ran on a managed screen. Filter the report by
date, screen, asset title or ID, layout zone, and outcome, then export
the same result as CSV.
- Played means the item reached its natural configured duration.
- Skipped means playback was interrupted or superseded before completion.
- Error means the player detected a media loading or playback failure.
- Multi-zone layouts report each zone independently.
- Offline players queue events locally and upload them after reconnecting.
Proof of play is client-reported lifecycle evidence. It does not
verify pixels on the physical display or confirm that an audience saw
the content. Draft previews and emergency messages are not included.
Send an emergency message
Administrators can use the emergency override on the dashboard to
interrupt normal playback on selected screens, a group, or the entire
fleet.
- Enter a short title and clear message.
- Choose critical, warning, or information severity.
- Choose the target and activate the override.
- When the event ends, select Restore published playback.
Restoring clears only the override; it does not alter the screen's
playlist, schedule, layout, or published assignment.
Accounts and roles
| Role | Typical access |
| Admin | Global access, including users, groups/sites, publishing, remote commands, emergency overrides, credentials, and the audit log. |
| Editor | Create shared content and stage assignments on visible screens. An administrator can grant publishing for individual groups/sites or the global fleet. |
| Viewer | Inspect shared content and the screens in assigned groups/sites without making changes. |
Administrators manage accounts
{% if g.user.role == "admin" %}
from Users.
{% else %}
from the Users page.
{% endif %}
Use an individual account for each person; passwords must contain at
least 12 characters.
Screen groups also act as site scopes. A scoped account sees the union
of screens in its assigned groups; ungrouped screens remain admin-only.
Content, playlists, layouts, and schedules are shared across the CMS,
so group scope limits fleet operations rather than asset ownership.
Group publishers publish one authorized group at a time. Administrators
can review publishes, emergencies, account changes, and credential
rotations in the Audit log.
REST API and webhooks
Create a personal bearer credential from
API tokens. Tokens use
your current role and screen-group permissions and can be revoked at
any time. The versioned API base is /api/v1.
curl -H "Authorization: Bearer $LIBRESIGNAGE_API_TOKEN" \
{{ request.url_root.rstrip('/') }}/api/v1/screens
Download the machine-readable
OpenAPI 3.1 contract for
media, playlists, schedules, screens, health, publish, emergency,
and webhook operations.
Administrators configure signed subscriptions from
Webhooks. Run
libresignage-monitor continuously to deliver and retry
screen.offline, publish.completed, and
emergency.activated events.
Troubleshooting checklist
{% for slug, question, answer in [
("not-playing", "My change is not playing", "Look for a Draft changes badge. Confirm the correct source is staged for the screen, then publish. Compare the screen's published revision with the latest publish."),
("black-screen", "The player is blank or black", "Open Preview draft and inspect every playlist or layout zone. Confirm that content is not expired, a video is ready, and a web page permits iframe embedding. Check the dashboard for the player's cache or media error."),
("offline", "A screen is offline", "Check power and network access, confirm the display is using the correct permanent player URL, and review its last-contact time. Once connected, use Sync now if the published revision is stale."),
("cache", "Offline playlist is not ready", "Keep the player open while online. Check storage quota, service-worker state, and the latest cache error. Clear LibreSignage caches only when you can reconnect and download the full revision again."),
("schedule", "The wrong scheduled playlist is active", "Verify the screen uses Scheduled channel. Check timezone, date range, weekday, daypart, enabled state, and overlapping priorities. Remember that overnight ranges cross midnight."),
("web", "A web page or feed does not appear", "Test the URL from the player network. Web pages must allow iframe embedding. Feeds must be valid RSS or Atom and publicly reachable; live web content is unavailable offline.")
] %}
{% endfor %}