# How to Configure CSP Headers for Plausible Analytics in Hugo

> Learn how to configure CSP headers for Plausible Analytics in Hugo. Integrate the plausible_csp.html partial or add plausible_head.html to your templates for seamless tracking.

- Repository: [divinerites/plausible-hugo](https://github.com/divinerites/plausible-hugo)
- Tags: how-to-guide
- Published: 2026-02-28

---

**To configure CSP headers for Plausible-Hugo, include the [`plausible_csp.html`](https://github.com/divinerites/plausible-hugo/blob/main/plausible_csp.html) partial in your `script-src` and `connect-src` directives, or add [`plausible_head.html`](https://github.com/divinerites/plausible-hugo/blob/main/plausible_head.html) to your templates to display the required CSP snippet in HTML comments when `proxy_netlify` is disabled.**

The plausible-hugo theme provides automated helpers for Content Security Policy (CSP) headers when integrating Plausible Analytics into Hugo sites. When you configure CSP headers properly, you allow the Plausible tracking script to execute while maintaining strict security policies against cross-site scripting vulnerabilities.

## Understanding CSP Requirements for Plausible-Hugo

Content Security Policy headers restrict which external resources a browser can load. Since Plausible Analytics loads a JavaScript file from an external domain, you must explicitly permit this source in your CSP configuration. The plausible-hugo repository handles this through specialized partials located in `layouts/partials/`.

When `proxy_netlify` is set to `true`, the Plausible script is served from your own domain via Netlify's proxy, eliminating the need for additional CSP entries. However, when using the standard Plausible CDN or custom domains without proxying, you must declare the domain in your policy.

## Key Configuration Parameters

In your [`config.toml`](https://github.com/divinerites/plausible-hugo/blob/main/config.toml) under `[params.plausible]`, these parameters control CSP generation:

- **`proxy_netlify`**: Boolean that suppresses CSP warnings when `true` (script served from same origin)
- **`custom_js_domain`**: Custom domain hosting the Plausible JS file (e.g., `stats.example.com`)
- **`selfhosted_domain`**: Domain of self-hosted Plausible instance (defaults to `plausible.io`)

## Generating the CSP Source String

The [`plausible_csp.html`](https://github.com/divinerites/plausible-hugo/blob/main/plausible_csp.html) partial generates the exact string required for your CSP directives. Located at [`layouts/partials/plausible_csp.html`](https://github.com/divinerites/plausible-hugo/blob/main/layouts/partials/plausible_csp.html), this template constructs the value `'unsafe-inline' https://<domain>` where `<domain>` is resolved from `custom_js_domain` or `selfhosted_domain` parameters.

For a standard Plausible.io setup, this outputs:

```

'unsafe-inline' https://plausible.io

```

For custom domains, it adapts accordingly:

```

'unsafe-inline' https://stats.example.com

```

You must add this generated string to both your `script-src` and `connect-src` directives.

## Implementation Methods

### Method 1: Manual CSP Integration with HTML Comments

Add the [`plausible_head.html`](https://github.com/divinerites/plausible-hugo/blob/main/plausible_head.html) partial to your site's `<head>` section. This automatically includes [`plausible_head_csp.html`](https://github.com/divinerites/plausible-hugo/blob/main/plausible_head_csp.html), which prints an HTML comment reminding you of the exact CSP values needed:

```html
<head>
  {{ partial "plausible_head.html" . }}
</head>

```

When rendered, this produces a comment in your HTML source:

```html
<!-- If you are using Content-Security-Policy, do not forget to add this code to your CSP :
  script-src 'unsafe-inline' https://plausible.io
  connect-src 'unsafe-inline' https://plausible.io
  or just add the partial 'plausible_csp.html' to those 2 csp directives in your 'index.headers' file -->

```

### Method 2: Automated Netlify Headers

For Netlify deployments, create or edit `layouts/index.headers` and embed the CSP partial directly:

```headers
Content-Security-Policy: default-src 'self'; {{ partial "plausible_csp.html" . }}

```

During the Hugo build process, apply the partial to both directives to generate the complete policy:

```headers
Content-Security-Policy: default-src 'self'; script-src 'unsafe-inline' https://plausible.io; connect-src 'unsafe-inline' https://plausible.io

```

## Complete Configuration Example

First, configure your [`config.toml`](https://github.com/divinerites/plausible-hugo/blob/main/config.toml):

```toml
[params.plausible]
  enable = true
  domain = "example.com"
  proxy_netlify = false
  custom_js_domain = "stats.example.com"  # Optional

```

Then implement your headers file for Netlify:

```headers

# layouts/index.headers

Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: default-src 'self'; script-src {{ partial "plausible_csp.html" . }}; connect-src {{ partial "plausible_csp.html" . }}

```

Or manually add the output to your web server configuration:

```apache
Header set Content-Security-Policy "script-src 'unsafe-inline' https://stats.example.com; connect-src 'unsafe-inline' https://stats.example.com;"

```

## Summary

- The [`plausible_csp.html`](https://github.com/divinerites/plausible-hugo/blob/main/plausible_csp.html) partial at [`layouts/partials/plausible_csp.html`](https://github.com/divinerites/plausible-hugo/blob/main/layouts/partials/plausible_csp.html) generates the required CSP source string `'unsafe-inline' https://<domain>`
- You must add this string to both `script-src` and `connect-src` directives in your CSP
- When `proxy_netlify` is `true`, no CSP configuration is required due to same-origin serving
- For manual setups, [`plausible_head_csp.html`](https://github.com/divinerites/plausible-hugo/blob/main/plausible_head_csp.html) provides HTML comments with the exact values needed
- Netlify users can automate CSP injection using the `layouts/index.headers` file with Hugo partials

## Frequently Asked Questions

### Do I need to configure CSP headers when using Netlify proxy?

No. When you set `proxy_netlify = true` in your configuration, the Plausible script is served from your own domain via Netlify's rewrite proxy, making it same-origin. This eliminates the need for additional CSP entries since the script no longer loads from an external domain, and the warning partial is automatically suppressed.

### Why does the CSP require 'unsafe-inline' for Plausible?

The `'unsafe-inline'` value is required because the Plausible tracking script uses inline JavaScript execution patterns for event collection and tracking. The [`plausible_csp.html`](https://github.com/divinerites/plausible-hugo/blob/main/plausible_csp.html) partial includes this value automatically alongside the domain specification to ensure the analytics functionality works correctly under strict CSP policies that would otherwise block inline script execution.

### Can I use this with a self-hosted Plausible instance?

Yes. Set the `selfhosted_domain` parameter in your [`config.toml`](https://github.com/divinerites/plausible-hugo/blob/main/config.toml) to your instance domain (e.g., `analytics.myselfhosted.com`). The [`plausible_csp.html`](https://github.com/divinerites/plausible-hugo/blob/main/plausible_csp.html) partial will automatically generate the CSP string using your custom domain instead of the default `plausible.io`, allowing you to configure CSP headers for self-hosted deployments.

### How do I configure CSP headers on non-Netlify hosts?

For Apache or Nginx servers, include the [`plausible_head.html`](https://github.com/divinerites/plausible-hugo/blob/main/plausible_head.html) partial in your templates to reveal the exact CSP values in HTML comments, then copy the generated `'unsafe-inline' https://<domain>` string into your server's CSP configuration. Apply this string to both the `script-src` and `connect-src` directives in your `Content-Security-Policy` header.