Vibefed kb-peertube

install
source · Clone the upstream repo
git clone https://github.com/reiver/vibefed
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/reiver/vibefed "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/kb-peertube" ~/.claude/skills/reiver-vibefed-kb-peertube && rm -rf "$T"
manifest: skills/kb-peertube/SKILL.md
source content

PeerTube — Complete Reference

Overview

PeerTube is a free, open-source, decentralized video streaming platform — the Fediverse's alternative to YouTube. Created by Chocobozzz and supported by the French non-profit Framasoft since October 2017, it federates via ActivityPub. As of October 2025, it has approximately 1,906 active instances, 815,000 registered users, and 1.56 million hosted videos. Licensed under AGPL-3.0.

PeerTube federations are asymmetrical — one instance can follow another to display their videos without the other having to reciprocate. This is fundamentally different from Mastodon's symmetrical user-follow model.


1. Technical Stack

LayerTechnology
Backend languageTypeScript (Node.js)
Backend frameworkExpress
DatabasePostgreSQL 12+ (with
pg_trgm
and
unaccent
extensions)
Cache / QueueRedis (BullMQ for job queues)
ORMSequelize
Video processingFFmpeg (LTS 4.3+)
OAuthBuilt-in OAuth 2.0
Web serverNginx (official configs provided)
Package managerpnpm
Frontend frameworkAngular (TypeScript)
PlaybackVideoJS, hls.js, P2P Media Loader
Frontend buildWebpack
Frontend CSSSASS / Bootstrap
MobileOfficial app (iOS + Android, December 2024)
LicenseAGPL-3.0
RuntimeNode.js LTS 20.19+ (excl. v21) or v22.12+ (excl. v23)

Server Components

  • REST API — handles client requests and video operations
  • RTMP server — accepts live streaming input (port 1935/TCP, 1936/TCP for RTMPS)
  • ActivityPub implementation — federation between instances
  • Socket.io server — real-time client notifications
  • Task scheduler — processes transcoding and ActivityPub delivery jobs via BullMQ

2. Actor Model

PeerTube uses a two-tier actor model that is central to how it federates video content:

  • Person — represents user accounts
  • Group — represents video channels, owned by Person actors
  • Application — platform-level instance actor for federation and anonymous activities

A single Person can own multiple Group (channel) actors.

Person Actor (Account)

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://w3id.org/security/v1",
    {"pt": "https://joinpeertube.org/ns#"}
  ],
  "type": "Person",
  "id": "https://peertube.example/accounts/alice",
  "preferredUsername": "alice",
  "name": "Alice",
  "summary": "<p>Bio text</p>",
  "inbox": "https://peertube.example/accounts/alice/inbox",
  "outbox": "https://peertube.example/accounts/alice/outbox",
  "following": "https://peertube.example/accounts/alice/following",
  "followers": "https://peertube.example/accounts/alice/followers",
  "publicKey": {
    "id": "https://peertube.example/accounts/alice#main-key",
    "owner": "https://peertube.example/accounts/alice",
    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
  },
  "endpoints": {
    "sharedInbox": "https://peertube.example/inbox"
  }
}

Group Actor (Video Channel)

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://w3id.org/security/v1",
    {"pt": "https://joinpeertube.org/ns#"}
  ],
  "type": "Group",
  "id": "https://peertube.example/video-channels/alice_channel",
  "preferredUsername": "alice_channel",
  "name": "Alice's Channel",
  "summary": "<p>Channel description</p>",
  "inbox": "https://peertube.example/video-channels/alice_channel/inbox",
  "outbox": "https://peertube.example/video-channels/alice_channel/outbox",
  "following": "https://peertube.example/video-channels/alice_channel/following",
  "followers": "https://peertube.example/video-channels/alice_channel/followers",
  "attributedTo": [
    {
      "type": "Person",
      "id": "https://peertube.example/accounts/alice"
    }
  ],
  "publicKey": {
    "id": "https://peertube.example/video-channels/alice_channel#main-key",
    "owner": "https://peertube.example/video-channels/alice_channel",
    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
  },
  "endpoints": {
    "sharedInbox": "https://peertube.example/inbox"
  }
}

Key points:

  • The Group actor's
    attributedTo
    points to the owning Person actor
  • Users follow channels (Group), not accounts (Person) directly
  • Both Person and Group actors are discoverable via WebFinger
  • The shared inbox path is
    /inbox
  • The Application instance actor handles platform-level federation and anonymous GET request signing

Interoperability with Non-Channel Platforms

For platforms that don't have a channel concept, PeerTube recommends:

  1. Simulate a Group actor representing the account, or
  2. Put the Person actor as a Group actor in
    attributedTo
    owned by a global Person actor

Without a Group actor in

attributedTo
, PeerTube cannot properly federate the video.


3. Supported Activities

ActivityDescription
Accept
Approves follow requests
Announce
Channel announces a video (primary video distribution mechanism)
ApproveReply
Comment moderation approval (v6.2+, implements FEP-5624)
Create
Creates Video, Note (comment), CacheFile, Playlist
Delete
Removes Video, Note, Person, Group, Playlist, CacheFile
Dislike
Thumbs down on a video (non-standard — most Fediverse software only has Like)
Flag
Federated report functionality
Follow
Subscribe to a channel or instance
Like
Thumbs up on a video
Reject
Denies follow requests
Undo
Reverses Follow, Announce, Like, Dislike, CacheFile
Update
Modifies Video, Note, Person, Group, Playlist, CacheFile
View
View count tracking

How Video Publishing Works

When a user uploads a video:

  1. The Person actor sends a
    Create{Video}
    activity
  2. The Group (channel) actor sends an
    Announce{Video}
    to its followers
  3. Followers of the channel receive the video via the Announce

This two-step flow is how PeerTube distributes videos — the channel

Announce
is the primary distribution mechanism.


4. Object Types

Video Object

PeerTube uses

Video
as the object type (not
Note
). This is an extended ActivityStreams object with many custom properties:

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://w3id.org/security/v1",
    {"pt": "https://joinpeertube.org/ns#"},
    {"sc": "http://schema.org/"}
  ],
  "type": "Video",
  "id": "https://peertube.example/videos/watch/abc-123",
  "name": "My Video Title",
  "content": "<p>Video description</p>",
  "summary": "Content warning text",
  "sensitive": false,
  "published": "2025-06-15T12:00:00Z",
  "updated": "2025-06-15T13:00:00Z",
  "attributedTo": [
    {
      "type": "Group",
      "id": "https://peertube.example/video-channels/alice_channel"
    },
    {
      "type": "Person",
      "id": "https://peertube.example/accounts/alice"
    }
  ],
  "to": ["https://www.w3.org/ns/activitystreams#Public"],
  "cc": ["https://peertube.example/video-channels/alice_channel/followers"],
  "duration": "PT5M30S",
  "downloadEnabled": true,
  "waitTranscoding": true,
  "state": 1,
  "commentsPolicy": 0,
  "canReply": "https://www.w3.org/ns/activitystreams#Public",
  "isLiveBroadcast": false,
  "url": [
    {
      "type": "Link",
      "mediaType": "text/html",
      "href": "https://peertube.example/videos/watch/abc-123"
    },
    {
      "type": "Link",
      "mediaType": "video/mp4",
      "href": "https://peertube.example/static/streaming-playlists/hls/abc-123/master.m3u8",
      "height": 1080,
      "fps": 30
    }
  ],
  "embedUrl": "https://peertube.example/videos/embed/abc-123",
  "tag": [
    {
      "type": "Hashtag",
      "name": "#technology"
    }
  ]
}

Key points about the Video object:

  • attributedTo
    must contain both a Group (channel) and a Person (account) — the Group entry is required for federation
  • name
    is the video title (not
    summary
    as with Mastodon posts)
  • content
    is the video description (HTML)
  • summary
    is used for content warnings (like Mastodon)
  • duration
    uses ISO 8601 duration format (e.g.,
    PT5M30S
    )
  • url
    is an array with multiple entries for different formats and resolutions (HTML page, MP4 files, HLS playlists)
  • If
    embedUrl
    is absent, the video has embedding restrictions
  • sensitive
    and a tag of
    type: SensitiveTag
    indicate sensitive content

Video Object Extensions

Live streaming properties:

  • isLiveBroadcast
    — whether this is a live stream
  • liveSaveReplay
    — whether to save the replay after stream ends
  • permanentLive
    — persistent stream URL that can be reused
  • latencyMode
    — latency configuration for the stream
  • schedules
    — array for scheduled broadcast times

Interaction controls:

  • commentsPolicy
    — comment policy (integer value)
  • canReply
    — FEP-5624; when set to the public collection, comments require approval via
    ApproveReply
  • downloadEnabled
    — boolean controlling whether viewers can download

State:

  • waitTranscoding
    — whether to wait for transcoding before publishing
  • state
    — current video state (integer)

Note (Comments)

Comments are represented as

Note
objects, compatible with Mastodon and other text-based platforms:

{
  "type": "Note",
  "id": "https://peertube.example/comments/456",
  "content": "<p>Great video!</p>",
  "inReplyTo": "https://peertube.example/videos/watch/abc-123",
  "attributedTo": "https://peertube.example/accounts/bob",
  "published": "2025-06-15T14:00:00Z",
  "to": ["https://www.w3.org/ns/activitystreams#Public"],
  "cc": ["https://peertube.example/accounts/alice"]
}

When a Mastodon user replies to a PeerTube video post, the reply appears as a comment on the video in PeerTube.

CacheFile (Redundancy)

A non-standard object type used for PeerTube's video mirroring system:

{
  "type": "CacheFile",
  "object": "https://peertube.example/videos/watch/abc-123",
  "expires": "2025-07-15T12:00:00Z",
  "url": {
    "type": "Link",
    "mediaType": "application/x-mpegURL",
    "href": "https://mirror.example/redundancy/hls/abc-123/master.m3u8"
  }
}

Other Object Types

TypePurpose
Playlist
Non-standard OrderedCollectionPage containing PlaylistElement items
PlaylistElement
Individual playlist entries with start/stop timestamps
WatchAction
Schema.org-derived object for aggregated viewer statistics

5. Video Redundancy and CacheFile

PeerTube has a built-in redundancy system allowing instances to mirror videos from other instances, improving resilience and bandwidth sharing.

How Redundancy Works

  1. An admin configures a redundancy strategy (cache trending videos, recently uploaded videos, etc.)
  2. PeerTube periodically checks for new videos to duplicate
  3. When a video is selected, all resolution files are imported and stored locally
  4. A
    Create{CacheFile}
    ActivityPub message is sent to federated instances
  5. The caching instance is injected as a WebSeed by instances that receive this message — viewers can now download video chunks from the mirror
  6. When the cache is full, old videos are evicted and new ones selected

ActivityPub Flow

  • Create{CacheFile}
    — sent when a mirror instance begins caching
  • Undo{CacheFile}
    — sent when the cached copy is removed

Redundancy Strategies

  • Most viewed — cache the most popular videos
  • Recently added — cache the newest videos
  • Complete mirror — use
    recently-added
    with view count set to 0

Benefits

  • If the origin server goes down, the video remains accessible from cache instances
  • Servers share bandwidth for popular content
  • P2P delivery benefits from additional WebSeeds

6. P2P Video Delivery

PeerTube uses HLS with WebRTC P2P for video playback:

  • Video chunks are loaded via HTTP from the origin server and any mirrors (WebSeeds)
  • Simultaneously, chunks are exchanged between viewers via WebRTC peer-to-peer connections
  • Under optimal conditions (many concurrent viewers), P2P can reduce server bandwidth usage by 80-90%
  • P2P efficacy diminishes with few concurrent viewers

Up until version 6.0.0, PeerTube also supported WebTorrent for P2P delivery. WebTorrent was dropped in v6.0 in favour of HLS-only P2P.

Privacy Consideration

P2P streaming exposes viewer IP addresses to other peers. This is inherent to how WebRTC works and should be considered when deploying PeerTube in privacy-sensitive contexts.


7. Live Streaming

PeerTube supports live streaming (introduced in v3.0, January 2021):

  • RTMP ingestion — stream via OBS or any RTMP-compatible software (port 1935/TCP)
  • RTMPS — encrypted streaming (port 1936/TCP)
  • Live transcoding — real-time transcoding to multiple resolutions
  • HLS output — live streams delivered via HLS with P2P WebRTC
  • Permanent live streams — persistent stream URLs that can be reused
  • Stream scheduling — schedule when a stream starts (v7.3+)
  • Live chat — basic integration (v7.3+)
  • Save replay — optionally save recordings as VOD after stream ends
  • Federation — live streams federate to channel followers via ActivityPub using Video objects with
    isLiveBroadcast: true

Live transcoding is processed differently from VOD transcoding — it happens in real-time and can be offloaded to remote runners.


8. JSON-LD Context

PeerTube uses extended contexts with multiple custom namespaces:

"@context": [
  "https://www.w3.org/ns/activitystreams",
  "https://w3id.org/security/v1",
  {"pt": "https://joinpeertube.org/ns#"},
  {"sc": "http://schema.org/"}
]
NamespacePrefixPurpose
https://www.w3.org/ns/activitystreams
ActivityStreams 2.0 vocabulary
https://w3id.org/security/v1
W3C Security Vocabulary (publicKey)
https://joinpeertube.org/ns#
pt:
PeerTube-specific properties (commentsPolicy, downloadEnabled, isLiveBroadcast, etc.)
http://schema.org/
sc:
Schema.org vocabulary (WatchAction, etc.)
https://join-lemmy.org/ns#
lemmy:
Lemmy compatibility (postingRestrictedToMods)

When processing PeerTube JSON-LD documents, unknown properties from the

pt:
namespace should be ignored rather than causing errors.


9. HTTP Signatures and WebFinger

HTTP Signatures

PeerTube signs ActivityPub messages with JSON Linked Data Signatures using the private key of the account that authored the action. HTTP Signatures are used for server-to-server authentication.

Each actor (Person, Group, Application) has its own key pair. The Application instance actor is used for platform-level operations.

WebFinger

PeerTube supports WebFinger at

/.well-known/webfinger
for actor discovery. Both Person (account) and Group (channel) actors are discoverable:

  • Account:
    acct:alice@peertube.example
  • Channel:
    acct:alice_channel@peertube.example

10. Cross-Platform Federation

Mastodon Interoperability

Action on MastodonResult on PeerTube
Follow a PeerTube channelVideos appear in Mastodon home timeline
Reply to a PeerTube video postAppears as a comment on the video
Favourite a PeerTube videoAppears as a thumbs up (Like)
Boost a PeerTube videoIncreases reach on federated timelines
Action on PeerTubeResult on Mastodon
Upload a videoAppears as a post in followers' timelines
Like a Mastodon commentStandard Like activity
DislikeNot processed — Mastodon ignores Dislike activities

Dislike (Non-Standard)

PeerTube supports the

Dislike
activity (thumbs down), which is non-standard in the broader Fediverse. Most Fediverse software only implements
Like
. Mastodon does not send or process
Dislike
activities, so dislikes from PeerTube are silently ignored by Mastodon and most other platforms.

Comment Approval (FEP-5624)

PeerTube v6.2+ supports comment moderation via the

ApproveReply
activity (implementing FEP-5624). When a video has
canReply
set to the public collection, comments from remote instances require approval before becoming visible. The origin PeerTube instance sends an
ApproveReply
activity back to the commenter's instance when approved.

Asymmetrical Instance Following

PeerTube instances can follow other PeerTube instances to display their videos without the followed instance needing to reciprocate. This is an admin-level operation used for content discovery.


11. Plugin System and Remote Runners

Plugin System

  • Plugins are installed via NPM in a dedicated directory
  • The server
    require
    s the module and calls its
    register()
    function
  • Hooks fire on application events (video creation, page initialization, transcoding, etc.)
  • Themes operate as client-only plugins with CSS injection
  • Plugins can add custom API routes, settings pages, and client-side components

Remote Runners

PeerTube can offload heavy processing to remote machines:

  • Remote runners register with the instance using registration tokens
  • They poll the REST API for pending jobs
  • Supported tasks: VOD transcoding, Studio transcoding, Live transcoding, Automatic transcription
  • When remote runners are enabled for a task, PeerTube stops processing that task locally
  • The runner posts the job result back to PeerTube

Known limitation: Server-side transcoding plugins are disabled when remote runners are enabled for transcoding tasks.


12. Common Implementation Mistakes

  • Missing Group actor in
    attributedTo
    : PeerTube requires videos to have an
    attributedTo
    field containing a Group actor — without it, the video cannot be properly federated. If your platform does not have channels, simulate a Group actor or use the Person actor in the Group role
  • Treating PeerTube videos as Note objects: PeerTube uses
    Video
    as the object type, not
    Note
    — code that only handles
    Note
    will miss all PeerTube content. Implement handling for
    type: "Video"
    in your ActivityPub processor
  • Ignoring the two-tier
    attributedTo
    : PeerTube's
    attributedTo
    contains both a Group (channel) and a Person (account) — if you only read the first entry, you may attribute the video to the channel instead of the person, or vice versa
  • Not handling
    Dislike
    gracefully
    : PeerTube sends
    Dislike
    activities that most Fediverse software does not understand — your implementation should ignore unknown activity types rather than erroring
  • Assuming video URL is a single string: PeerTube's
    url
    field is an array with multiple entries for different formats (HTML page, MP4 at various resolutions, HLS playlists) — pick the appropriate entry based on
    mediaType
  • Not handling
    CacheFile
    : if you receive a
    Create{CacheFile}
    activity, it means a remote instance is mirroring one of your videos — you should add the mirror as a WebSeed for that video, not reject the activity as unknown
  • Expecting symmetrical follows: PeerTube instance-level follows are asymmetrical — following an instance does not mean they follow you back. Don't assume mutual federation.
  • Ignoring
    embedUrl
    absence
    : if a PeerTube Video object lacks
    embedUrl
    , the video has embedding restrictions — do not attempt to generate an embed URL by guessing the pattern
  • Not supporting
    ApproveReply
    : if your users comment on PeerTube videos with comment approval enabled, the comment won't be visible until the PeerTube instance sends back an
    ApproveReply
    — handle this pending state in your UI rather than showing it as posted