Display Plausible Statistics in Your 11ty Blog

How to display popular and trending blog posts using Plausible Analytics and 11ty. Follow this step-by-step guide for seamless API integration.

# Introduction

Highlighting your most popular and trending posts is a great way to engage readers and showcase your best content. In this guide, I’ll walk you through how I implemented this feature for my blog using the privacy-friendly Plausible Analytics.

# Table of Contents

  1. Why Use Plausible Analytics?
  2. Steps to Display Popular and Trending Posts
  3. Limitations

# Why Use Plausible Analytics?

  • Data Privacy: Unlike other analytics platforms, Plausible values privacy, ensuring compliance with GDPR, CCPA, and other regulations.
  • API-Driven: Its developer-friendly API provides easy access to site metrics such as page views.
  • Lightweight Integration: Ideal for static site generators like Eleventy, allowing minimal overhead.

I have been using Plausible since 2020 so I have 4 years of analytics in one place.

# Calling the Plausible API

To fetch statistics from Plausible, you'll need:

  1. API Key: Obtain this from your API Settings page.
  2. Site ID: This corresponds to the domain name you registered with Plausible (e.g., jjude.com).

I opted to use the 11ty Fetch plugin to cache the results. Below is the function to fetch stats from Plausible (plausible.mjs file):

async function fetchPlausibleData(params) {
    const PLAUSIBLE_API_KEY = process.env.PLAUSIBLE_API_KEY;
    const SITE_ID = process.env.PLAUSIBLE_SITE_ID;
    const PLAUSIBLE_API = 'https://plausible.io/api/v2/query';
    const options = {
        fetchOptions: {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${PLAUSIBLE_API_KEY}`,
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ ...params, site_id: SITE_ID })
        }
    };
    try {
        return await EleventyFetch(`${PLAUSIBLE_API}`, options);
    } catch (error) {
        console.error(`Error fetching data: ${error.message}`);
        return { results: [] };
    }
}

Use environment variables to keep your API key and site ID secure. Add these to your .env file:

PLAUSIBLE_API_KEY=
PLAUSIBLE_SITE_ID=

You can fetch the top 10 posts with the following parameters:

const allTimeData = await fetchPlausibleData({
    metrics: ["pageviews"],
    dimensions: ["event:page"],
    date_range: "all",
    order_by: [["pageviews", "desc"]],
    pagination: { "limit": 10 }
});

# Creating an 11ty Collection

To dynamically link post slugs to titles, we can create an 11ty Collection. This allows us to loop through all posts, filter the results, and maintain a mapping of slugs to titles. Add the following to your plausibleStats collection in .eleventy.js:

eleventyConfig.addCollection("plausibleStats", async (collectionApi) => {
    let slugToFileMap = {};
    // Map slugs to post titles
    collectionApi.getAll().forEach(item => {
        const slug = item.data.slug || slugifyFilter(item.fileSlug);
        slugToFileMap[slug] = item.data.title || slug;
    });
    const data = await getPlausibleStats(slugToFileMap); // Fetch stats
    return data;
});

# Mapping Slugs to Titles

Since the Plausible API provides URLs but not titles, a custom mapping is required. For example:

  • /blog/intro-to-cloud → "Introduction to Cloud"
  • /travel/beach-trip → "Beach Trip Highlights"

Use the following utility function to transform results (in plausible.mjs):

const transformResults = (results) => {
    return results.map(result => {
        const pagePath = result.dimensions[0];
        // get the last segment
        const slug = pagePath.split('/').filter(Boolean).pop();
        return {
            title: slugToFileMap[slug] || slug,
            slug: pagePath,
            pageviews: result.metrics[0]
        };
    }).filter(item => item.title);
};

let allTime = transformResults(allTimeData.results);

If you want to fetch other stats like for past 7 days, you can do that too. Here I've shown only for allTime popular posts.

# Displaying Posts with Templates

To render the fetched data on your blog, insert the statistics into your Nunjucks template:

<ul>
    {% for post in collections.plausibleStats.allTime | limit(5) %}
        <li>
            <a href="{{ post.slug }}">
                <strong>{{ post.title }}</strong> ({{ post.pageviews }} views)
            </a>
        </li>
    {% endfor %}
</ul>

This will display the top 5 posts with clickable links and their respective page views.

# Limitations

  • Build-Time Updates: The data fetch happens only during the build process, so statistics won’t refresh in real-time.
  • Error Handling: I've not shown error handling in these blocks of code. Handle errors appropriately.
Published On:
Under: #11ty , #code