# How to Enable Hash-Based Routing in Plausible-Hugo

> Enable hash based routing in Plausible Hugo by setting hash_based_routing true in your config. Track URL fragments in SPAs easily.

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

---

**Set `hash_based_routing = true` in your Hugo site's `[params.plausible]` configuration to append `.hash` to the Plausible script URL, enabling tracking of URL fragments in single-page applications.**

The Plausible-Hugo theme provides native support for hash-based routing, a critical feature for single-page applications (SPAs) and client-side routing where URL fragments (the portion after `#`) must be tracked. When enabled, the theme automatically modifies the tracking script's filename to include the `.hash` suffix, instructing Plausible's backend to capture and record these fragments alongside standard page-view data.

## What Is Hash-Based Routing?

Hash-based routing allows Plausible Analytics to capture URL fragments—everything following the `#` symbol in a URL. In standard web analytics, browsers do not send URL fragments to the server, so traditional tracking scripts miss this navigation data. By loading [`script.hash.js`](https://github.com/divinerites/plausible-hugo/blob/main/script.hash.js) instead of [`script.js`](https://github.com/divinerites/plausible-hugo/blob/main/script.js), Plausible's tracker parses the fragment and includes it in the page-view payload, ensuring complete path tracking for SPAs built with frameworks like React, Vue, or Alpine.js.

## Enabling Hash-Based Routing in Your Hugo Configuration

### Step 1: Configure the Site Parameter

Open your Hugo configuration file (typically [`config.toml`](https://github.com/divinerites/plausible-hugo/blob/main/config.toml) at the project root) and locate the `[params.plausible]` table. Add the `hash_based_routing` parameter and set it to `true`:

```toml
[params.plausible]
domain = "example.com"
enable = true
hash_based_routing = true

```

According to the repository's default configuration in [`config.toml`](https://github.com/divinerites/plausible-hugo/blob/main/config.toml), this parameter exists but is commented out by default, allowing you to uncomment it when needed.

### Step 2: Rebuild and Verify

Run `hugo` or `hugo server` to rebuild your site. The [`layouts/partials/plausible_head.html`](https://github.com/divinerites/plausible-hugo/blob/main/layouts/partials/plausible_head.html) partial will detect the enabled parameter and render the script tag with the `.hash` suffix:

```html
<script defer data-domain="example.com"
        src="https://plausible.io/js/script.hash.js"></script>

```

To confirm hash-based routing is active, navigate to a URL containing a fragment (such as `/#/dashboard`) and check your Plausible dashboard. The page-view entry should display the full path including the fragment, rather than just `/`.

## How the Hash-Based Routing Implementation Works

The logic resides in [`layouts/partials/plausible_head.html`](https://github.com/divinerites/plausible-hugo/blob/main/layouts/partials/plausible_head.html), where the theme constructs the script URL dynamically. When `site.Params.plausible.hash_based_routing` evaluates to `true`, the partial appends the string `.hash` to the filename variable:

```go-template
{{- $hash := "" }}
{{- if site.Params.plausible.hash_based_routing }}
{{- $hash = ".hash" }}
{{- end }}
{{- $pio_script = printf "%s%s%s%s" $pio_script $downloads $outbound $hash }}

```

This conditional assignment ensures that `$hash` contains either an empty string (default) or `.hash` (when enabled). The final `printf` statement concatenates this suffix onto the base script name, transforming [`script.js`](https://github.com/divinerites/plausible-hugo/blob/main/script.js) into [`script.hash.js`](https://github.com/divinerites/plausible-hugo/blob/main/script.hash.js) before injection into the HTML head.

## Configuration Examples

### Standard Plausible.io Domain

For sites using the default Plausible analytics domain:

```toml
[params.plausible]
domain = "your-site.com"
enable = true
hash_based_routing = true

```

Generates:

```html
<script defer data-domain="your-site.com"
        src="https://plausible.io/js/script.hash.js"></script>

```

### Custom JavaScript Domain

When using a custom CDN or self-hosted Plausible instance via the `custom_js_domain` parameter:

```toml
[params.plausible]
domain = "your-site.com"
custom_js_domain = "stats.your-cdn.com"
enable = true
hash_based_routing = true

```

This configuration produces [`index.hash.js`](https://github.com/divinerites/plausible-hugo/blob/main/index.hash.js) instead of [`script.hash.js`](https://github.com/divinerites/plausible-hugo/blob/main/script.hash.js), as implemented in the source logic:

```html
<script defer data-domain="your-site.com"
        src="https://stats.your-cdn.com/misc/js/index.hash.js"></script>

```

## Summary

- **Hash-based routing** captures URL fragments for single-page applications by loading a specialized Plausible script variant.
- **Enable the feature** by setting `hash_based_routing = true` in the `[params.plausible]` section of [`config.toml`](https://github.com/divinerites/plausible-hugo/blob/main/config.toml).
- **The partial [`layouts/partials/plausible_head.html`](https://github.com/divinerites/plausible-hugo/blob/main/layouts/partials/plausible_head.html)** dynamically appends `.hash` to the script filename when the parameter is enabled.
- **Resulting script URLs** become [`script.hash.js`](https://github.com/divinerites/plausible-hugo/blob/main/script.hash.js) or [`index.hash.js`](https://github.com/divinerites/plausible-hugo/blob/main/index.hash.js), depending on whether you use the standard domain or a custom JavaScript domain.
- **Verification** requires checking that Plausible records the full URL including the `#` fragment in your analytics dashboard.

## Frequently Asked Questions

### Does enabling hash-based routing affect performance?

No, enabling hash-based routing does not impact site performance or loading times. The only difference is the filename of the fetched script ([`script.hash.js`](https://github.com/divinerites/plausible-hugo/blob/main/script.hash.js) versus [`script.js`](https://github.com/divinerites/plausible-hugo/blob/main/script.js)). The file size and execution behavior remain identical; Plausible's backend simply processes the URL fragment data when the `.hash` suffix is present.

### Can I use hash-based routing with a self-hosted Plausible instance?

Yes, hash-based routing works with both Plausible.io and self-hosted instances. When using a custom domain via the `custom_js_domain` parameter, the theme automatically generates [`index.hash.js`](https://github.com/divinerites/plausible-hugo/blob/main/index.hash.js) instead of [`script.hash.js`](https://github.com/divinerites/plausible-hugo/blob/main/script.hash.js), ensuring compatibility with self-hosted deployments that use the `misc/js/` path structure.

### What happens if I enable hash-based routing on a traditional multi-page site?

Enabling the feature on a traditional site causes no harm or data loss. The `.hash` script variant will simply record fragment data when present (such as anchor links like `#section-2`) while continuing to track standard page views normally. If your site does not use URL fragments for routing, the analytics data remains unchanged compared to the standard script.

### Where is the hash-based routing logic implemented in the source code?

The implementation resides in [`layouts/partials/plausible_head.html`](https://github.com/divinerites/plausible-hugo/blob/main/layouts/partials/plausible_head.html) within the divinerites/plausible-hugo repository. Specifically, the conditional logic checks `site.Params.plausible.hash_based_routing` and sets the `$hash` variable to `.hash` when enabled, which is then concatenated into the final script URL via the `printf` function.