Last edited:

Looking for a sitemap with both filter or search functionality? Why not have both? Browse all posts from your blog in one place. You can filter by category or search by keyword to narrow down the results. New content is automatically added to the top of the list.

Adding an HTML Sitemap in Blogger

Step 1 — Create a New Page

  1. Log in to your Blogger Dashboard.
  2. Go to Pages in the left sidebar.
  3. Click + NEW PAGE.
  4. Give the page a title (e.g., "Sitemap" or "Archive").

Step 2 — Switch to HTML View

  1. In the page editor, click the Pencil icon (or "Compose view") in the top left corner.
  2. Select HTML view.
  3. Delete any existing code in the editor and paste the entire code (HTML, Script, and Style).
<div class="sm-topbar">
  <div class="sm-filters">
    <select id="sort">
      <option value="published">Latest Posts</option>
      <option value="updated">Latest Updated</option>
    </select>

    <select id="category">
      <option value="">All</option>
    </select>
  </div>

  <div class="sm-search-wrapper">
    <input class="sm-search" id="search" placeholder="Search posts..." type="search"/>
    <div class="sm-search-icon">
      <svg viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z" fill="currentColor"/></svg>
    </div>
  </div>
</div>

<div class="sm-count" id="count">Loading...</div>
<div class="sm-posts" id="posts"></div>

<script>//<![CDATA[
const blogURL = "https://YOURBLOGNAME.blogspot.com";
const maxLabels = 20;
const postsPerLoad = 150;

let nextPage = 1;
let currentLabel = "";
let currentSort = "published";
let searchQuery = "";

async function loadLabels() {
  const res = await fetch(blogURL + "/feeds/posts/default?alt=json&max-results=0");
  const data = await res.json();

  let labels = data.feed.category?.map(c => c.term) || [];
  labels = labels.slice(0, maxLabels);

  const select = document.getElementById("category");

  labels.forEach(label => {
    const opt = document.createElement("option");
    opt.value = label;
    opt.textContent = label;
    select.appendChild(opt);
  });
}

