Posts

Showing posts with the label tag16

build a user feedback loop in jekyll without backend

Why Feedback Matters in Static Knowledge Bases

Most websites evolve based on user behavior and direct feedback. But when you’re running a static site using Jekyll on GitHub Pages, collecting feedback becomes more complex — no server-side logic, no database. The good news? With some creative use of JavaScript and browser storage, you can still capture useful signals and build a feedback loop.

Use Cases for Static Feedback

In the context of a knowledge base, feedback helps answer:

  • Was this article helpful?
  • Did users find the content they were searching for?
  • Which topics should be expanded or improved?

Step 1: Build a Simple Voting Interface

Let’s add a feedback box to every article using a simple “Yes/No” prompt:

<div class="feedback-box">
  <p>Was this article helpful?</p>
  <button onclick="submitFeedback(true)">Yes</button>
  <button onclick="submitFeedback(false)">No</button>
</div>

Step 2: Store Feedback Locally

Since you can’t send feedback to a backend, store it locally per post using the page URL as the key.

function submitFeedback(value) {
  const key = window.location.pathname;
  const feedbackData = JSON.parse(localStorage.getItem('feedbackData')) || {};
  feedbackData[key] = value;
  localStorage.setItem('feedbackData', JSON.stringify(feedbackData));

  document.querySelector('.feedback-box').innerHTML = 'Thanks for your feedback!';
}

Step 3: Track and Visualize Aggregate Feedback

Over time, you may want to show users what they’ve voted on, or create a dashboard view for yourself. This is possible using session aggregation.

function getFeedbackSummary() {
  const data = JSON.parse(localStorage.getItem('feedbackData')) || {};
  const total = Object.keys(data).length;
  const positive = Object.values(data).filter(x => x).length;
  const negative = total - positive;

  return { total, positive, negative };
}

Then you could render a simple display somewhere in the footer or sidebar:

const summary = getFeedbackSummary();
document.getElementById('summary-box').innerText =
  `You’ve rated ${summary.total} pages. Helpful: ${summary.positive}, Needs improvement: ${summary.negative}`;

Step 4: Build a Personalized “Improvement List”

Help users help themselves. If they marked an article unhelpful, suggest better ones next time.

const feedbackData = JSON.parse(localStorage.getItem('feedbackData')) || {};

const unhelpfulPages = Object.keys(feedbackData).filter(key => !feedbackData[key]);

const suggestions = allPosts.filter(post => !unhelpfulPages.includes(post.url));

renderSuggestions(suggestions.slice(0, 3));

This avoids showing previously disliked content, improving personalization.

Step 5: Use Feedback to Trigger Conditional Prompts

Feedback doesn’t need to be passive. Trigger follow-up questions based on answers:

function submitFeedback(value) {
  const key = window.location.pathname;
  const feedbackData = JSON.parse(localStorage.getItem('feedbackData')) || {};
  feedbackData[key] = value;
  localStorage.setItem('feedbackData', JSON.stringify(feedbackData));

  if (!value) {
    const box = document.querySelector('.feedback-box');
    box.innerHTML = '<p>What could be improved?</p><input id="feedback-detail"><button onclick="saveDetail()">Send</button>';
  } else {
    document.querySelector('.feedback-box').innerHTML = 'Thanks!';
  }
}

function saveDetail() {
  const detail = document.getElementById('feedback-detail').value;
  sessionStorage.setItem('lastFeedbackDetail', detail);
  document.querySelector('.feedback-box').innerHTML = 'Thanks for your input!';
}

Step 6: Respect Privacy and Offer Transparency

Since everything is stored locally, privacy is preserved. Still, users should know how it works and be given a reset option:

<button onclick="localStorage.clear(); alert('Your feedback history has been cleared.')">Clear Feedback</button>

Step 7: Bonus — Export Feedback for Review

If you're the site owner, you might want to inspect user feedback by asking them to export and send it:

<button onclick="downloadFeedback()">Export Feedback</button>

function downloadFeedback() {
  const data = localStorage.getItem('feedbackData');
  const blob = new Blob([data], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'feedback.json';
  a.click();
  URL.revokeObjectURL(url);
}

This gives power users the ability to share insights manually without compromising the site's static nature.

Conclusion

Even without a backend, it’s entirely possible to implement a basic yet useful feedback loop in Jekyll using only client-side tools. By gathering, storing, and responding to local feedback, you enhance the user experience and create the impression of a responsive, evolving knowledge base — all while staying within the boundaries of GitHub Pages hosting.

In the next article, we’ll dive into making your search and feedback mechanisms accessible and inclusive for all users.