diff --git a/app/Config/View.php b/app/Config/View.php
index 7225324cb8d2c07c292258d0a73adb1d6d86751a..c43985de570c139854d1f57b25e9f32c060c7011 100644
--- a/app/Config/View.php
+++ b/app/Config/View.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Config;
 
+use App\Views\Decorators\SiteHead;
 use CodeIgniter\Config\View as BaseView;
 use CodeIgniter\View\ViewDecoratorInterface;
 use ViewComponents\Decorator;
@@ -53,5 +54,5 @@ class View extends BaseView
      *
      * @var list<class-string<ViewDecoratorInterface>>
      */
-    public array $decorators = [Decorator::class];
+    public array $decorators = [Decorator::class, SiteHead::class];
 }
diff --git a/app/Helpers/rss_helper.php b/app/Helpers/rss_helper.php
index dc5e1cee45891a887f3bbede5c03dfb012354f67..bf7918ba940964c3f735b705d38e13baa6b63c4d 100644
--- a/app/Helpers/rss_helper.php
+++ b/app/Helpers/rss_helper.php
@@ -298,7 +298,7 @@ if (! function_exists('get_rss_feed')) {
         }
 
         // run plugins hook at the end
-        $plugins->setChannelTag($podcast, $channel);
+        $plugins->channelTag($podcast, $channel);
 
         foreach ($episodes as $episode) {
             if ($episode->is_premium && ! $subscription instanceof Subscription) {
@@ -460,7 +460,7 @@ if (! function_exists('get_rss_feed')) {
                 ], $item);
             }
 
-            $plugins->setItemTag($episode, $item);
+            $plugins->itemTag($episode, $item);
         }
 
         return $rss->asXML();
diff --git a/app/Views/Decorators/SiteHead.php b/app/Views/Decorators/SiteHead.php
new file mode 100644
index 0000000000000000000000000000000000000000..ff8e91a1b0dcb07eaefe353e3373dce34c8a49b2
--- /dev/null
+++ b/app/Views/Decorators/SiteHead.php
@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Views\Decorators;
+
+use CodeIgniter\View\ViewDecoratorInterface;
+
+class SiteHead implements ViewDecoratorInterface
+{
+    private static int $renderedCount = 0;
+
+    public static function decorate(string $html): string
+    {
+        if (url_is(config('Admin')->gateway . '*') || url_is(config('Install')->gateway)) {
+            return $html;
+        }
+
+        if (static::$renderedCount > 0) {
+            return $html;
+        }
+
+        ob_start(); // Start output buffering
+        // run hook to add tags to <head>
+        service('plugins')->siteHead();
+        $metaTags = ob_get_contents(); // Store buffer in variable
+        ob_end_clean();
+
+        if (str_contains($html, '</head>')) {
+            $html = str_replace('</head>', "\n\t{$metaTags}\n</head>", $html);
+            ++static::$renderedCount;
+        }
+
+        return $html;
+    }
+}
diff --git a/modules/Plugins/BasePlugin.php b/modules/Plugins/BasePlugin.php
index d73683c1d45ea0160996e8aec3e98e86020d057e..973dc31eeb61b0ebdf6876f639746366a1ec9b71 100644
--- a/modules/Plugins/BasePlugin.php
+++ b/modules/Plugins/BasePlugin.php
@@ -59,11 +59,15 @@ abstract class BasePlugin implements PluginInterface
         // TODO: setup navigation and views?
     }
 
-    public function setChannelTag(Podcast $podcast, SimpleRSSElement $channel): void
+    public function channelTag(Podcast $podcast, SimpleRSSElement $channel): void
     {
     }
 
-    public function setItemTag(Episode $episode, SimpleRSSElement $item): void
+    public function itemTag(Episode $episode, SimpleRSSElement $item): void
+    {
+    }
+
+    public function siteHead(): void
     {
     }
 
diff --git a/modules/Plugins/PluginInterface.php b/modules/Plugins/PluginInterface.php
index 7c46f18b57cbdb7f02f9b8432d3580550e63835e..229ff29084395a0f5845b8740fba5a4c5fbbdd5b 100644
--- a/modules/Plugins/PluginInterface.php
+++ b/modules/Plugins/PluginInterface.php
@@ -10,7 +10,9 @@ use App\Libraries\SimpleRSSElement;
 
 interface PluginInterface
 {
-    public function setChannelTag(Podcast $podcast, SimpleRSSElement $channel): void;
+    public function channelTag(Podcast $podcast, SimpleRSSElement $channel): void;
 
-    public function setItemTag(Episode $episode, SimpleRSSElement $item): void;
+    public function itemTag(Episode $episode, SimpleRSSElement $item): void;
+
+    public function siteHead(): void;
 }
diff --git a/modules/Plugins/Plugins.php b/modules/Plugins/Plugins.php
index 48c6a42a70461130d5ce03d8fbe0444e3663058a..0995cc2a6c5a0beeb124bc038425351ec65c8d97 100644
--- a/modules/Plugins/Plugins.php
+++ b/modules/Plugins/Plugins.php
@@ -9,8 +9,9 @@ use App\Entities\Podcast;
 use App\Libraries\SimpleRSSElement;
 
 /**
- * @method void setChannelTag(Podcast $podcast, SimpleRSSElement $channel)
- * @method void setItemTag(Episode $episode, SimpleRSSElement $item)
+ * @method void channelTag(Podcast $podcast, SimpleRSSElement $channel)
+ * @method void itemTag(Episode $episode, SimpleRSSElement $item)
+ * @method string siteHead()
  */
 class Plugins
 {
@@ -19,7 +20,7 @@ class Plugins
     /**
      * @var list<string>
      */
-    protected const HOOKS = ['setChannelTag', 'setItemTag'];
+    protected const HOOKS = ['channelTag', 'itemTag', 'siteHead'];
 
     /**
      * @var array<BasePlugin>