Live for Craft CMS

GraphQL

GraphQL is a Pro feature. On Lite nothing is registered at all, so Live's queries are absent from the schema rather than present and answering with an error.

The API is shaped like the JavaScript client rather than a generic element API: a headless front end polls one cheap query and fetches updates only when the sequence has moved.

Poll liveFeed

liveFeed reads the post's head row — one indexed row, no element query:

{
  liveFeed(postId: 923) {
    seq
    state
    isLive
    isFollowable
    count
    pinnedId
    startedAt
    endedAt
  }
}

postId is the entry's ID. fieldId is optional — most entries carry one Live field and Live finds it — and siteId defaults to the current site.

Fetch what you are missing

When seq has moved past what you hold, ask for everything after it:

{
  liveUpdates(postId: 923, since: 412, orderBy: "seq asc") {
    id
    seq
    rev
    body
    postedAt
    typeHandle
    ... on goal_LiveUpdate {
      scorer
    }
  }
}

Each update type has its own GraphQL type, <handle>_LiveUpdate, carrying its field layout's fields.

liveUpdate returns one update and liveUpdateCount counts them. All three take the same arguments:

ArgumentNarrows to
postIdUpdates on a given entry
fieldIdUpdates posted through a given Live field
type / typeIdOne or more update types, by handle or ID
seqSpecific sequence numbers
sinceUpdates after this sequence number — the polling query
beforeUpdates below this sequence number — loading older ones
pinnedThe pinned update, or everything but it
highlightKey moments
authorIdUpdates by a given author

plus the usual element arguments — limit, offset, orderBy, id.

Fields on an update

Field
seq, revSequence number, and revision (bumped on every edit)
postId, fieldIdWhere it belongs
typeHandle, typeName, color, iconIts update type
bodyPurified HTML
sourceWhat the editor typed, before it became HTML
excerptA plain-text summary
htmlThe update rendered through the site's own live/_update.twig
pinned, highlightPinned, key moment
postedAtWhen it was posted
authorId, authorNameWho posted it

html is the same markup the server would have produced, which is useful when a JavaScript front end wants the site's card rather than its own. It costs a template render per update, so it is only produced when you ask for it.

Handling edits and deletions

An edited update keeps its seq and increments rev. A front end that keys on seq alone will show the original wording forever: keep rev alongside, re-fetch an update when its rev changes, and replace it in place.

The field on its entry

The Live field appears on its owner's GraphQL type and returns the same shape as liveFeed, with an updates field that takes the arguments above:

{
  entry(id: 923) {
    ... on liveMatch_Entry {
      commentary {
        seq
        state
        updates(limit: 20) {
          seq
          body
        }
      }
    }
  }
}

Schemas and tokens

Each update type is its own schema component, listed under Live in the schema editor as Query for "Goal" live updates (liveupdatetypes.<uid>:read). A token can be given the match commentary without being given the newsroom's internal feed.

A type outside the schema isn't merely filtered out of results: its GraphQL type doesn't exist for that token at all. A token that can read none of the types on a post gets null from liveFeed, so it can't learn the post's state either.

Grant read access to the update types a token needs, and nothing more. The schema decides what a token can read, so treat a Live update type the way you would an entry section.