Skip to content

[Feature]: GTM possibility #227

Description

@HrjSnz

Problem

Hello,

first thanks for amazing work!

I analyzed with claude codebase and there is what it found about GTM. My question is - wil be somehow GTM available ? Thanks

Analysis: SEO, meta tags, GTM, and cookies on published pages

Short discussion note. Question: how far can an author / plugin reach, and where do we have to touch the core?
Context: the published output is intentionally clean static HTML with a strict CSP.

1. What we do natively (no plugin)

The publisher emits into <head> (src/core/publisher/render.ts):

  • <title> (from page title / seoTitle)
  • <meta name="description"> (settings.metaDescription)
  • <link rel="icon">, lang, charset, viewport
  • postType rows have seoTitle / seoDescription fields

Plus the architecture itself = static, fast, semantic HTML with no framework runtime → the best possible baseline for technical SEO.

Missing natively: og:*, Twitter cards, <link rel="canonical">, robots meta.

2. What a plugin can handle on its own

  • OG / canonical / robots metafrontend.assets[] with kind: "meta", placement: "head".
  • Custom client-side JS (calculator, tabs, dataLayer, self-hosted consent banner) → runtime script / script-inline (runs as 'self').
  • Calls to own / allowlisted APIsnetworkAllowedHostsconnect-src.

3. Key constraint: CSP script-src is locked to 'self'

The CSP relaxation available to plugins is hardcoded and limited (server/publish/frontendInjections.ts, relaxCspForPlan):

Directive What a plugin can add
script-src only 'self' (+ 'unsafe-inline' for inline) — no external host
connect-src 'self' + networkAllowedHosts (for fetch(), not for scripts)
style-src 'self' 'unsafe-inline'
img-src 'self' data: https:

There is no manifest field and no code path by which a plugin can add an external host (e.g. googletagmanager.com) to script-src. A remote <script src=…> declared by a plugin is additionally rejected at the manifest level (assets must be package-relative).

4. Consequence for GTM and third-party tracking

Thing Plugin alone enough?
OG / meta / canonical
Custom JS / self-hosted consent / dataLayer
First-party / server-side measurement (beacon to own endpoint)
Classic GTM (gtm.js from Google + injects vendor pixels)
Remote third-party pixels (FB, GA via remote script)

A plugin alone is not enough for purely client-side GTM. It needs an external script-src host, which no plugin can add.

5. Options for enabling GTM

  1. Core change — add Google hosts to the base CSP (src/core/publisher/cspPlan.ts). Works, but it is a change to the CMS core and a deliberate weakening of the security model for the whole site.
  2. Server-side / same-origin tagging — proxy GTM through your own domain / measure via a first-party endpoint. Stays plugin-only, but if the proxied GTM itself injects remote <script> tags from third parties, we hit script-src again → the cleanly viable variant is mainly server-side measurement.

6. Open questions for discussion

  • Do we want to support an author-facing "GTM ID / custom head scripts" field at all? It runs against the CSP philosophy.
  • If yes: add a controlled script-src host declaration to the manifest (permission-gated, visible in the install/consent UI) instead of a core hack?
  • Or hold the line and officially recommend server-side tagging as the only supported path?
  • Cookie consent (CMP): leave it to the author/plugin, or add a lightweight first-party consent primitive?

Sources: src/core/publisher/render.ts (head), server/publish/frontendInjections.ts (relaxCspForPlan), src/core/plugins/manifest.ts (networkAllowedHosts, frontend.assets), src/core/publisher/cspPlan.ts (base CSP).

Proposed solution

Allow GTM scripts ?

Alternatives considered

No response

Area

Plugins

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions