Live pages
Pages that update the moment something happens, for everyone on them at once. Live scores, chat, multiplayer games, and real-time for apps you host elsewhere.
A live page stays connected, so it changes the moment something happens: a goal is scored, an order comes in, another player moves. Everyone on the page gets the change at once, and nobody reloads. Your agent builds it from the same pieces as any other page, and Tessryx runs the connections at its edge, so there's no server of yours to keep running.
You don't need to know the details below to have one. Ask your agent for "a scoreboard that updates live" or "a chat room with who's online" and it sets them up. This page explains what it set up.
#How a live page works
A live page is an endpoint with a live section. Instead of loading it,
the page connects to it, and it keeps the endpoint's address, its sign-in gate, your custom
domain and its run history like any other.
- A stream is the name updates are sent to, like
scores. - Any workflow publishes to the stream with a publish step: a route a form posts to, a webhook from another service, a schedule.
- The live endpoint's own workflow shapes each update for the people watching, and what it returns is what they get. Returning nothing sends nothing, so published data never reaches a browser unchecked.
The page connects with the site runtime, a small script every Tessryx site serves at
/_tessryx/site-1.js. It reconnects by itself, catches up on what it missed, and tells the
page what's going on with a reason it can show a visitor: reconnecting, paused, full or closed.
#Sending updates
Each update runs the live endpoint's workflow once for each different input among the people watching. A thousand people watching the same match is one run; people watching three different matches is three. With nobody watching, a publish runs nothing at all.
Give updates a key, like the match they're about, and ones published with the same key within a tenth of a second are merged, with only the latest sent. A burst of score changes doesn't become a burst of runs.
#When someone joins
A new viewer can see the current state straight away instead of waiting for the next update: an initial workflow renders what they see the moment they join. Joining costs a credit, like a page view. A phone that loses its connection, or a tab that comes back from the background, reconnects for free within a few minutes and is sent whatever it missed, up to a minute's worth.
#People sending to each other
People on a live page can send too, on channels you name. There are two kinds.
- Relay passes each sender's messages straight to everyone else at the edge, with no run per message. It suits fast things: positions in a game, cursors, strokes on a whiteboard. Messages go out in batches about ten times a second (you can set every 50 to 250 milliseconds), each one stamped with its sender, so nobody can speak for anyone else. A channel can keep each sender's latest message per batch, for positions, or every message, for shots and strokes.
- Screened sends each message through one of your routes first. The page posts a chat line to its own route, whose workflow checks it, cleans it up and publishes it to the channel. Nothing is kept unless your workflow saves it.
Who may send is set per channel: signed-in people, or anyone.
#Checks at the edge
Every relay message is checked before anyone else sees it, for free:
- Its shape: it has to match the channel's schema, a simple one where every text field has a pattern or a list of allowed values and every number a range. A message is at most 1 KB.
- How often: messages a second per sender, 10 by default and 30 at most.
- Rules you add with no code: a cooldown between one sender's messages (one reaction at a time), number fields that may only go up (a score), and fields to record for each sender in the room's state, for a route to read later.
When a message is dropped, the sender's page is told why, so it can show the player something sensible.
#Game rules in a handler
For your app's own rules, a handler is a workflow the edge runs on each batch of messages before anyone sees them: a top speed, a weapon's cooldown, ammo, whose turn it is, or that only a stroke's author can erase it. It can drop a message, change it, update the sender's entry or the room, or hand it to another workflow to award a point or save a score.
A handler runs a few times a second, so it does calculation only, with JavaScript expressions: no reading or writing records and no calls to other services. Publishing the endpoint tries it on a sample message first and refuses one that doesn't fit, with the reason. If a handler is ever too slow for a batch, that batch goes out on the built-in checks, so it never holds up the game.
#Who's here
Turn on presence and every page gets the list of who's on it, who just joined and who left, and a count. It uses no credits.
- Names come from your join workflow (below). Everyone on the page sees them, so use a display name, never an email.
- No flicker: someone counts as gone 30 seconds after their last tab closes, so a reload or a network blip doesn't show them leaving and coming back.
- Big audiences: past 100 people, pages get the count without the list.
#When someone leaves
Most pages don't need anything more than presence. For work when someone is gone for good, like freeing a seat in a lobby, ending a match or settling a player's score into a record, a leave workflow runs once for each person, 30 seconds after their last connection closed. A reload or a reconnect inside that time doesn't run it.
#Room state
Everyone watching one stream shares a small room state: round settings, spawn points, a board. Your workflows change it, and every page gets it when it joins and whenever it changes.
It lasts as long as people are watching, unless you name two workflows to keep it: one that loads it when the first person joins, for example from a content record, and one that saves it every 5 minutes while people are watching and once after the last person leaves, each time only if it changed.
#Bring your own users
A join workflow decides each person joining: who gets in, the id they appear under, which channels they may send on, and when their access ends. It runs after the endpoint's own sign-in gate, so it can only narrow who gets in. Use it for an invite list, a player limit, a ban list, or your own app's accounts.
To bring your own users, your backend signs a short token, and the join workflow checks it with a key you also stored as a secret:
- JWTs signed with a shared key (HS256, HS384, HS512) or checked with a public key (RS256, RS384, RS512, ES256, ES384). The key decides which algorithm is accepted, never the token.
- HMAC-SHA256 signatures over a message you choose, also handy for signed links.
Tessryx only ever sees the token. A person admitted this way appears under your own id for them. A workflow can take away their right to send at once, and their admission ends at the time the join workflow set (at most 12 hours), when rejoining runs the join workflow again and it can turn them away. A workflow can also close the live page for everyone, with a reason.
On another website. An app hosted anywhere can connect: it loads the site runtime from your Tessryx site's address and names that site as the host, or uses any WebSocket client. WebSockets don't need a cross-site setting. Signing in with Tessryx doesn't carry over to another website, so there the join workflow and your tokens decide who gets in. A live page with neither a sign-in gate nor a join workflow is open to anyone.
#What it costs
Live pages use the same credits as everything else.
| What | Credits |
|---|---|
| Someone joining | 1 (reconnecting within a few minutes is free) |
| An update | 1 for each different input among the people watching, however many there are |
| Relaying | 1 for each person who sends in a minute, at least 2 a minute while anyone sends |
| A handler | 8 for each relaying minute it runs |
| Big audiences | 2 per relaying minute for each thousand watchers past the first thousand |
| Who's here | Free |
| The join, initial, leave, load and save workflows, and each screened line's route | 1 a run, like any run |
Four players relaying for an hour with a handler: 4 joins, 240 for relaying and 480 for the handler, 724 credits in all. A thousand people watching a scoreboard for two hours, updated once a minute: 1,000 joins and 120 updates, 1,120 credits.
Out of credits, new joins are refused and relaying pauses, while open connections stay up and pages are told live updates are paused. A top-up within 10 minutes picks up where it left off. After 10 minutes the pages close with that reason, and they try again every 10 minutes and whenever the visitor comes back to the tab.
#Limits
- People on one live page at once, every room on it together: 100 on Free, and 5,000 on Pro, Agency and Scale. Past that, a new viewer is told the page is full, and nobody already watching is dropped. See Plans & limits.
- Messages: at most 1 KB each, and at most 30 a second per sender.
- Room state holds up to 64 KB. A change that would take it past that is refused, and a sender's page is told the room is full.
- Presence lists up to 100 people; past that, the count only.
- A handler does calculation only (above), and an endpoint has one.
- Ordinary pages and routes aren't streamed. Updates reach a page over its live connection; a normal request still gets its whole answer at once.