Embed PeerTube videos

Hugo lacks a native shortcode for PeerTube embeds. Using a custom shortcode allows you to display videos by providing a URL and optional parameters instead of pasting raw HTML into Markdown files. This keeps the source code clean and centralizes the embed logic in one template file.

Example

Use the following syntax in your Markdown files to display a Peertube video.

{{< peertube url="https://toobnix.org/w/5jBegFpNbffA1nhmp32kqR" >}}

Arguments

Use these arguments to configure the video player.

url
(string) The URL of the PeerTube video.
start
(string) The time, from the start of the video, when the player should start playing the video (e.g., 42s, 6m7s).
stop
(string) The time, from the start of the video, when the player should stop playing the video (e.g., 42s, 6m7s).
loading
(string) The loading attribute of the iframe element, either eager or lazy. Default is eager.
width
(int) The width of the video in pixels. Responsive if 0. Default is 0.
allowFullScreen
(bool) Whether to allow full screen playback. Default is true.
autoplay
(bool) Whether to automatically play the video. Forces mute to true. Default is false.
controls
(bool) Whether to display the video controls. Default is true.
displayLink
(bool) Whether to display the video link. Default is true.
displayTitle
(bool) Whether to display the video title. Default is true.
displayWarning
(bool) Whether to display the privacy warning. Default is true.
loop
(bool) Whether to indefinitely repeat the video. Default is false.
mute
(bool) Whether to mute the video. Always true when autoplay is true. Default is false.
p2p
(bool) Whether to enable peer-to-peer bandwidth sharing. Default is true.

Source

Add this shortcode template to your project.

layouts/_shortcodes/peertube.html
{{- /* Last modified: 2026-03-15T10:30:19-07:00 */}}

{{- /*
Copyright 2025 Veriphor, LLC

Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
*/}}


{{- /*
Embeds a PeerTube video.

@param {string} url The URL of the PeerTube video.
@param {string} [start] The time, from the start of the video, when the player should start playing the video (e.g., 42s, 6m7s).
@param {string} [stop] The time, from the start of the video, when the player should stop playing the video (e.g., 42s, 6m7s).
@param {string} [loading=eager] The loading attribute of the iframe element, either eager or lazy. Default is eager.
@param {int} [width=0] The width of the video in pixels. Responsive if `0`.
@param {bool} [allowFullScreen=true] Whether to allow full screen playback.
@param {bool} [autoplay=false] Whether to automatically play the video. Forces mute to true.
@param {bool} [controls=true] Whether to display the video controls.
@param {bool} [displayLink=true] Whether to display the PeerTube link.
@param {bool} [displayTitle=true] Whether to display the video title.
@param {bool} [displayWarning=true] Whether to display the privacy warning.
@param {bool} [loop=false] Whether to indefinitely repeat the video.
@param {bool} [mute=false] Whether to mute the video. Always true when autoplay is true.
@param {bool} [p2p=true] Whether to enable peer-to-peer bandwidth sharing.

@returns {template.HTML}

@link https://docs.joinpeertube.org/api/embed-player

@example {{< peertube url="https://toobnix.org/w/5jBegFpNbffA1nhmp32kqR" >}}
*/}}

{{- /* Set constants. */}}
{{- $trueValues := slice "true" true 1 }}
{{- $falseValues := slice "false" false 0 }}
{{- $sandbox := "allow-same-origin allow-scripts allow-popups allow-forms" }}

{{- /* Set defaults. */}}
{{- $url := "" }}
{{- $start := "" }}
{{- $stop := "" }}
{{- $loading := "eager" }}
{{- $width := 0 }}
{{- $height := 0 }}
{{- $allowFullScreen := true }}
{{- $autoplay := false }}
{{- $controls := true }}
{{- $displayLink := true }}
{{- $displayTitle := true }}
{{- $displayWarning := true }}
{{- $loop := false }}
{{- $mute := false }}
{{- $p2p := true }}

{{- /* Get parameters. */}}
{{- $url = or (.Get "url") $url }}
{{- $start := or (.Get "start") $start }}
{{- $stop := or (.Get "stop") $stop }}
{{- $width = or (.Get "width") $width | int }}
{{- $loading := or (.Get "loading") $loading }}
{{- if in $trueValues (.Get "allowFullScreen") }}
  {{- $allowFullScreen = true }}
{{- else if in $falseValues (.Get "allowFullScreen") }}
  {{- $allowFullScreen = false }}
{{- end }}
{{- if in $trueValues (.Get "autoplay") }}
  {{- $autoplay = true }}
{{- else if in $falseValues (.Get "autoplay") }}
  {{- $autoplay = false }}
{{- end }}
{{- if in $trueValues (.Get "controls") }}
  {{- $controls = true }}
{{- else if in $falseValues (.Get "controls") }}
  {{- $controls = false }}
{{- end }}
{{- if in $trueValues (.Get "displayLink") }}
  {{- $displayLink = true }}
{{- else if in $falseValues (.Get "displayLink") }}
  {{- $displayLink = false }}
{{- end }}
{{- if in $trueValues (.Get "displayTitle") }}
  {{- $displayTitle = true }}
{{- else if in $falseValues (.Get "displayTitle") }}
  {{- $displayTitle = false }}
{{- end }}
{{- if in $trueValues (.Get "displayWarning") }}
  {{- $displayWarning = true }}
{{- else if in $falseValues (.Get "displayWarning") }}
  {{- $displayWarning = false }}
{{- end }}
{{- if in $trueValues (.Get "loop") }}
  {{- $loop = true }}
{{- else if in $falseValues (.Get "loop") }}
  {{- $loop = false }}
{{- end }}
{{- if in $trueValues (.Get "mute") }}
  {{- $mute = true }}
{{- else if in $falseValues (.Get "mute") }}
  {{- $mute = false }}
{{- end }}
{{- if in $trueValues (.Get "p2p") }}
  {{- $p2p = true }}
{{- else if in $falseValues (.Get "p2p") }}
  {{- $p2p = false }}
{{- end }}