async function loadPosts(reset = false) {
  let url = blogURL + "/feeds/posts/default";

  if (currentLabel) url += "/-/" + currentLabel;

  url += `?alt=json&max-results=${postsPerLoad}&start-index=${(nextPage - 1) * postsPerLoad + 1}`;

  if (currentSort === "updated") {
    url += "&orderby=updated";
  }

  const res = await fetch(url);
  const data = await res.json();

  const container = document.getElementById("posts");

  if (reset) container.innerHTML = "";

  let entries = data.feed.entry || [];

if (searchQuery) {
  const query = searchQuery.toLowerCase();
  
  entries = entries.filter(e => {
    const title = e.title.$t.toLowerCase();
    
    const labels = e.category ? e.category.map(cat => cat.term.toLowerCase()) : [];
    
    const content = e.content ? e.content.$t.toLowerCase() : "";
    const summary = e.summary ? e.summary.$t.toLowerCase() : "";

    return title.includes(query) || 
           labels.some(l => l.includes(query)) || 
           content.includes(query) || 
           summary.includes(query);
  });
}

  document.getElementById("count").innerText =
    `${entries.length} posts found`;

  entries.forEach(entry => {
    const link = entry.link.find(l => l.rel === "alternate").href;

let thumb = "";
if (entry.media$thumbnail) {
    thumb = entry.media$thumbnail.url;
} else if (entry.content && entry.content.$t.includes("<img")) {
    const srcMatch = entry.content.$t.match(/src=["']([^"']+)["']/);
    thumb = srcMatch ? srcMatch[1] : "";
}

if (thumb !== "") {
    thumb = thumb.replace(/\/s[0-9]+(-c)?\//, "/s1600/");
} else {
    thumb = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTxYv-Ua7D6ImswxKjjbUDpy8JcZ6qZKuCrIA&s";
}

    let snippet = "";
if (entry.summary) {
    snippet = entry.summary.$t;
} else if (entry.content) {
    snippet = entry.content.$t.replace(/<[^>]*>?/gm, ''); 
}

snippet = snippet.substring(0, 250) + "...";

const date = new Date(entry.published.$t).toLocaleDateString();

const div = document.createElement("div");
div.className = "sm-post";

div.innerHTML = `
  <img alt="${entry.title.$t}" class="sm-thumb" src="${thumb}">
  <div class="sm-info">
    <div class="sm-title"><a aria-label="${entry.title.$t}" href="${link}" target="_self">${entry.title.$t}</a></div>
    <div class="sm-snippet" style="font-size: 13px; color: #666; margin-bottom: 4px;">${snippet}</div>
    <div class="sm-date">${date}</div>
  </div>
`;

    container.appendChild(div);
  });

  nextPage++;
}

document.getElementById("sort").onchange = function() {
  currentSort = this.value;
  nextPage = 1;
  loadPosts(true);
};

document.getElementById("category").onchange = function() {
  currentLabel = this.value;
  nextPage = 1;
  loadPosts(true);
};

document.getElementById("search").oninput = function() {
  searchQuery = this.value;
  nextPage = 1;
  loadPosts(true);
};

document.getElementById("posts").addEventListener("scroll", function() {
  const el = this;
  if (el.scrollTop + el.clientHeight >= el.scrollHeight - 50) {
    loadPosts();
  }
});

loadLabels();
loadPosts(true);
//]]></script>

<style>
:root{--sm-bg: #ffffff; --sm-text: #1e293b; --sm-card: #e8e8e8; --sm-accent: #4f46e5; --sm-border: #ccc;}
body.dark-mode{--sm-bg: #0f0f0f; --sm-text: #eee; --sm-card: #1a1a1a; --sm-accent: #818cf8; --sm-border: #282828;}
.sm-topbar{display: flex;gap: 10px;flex-wrap: wrap;}
.sm-topbar select,.sm-topbar input{padding: 8px;border-radius: 6px;border: 1px solid var(--sm-border);background: var(--sm-card);color: var(--sm-text);}
.sm-search{flex: 1;}
@media (max-width: 768px){.sm-topbar{flex-direction: column;}
.sm-filters{display: flex;gap: 10px;}
.sm-search{width: 100%;}
.sm-search-wrapper{width: 100%;}
;}
@media (max-width: 650px){.sm-snippet{display:none!important;}
.sm-title a{display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;overflow: hidden;text-overflow: ellipsis;line-height: 1.4;}
;}
.sm-count{padding: 10px;font-size: 14px;opacity: 0.8;}
.sm-posts{overflow-y: auto;}
.sm-post{display: flex;gap: 12px;margin-bottom: 10px;border-radius: 10px;}
.sm-thumb{width: 120px;height: 70px;flex-shrink: 0;border-radius: 6px;object-fit: cover;}
.sm-info{flex: 1;}
.sm-title{font-weight: bold;margin-bottom: 5px;}
.sm-date{font-size: 12px;opacity: 0.7;color: var(--sm-text);}
.sm-snippet{display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;overflow: hidden;text-overflow: ellipsis;line-height: 1.4;margin: 5px 0;}
  .sm-search-wrapper{position: relative; flex: 1; display: flex; align-items: center;}
.sm-search{width: 100%; padding-right: 35px !important;}
.sm-search-icon{position: absolute; right: 10px; width: 16px; height: 16px; color: var(--sm-text); opacity: 0.5; pointer-events: none; display: flex; align-items: center; justify-content: center;}
.sm-search-icon svg{width: 100%; height: 100%;}
.sm-search:focus + .sm-search-icon{opacity: 1; color: var(--sm-accent);}
.sm-search-icon{transition: all 0.2s ease;}
</style>

Step 3 — Save and Publish

  1. Click Publish (or "Update" if you already saved it).
  2. Check the live page to ensure the posts are loading.

What You Must Change

For the sitemap to work with your specific blog, you need to modify a few lines in the <script> section.

1. The Blog URL (Mandatory)

Find this line at the very beginning of the script:

const blogURL = "https://YOURBLOGNAME.blogspot.com";
Replace https://YOURBLOGNAME.blogspot.com with your actual blog address (e.g., https://omniotakuu.blogspot.com). Do not add a trailing slash (/) at the end.

2. Maximum Labels (Optional)

Find this line:

const maxLabels = 20;
This controls how many categories appear in the "All" dropdown menu. If you have many labels and want to show more, increase this number.

3. Posts Per Load (Optional)

const postsPerLoad = 150;
This is the number of posts fetched every time you scroll to the bottom. If your posts have very high-resolution images, you might want to lower this to 20 for faster loading.

4. Thumbnail Behavior (Optional)

You can change fallback image here:

thumb = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTxYv-Ua7D6ImswxKjjbUDpy8JcZ6qZKuCrIA&s";

5. Styling (Optional Customization)

You can customize colors in this section:

:root{
  --sm-bg: #ffffff;
  --sm-text: #1e293b;
  --sm-card: #e8e8e8;
  --sm-accent: #4f46e5;
}
body.dark-mode{
  --sm-bg: #0f0f0f;
  --sm-text: #eee;
}
Match this with your theme colors

Understanding the Features

  • Real-Time Search: The search bar filters titles, labels, and post content locally from the fetched results.
  • Infinite Scroll: As you scroll down the sm-posts container, it automatically triggers a request for the next "page" of posts.
  • Thumbnail Fallback: If a post doesn't have a "Featured Image," the script will automatically search the post body for the first <img> tag. If no image is found, it uses a default placeholder.
  • Dark Mode Ready: The CSS uses CSS Variables (:root). If your main blog theme uses a .dark-mode/.dark class on the <body>, the sitemap will automatically switch colors to match.
  • Mobile Friendly: This sitemap is fully responsive, hidden long snippets on small screens, and optimized titles for readability.
Because Blogger's JSON feed is restricted by CORS, this script works best when hosted directly on a Blogger page. If you try to run this on a different website to display Blogger posts, it may be blocked unless you use a proxy.

Result

Your sitemap will now:

  • Show all posts dynamically
  • Allow filtering by category
  • Support keyword search
  • Load more posts on scroll
  • Stay updated automatically

Tips

  • Add this page to your navigation menu
  • Name it:
    • “Sitemap”
    • “All Posts”
    • “Browse”

And that’s it! Adding this Advanced Searchable Sitemap to your Blogger site is a great way to improve content discovery, user engagement, and site navigation. Now your readers can find exactly what they are looking for in seconds, whether they are searching by keyword or filtering through your categories.