Skip to content

Clips

There are two ways to get a time range out of a stream:

Stored clip (createClip)Ad-hoc cut (URL parameters)
What you getA new asset in your account with its own playbackIdA one-off MP4, MKV, WebM, or TS response
StoredYes, until you delete it or retention expires itNo
Playable asEvery protocol (HLS, DASH, WebRTC, MP4, …) and the playerThe single file you requested
Access policySnapshot of the source’s policy at creationThe source’s policy, checked on the request
Billed asStorage, plus delivery when watchedDelivery, like any other playback
Use it forHighlights you share, embed, or list laterDownloads, exports, and handing a range to another tool

A stored clip is processed on the media cluster and saved as its own asset. It gets a playbackId, shows up in your storage listing, and plays through the same player and URLs as any stream or VOD asset, without exposing the source stream’s playback ID.

createClip takes the source stream’s global ID, a title, and a time range in one of four modes:

modeRangeFields
ABSOLUTE (default)Exact start and stopstartUnix + stopUnix
DURATIONStart time plus a lengthstartUnix + duration
CLIP_NOWThe last N seconds of the live streamduration
RELATIVESeconds from the stream startstartMedia + stopMedia

startUnix and stopUnix are Unix timestamps in seconds; duration, startMedia, and stopMedia are seconds. expiresAt (Unix seconds) optionally deletes the clip at that time.

mutation {
createClip(
input: {
streamId: "<stream global id>"
title: "Last 30 seconds"
mode: CLIP_NOW
duration: 30
}
) {
__typename
... on Clip {
id
clipHash
playbackId
status
}
... on ValidationError {
field
message
}
... on NotFoundError {
message
}
}
}

See SDKs for client setup, retries, and typed errors.

Always pass the live stream’s ID, however far back the range goes. FrameWorks picks the source from where the range falls:

  • The live buffer (about the last two minutes): read from the live stream.
  • The rolling DVR window, when the stream is recording: read from the DVR segments.
  • A finalized chapter (FINALIZED, FROZEN, or RECLAIMED): read from the chapter file.

A range that spans two sources, such as the live buffer and the DVR window or two chapters, is rejected with a ValidationError. Split it into two clips.

The clip exists as soon as createClip returns, and status moves through queued, processing, and ready, or ends at failed. Follow it with the clip events of tenantEvents (pass streamId for one stream only) or the matching webhooks:

subscription {
tenantEvents(types: ["clip.requested", "clip.ready", "clip.failed"]) {
type
time
data {
... on ClipReady {
artifact {
artifactId
}
durationMs
sizeBytes
}
... on ClipFailed {
artifact {
artifactId
}
reason
}
}
}
}

artifactId is the clip’s clipHash. Clip events leave artifact.playbackId empty; read the clip’s playbackId with clip(id: "<clipHash>") or with storageArtifactsConnection and artifactHash. See Events for every payload field.

A ready clip plays at the same URLs as any other content, or through the player with its playbackId:

https://foghorn.frameworks.network/play/{clipPlaybackId}/hls/index.m3u8
https://foghorn.frameworks.network/play/{clipPlaybackId}.mp4

For a custom player, resolveViewerEndpoint(contentId: "<clip playback id>") returns the edge node and its output catalog.

The clip’s playback policy is a snapshot of the source stream’s policy when the clip was created. Changing the stream’s policy later does not change clips that already exist. See playback access control.

Clips are listed with the other stored media through storageArtifactsConnection:

query {
storageArtifactsConnection(input: { kinds: [CLIP], streamId: "<stream global id>", first: 20 }) {
nodes {
id
hash
title
playbackId
status
durationSeconds
sizeBytes
createdAt
expiresAt
}
totalCount
hasNextPage
}
}

clip(id: ID!) fetches one clip by global ID. Deleting removes the clip’s media and cannot be undone:

mutation {
deleteClip(id: "<clip global id>") {
__typename
... on DeleteSuccess {
success
}
... on NotFoundError {
message
}
}
}

Clips count toward storage and follow your retention settings; see storage and retention. Agents create and delete clips with the create_clip and delete_clip MCP tools.

Any progressive playback URL (.mp4, .mkv, .webm, .ts) accepts time-range parameters. The edge cuts the range on the fly and returns it as a single file. Nothing is processed in advance or saved to your account.

Terminal window
# The last 60 seconds of a live stream, as a download
curl -L -o last-minute.mp4 "https://foghorn.frameworks.network/play/{playbackId}.mp4?startunix=-60&dl=1"
# A fixed wall-clock range from the DVR window, delivered as fast as possible
curl -L -o keynote.mkv "https://foghorn.frameworks.network/play/{dvrPlaybackId}.mkv?startunix=1706000000&stopunix=1706000060&rate=0"

/play validates these parameters and passes them on to the edge it redirects to. Other query parameters are not forwarded.

ParameterValueEffect
startunixUnix secondsStart of the cut in wall-clock time. A value of 36000 or less is relative to now: -300 means five minutes ago.
stopunixUnix secondsEnd of the cut, with the same relative rule.
durationSecondsLength of the cut from its start. Takes precedence over stop and stopunix.
startMillisecondsStart of the cut on the content’s own media timeline.
stopMillisecondsEnd of the cut on the content’s own media timeline.
dl1 or a file nameSends the response as a download. A value with a dot, such as dl=keynote.mp4, is the file name; otherwise the URL’s file name is used. Also turns off realtime pacing.
rateNumberDelivery speed: 0 sends as fast as the network allows, 2 at twice realtime.
audio, video, subtitleTrack selectorWhich tracks to include, such as video=all or audio=none.

Behavior to expect:

  • The cut starts at the keyframe at or before the requested start.
  • A start earlier than the available media is moved up to the oldest available point. A stop earlier than the available media returns an error.
  • On a live stream, a stop in the future holds the response open until that moment arrives.
  • Cuts are supported on progressive formats only. Segmented protocols (HLS, DASH) and WebRTC are not a reliable way to request a range.

How far back you can reach depends on the playback ID:

Playback IDReachUse
Live playbackIdAbout the last two minutes”The last N seconds” with startunix
dvrPlaybackIdThe recording’s rolling DVR windowLonger ranges while the stream is live
A chapter’s playbackIdThat chapterRanges from finished recordings
A VOD asset’s or clip’s playbackIdThe whole asset, with start and stopTrimming uploaded or stored media