{{- /* Mute if autoplay enabled. */}}
{{- if $autoplay }}
  {{- $mute = true }}
{{- end }}

{{- if $url }}
  {{- /* Determine API URL. */}}
  {{- $u := urls.Parse $url }}
  {{- $pathSegments := strings.Split $u.Path "/" }}
  {{- $shortUUID := index $pathSegments (sub (len $pathSegments) 1) }}
  {{- $api := fmt.Printf "%s://%s/api/v1/videos/%s" $u.Scheme $u.Host $shortUUID }}

  {{- /* Get data from API. */}}
  {{- $data := "" }}
  {{- with try (resources.GetRemote $api) }}
    {{- with .Err }}
      {{- errorf "%s" . }}
    {{- else with .Value }}
      {{- $data = . | transform.Unmarshal }}
      {{- /* Handle null aspect ratio for videos uploaded prior to PeerTube API v6.1.0. */}}
      {{- if not $data.aspectRatio }}
        {{- $aspectRatio := partial "inline/peertube/get-aspect-ratio.html" (dict "data" $data "name" $.Name "position" $.Position) }}
        {{- $data = merge $data (dict "aspectRatio" $aspectRatio) }}
      {{- end }}
    {{- else }}
      {{- warnidf "shortcode-peertube" "The %q shortcode was unable to retrieve the remote data. See %s" $.Name $.Position }}
    {{- end }}
  {{- end }}

  {{- if $data }}
    {{- /* Build src attribute. */}}
    {{- $qsp := dict
      "autoplay"      (cond $autoplay 1 0)
      "controlBar"    (cond $controls 1 0)
      "loop"          (cond $loop 1 0)
      "muted"         (cond $mute 1 0)
      "peertubeLink"  (cond $displayLink 1 0)
      "p2p"           (cond $p2p 1 0)
      "title"         (cond $displayTitle 1 0)
      "warningTitle"  (cond $displayWarning 1 0)
    }}
    {{- with $start }}
      {{- $qsp = merge $qsp (dict "start" .) }}
    {{- end }}
    {{- with $stop }}
      {{- $qsp = merge $qsp (dict "stop" .) }}
    {{- end }}
    {{- $qs := collections.Querify $qsp }}
    {{- $src := fmt.Printf "%s://%s%s?%s" $u.Scheme $u.Host $data.embedPath $qs }}

    {{- /* Render. */}}
    {{- if $width }}
      {{- $height = div $width $data.aspectRatio | math.Round }}
      <iframe
        {{- if $allowFullScreen }} allowfullscreen {{- end }}
        width="{{ $width }}"
        height="{{ $height }}"
        frameborder="0"
        loading="{{ $loading }}"
        title="{{ $data.name }}"
        sandbox="{{ $sandbox }}"
        src="{{ $src }}"
      ></iframe>
    {{- else }}
      {{- $width = "100%" }}
      {{- $height = "100%" }}
      {{- $paddingTop := $data.aspectRatio | div 1 | mul 100 | fmt.Printf "%2.2f%%" }}
      <div style="position: relative; padding-top: {{ $paddingTop }};">
        <iframe
          {{- if $allowFullScreen }} allowfullscreen {{- end }}
          width="{{ $width }}"
          height="{{ $height }}"
          frameborder="0"
          loading="{{ $loading }}"
          title="{{ $data.name }}"
          sandbox="{{ $sandbox }}"
          style="position: absolute; inset: 0px;"
          src="{{ $src }}"
        ></iframe>
      </div>
    {{- end }}
  {{- end }}
{{- else }}
  {{- errorf "The %q shortcode requires a %q argument. See %s" .Name "url" .Position }}
{{- end -}}

{{- define "_partials/inline/peertube/get-aspect-ratio.html" }}
  {{- $aspectRatio := 0 }}

  {{- $metadataUrl := "" }}
  {{- range .data.streamingPlaylists }}
    {{- range .files }}
      {{- if .hasVideo }}
        {{- $metadataUrl = .metadataUrl }}
        {{- break }}
      {{- end }}
    {{- end }}
    {{- if $metadataUrl }}
      {{- break }}
    {{- end }}
  {{- end }}

  {{- with $metadataUrl }}
    {{- with try (resources.GetRemote .) }}
      {{- with .Err }}
        {{- errorf "%s" . }}
      {{- else with .Value }}
        {{- with . | transform.Unmarshal }}
          {{- range .streams }}
            {{- if and .width .height  }}
              {{- $aspectRatio = div .width .height }}
              {{- break }}
            {{- end }}
          {{- end }}
          {{- if not $aspectRatio }}
            {{- errorf "The %q shortcode was unable to determine the aspect ratio. See %s" $.name $.position }}
          {{ end }}
        {{- end }}
      {{- else }}
        {{- errorf "The %q shortcode was unable to retrieve the metadata. See %s" $.name $.position }}
      {{- end }}
    {{- end }}
  {{- else }}
    {{- errorf "The %q shortcode was unable to determine the metadata URL. See %s" $.name $.position }}
  {{- end }}

  {{- return $aspectRatio }}
{{- end -}}
Last modified: