How to Use Variable Custom Goals in Plausible-Hugo: Complete Implementation Guide
Track custom events in Plausible Analytics using dynamic, data-driven goal names by leveraging Hugo's templating system and the plausible_js.html partial.
The divinerites/plausible-hugo module provides a lightweight integration for Plausible Analytics in Hugo sites. Beyond basic pageview tracking, it supports variable custom goals—dynamic event names generated from data files, page parameters, or site variables—enabling scalable analytics for large sites without hardcoding JavaScript for every individual action.
Understanding the Architecture
The integration relies on three core components defined in layouts/partials/plausible_head.html:
plausible_head.html– The engine that constructs the Plausible script URL, initializes thewindow.plausiblequeue, and conditionally injects custom goal logic.plausible_js.html– A user-created partial where you define JavaScript helper functions. This is rendered as raw JavaScript (| safeJS) insideplausible_head.html, allowing full use of Hugo templating to generate dynamic function names and calls.- Front-matter
plausible_custom_goal– A declarative key that triggers an automatic goal event when a specific page loads.
Both mechanisms respect the global site.Params.plausible.enable setting and respect user privacy via the plausible_do_not_track page parameter.
Method 1: JavaScript Helper Functions
For one-off custom events triggered by user interactions, create reusable JavaScript functions.
Creating the Helper Partial
Create a file at layouts/partials/plausible_js.html in your site root:
// layouts/partials/plausible_js.html
function ClickOnTelephoneNumber() {
plausible('ClickOnTelephoneNumber');
}
This partial is automatically detected by plausible_head.html and injected into the page's <script> block, making the ClickOnTelephoneNumber function available globally.
Invoking Goals in Templates
Reference the function in any Hugo template using an onclick handler:
<a href="tel:+331234567890"
onclick="ClickOnTelephoneNumber()">
+33 1 23 45 67 90
</a>
When a visitor clicks the link, the helper function fires the plausible() call with the specified goal name.
Method 2: Automatic Page-Level Goals
To track a goal immediately when a page loads—useful for "thank you" pages or specific landing pages—use front-matter configuration.
Add the plausible_custom_goal key to any content file:
---
title: "Contact Confirmation"
plausible_custom_goal: "ContactFormSubmitted"
---
During the build, plausible_head.html checks for this key. If present, it renders:
<script>
plausible('ContactFormSubmitted');
</script>
This executes immediately after the Plausible script initializes, capturing the event without requiring user interaction.
Method 3: Dynamic Variable Custom Goals from Data
The most powerful feature is generating goal names dynamically from Hugo data files or site parameters. This enables tracking hundreds of unique events—such as clicks on different phone numbers or downloads of specific files—without manually writing JavaScript for each.
Setting Up the Data Source
Create a data file at /data/locations.yml:
locations:
- name: "Paris Office"
plausible_goal: "ParisPhone"
phone: "+33 1 23 45 67 89"
- name: "London Office"
plausible_goal: "LondonPhone"
phone: "+44 20 7946 0958"
Generating Functions Dynamically
In layouts/partials/plausible_js.html, loop through the data to create unique functions:
{{- $data := index .Site.Data .Site.Language.Lang }}
{{- if $data.locations }}
{{- range $data.locations.locations }}
function {{ .plausible_goal | safeJS }}Click() {
plausible('{{ .plausible_goal | safeJS }}');
}
{{- end }}
{{- end }}
This generates JavaScript functions named ParisPhoneClick() and LondonPhoneClick() at build time.
In your template, invoke these dynamically:
{{- $data := index .Site.Data .Site.Language.Lang }}
{{- if $data.locations }}
{{- range $data.locations.locations }}
{{ $phone_clean := replaceRE "(\\s)" "" .phone }}
<a href="tel:{{ $phone_clean }}"
onclick="{{ .plausible_goal | safeJS }}Click()">
{{ .phone }}
</a>
{{- end }}
{{- end }}
Each phone link now triggers a distinct Plausible goal based on the data file, enabling granular analytics without code duplication.
Integration with Other Tracking Features
Variable custom goals work alongside Plausible's built-in extensions. Enable additional tracking in your config.toml:
[params.plausible]
enable = true
domain = "example.com"
outbound_link = true
file_downloads = true
plausible_head.html automatically appends .outbound-links and .file-downloads to the script URL when these flags are active. Your custom goals will fire alongside these automatic events without conflict.
Summary
- JavaScript Helpers: Create
layouts/partials/plausible_js.htmlto define reusableonclickfunctions for interactive events. - Page-Level Goals: Use the
plausible_custom_goalfront-matter key to fire goals automatically when a page loads. - Variable Goals: Leverage Hugo's
rangeloops and data files inplausible_js.htmlto generate dynamic goal names and functions at build time. - Conditional Loading: All goal mechanisms respect the global
enableflag and theplausible_do_not_trackpage parameter.
Frequently Asked Questions
How do I disable tracking on specific pages while keeping custom goals active elsewhere?
Add plausible_do_not_track: true to the front-matter of any page. The plausible_head.html partial checks for this parameter and skips injecting the Plausible script and any custom goal logic for that specific page.
Can I use Hugo variables inside the plausible_js.html partial?
Yes. The partial is rendered with | safeJS inside plausible_head.html, which means you can use any Hugo templating syntax—such as {{ .Params.custom_goal }}, {{ .Site.Data }}, or range loops—to dynamically generate JavaScript function names and goal identifiers at build time.
What happens if I define both a front-matter goal and a JavaScript helper on the same page?
Both will execute. The front-matter plausible_custom_goal fires immediately when the page loads, while JavaScript helpers fire when the specific event (e.g., onclick) occurs. Ensure the goal names are distinct to avoid duplicate events in your Plausible dashboard.
Is there a limit to how many variable custom goals I can generate from a data file?
There is no hard limit imposed by the plausible-hugo module. However, since all goal functions are rendered into the HTML at build time, generating thousands of goals could increase page weight. For high-volume scenarios, consider using a single dynamic goal with custom properties (if supported by your Plausible version) or grouping similar actions under broader goal categories.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →