November 30, 2025 11 min read
In Part 1 of this series, we covered the foundational optimizations for Jekyll sites on GitHub Pages. Part 2 dives into advanced analytics, performance monitoring, and the lessons learned from running a technical blog with 100+ posts.
Advanced Analytics and Monitoring
Google Analytics 4 Integration
Beyond basic page tracking, GA4 provides valuable insights for technical blogs:
<!-- Google tag (gtag.js) -->
<script async src= "https://www.googletagmanager.com/gtag/js?id=G-F90DVB199P" ></script>
<script>
window . dataLayer = window . dataLayer || [];
function gtag (){ dataLayer . push ( arguments );}
gtag ( ' js ' , new Date ());
gtag ( ' config ' , ' G-F90DVB199P ' , {
// Enhanced measurement for technical content
enhanced_measurement_settings : {
scrolls_enabled : true ,
outbound_clicks_enabled : true ,
site_search_enabled : true ,
video_engagement_enabled : true ,
file_downloads_enabled : true
}
});
</script>
Custom Event Tracking
Track specific interactions valuable for technical content:
// Track code copy button usage
document . addEventListener ( ' click ' , function ( e ) {
if ( e . target . classList . contains ( ' copy-button ' )) {
gtag ( ' event ' , ' code_copy ' , {
event_category : ' engagement ' ,
event_label : ' code_snippet_copied '
});
}
});
// Track external link clicks
document . addEventListener ( ' click ' , function ( e ) {
if ( e . target . tagName === ' A ' && e . target . hostname !== window . location . hostname ) {
gtag ( ' event ' , ' click ' , {
event_category : ' outbound ' ,
event_label : e . target . href ,
transport_type : ' beacon '
});
}
});
Key metrics to track for technical blogs:
// Core Web Vitals tracking
new PerformanceObserver (( entryList ) => {
for ( const entry of entryList . getEntries ()) {
if ( entry . entryType === ' largest-contentful-paint ' ) {
gtag ( ' event ' , ' web_vitals ' , {
event_category : ' performance ' ,
event_label : ' LCP ' ,
value : Math . round ( entry . startTime )
});
}
}
}). observe ({ entryTypes : [ ' largest-contentful-paint ' ]});
// Track page load performance
window . addEventListener ( ' load ' , function () {
const loadTime = performance . timing . loadEventEnd - performance . timing . navigationStart ;
gtag ( ' event ' , ' page_load_time ' , {
event_category : ' performance ' ,
value : Math . round ( loadTime )
});
});
Remaining Optimization Priorities
Based on analytics data and user feedback, here are the high-impact optimizations still on my roadmap:
High Priority Enhancements
1. Dark/Light Theme Toggle
User preference support with system detection:
// Theme toggle implementation
const themeToggle = document . getElementById ( ' theme-toggle ' );
const prefersDark = window . matchMedia ( ' (prefers-color-scheme: dark) ' );
function setTheme ( theme ) {
document . documentElement . setAttribute ( ' data-theme ' , theme );
localStorage . setItem ( ' theme ' , theme );
gtag ( ' event ' , ' theme_change ' , {
event_category : ' user_preference ' ,
event_label : theme
});
}
// Initialize theme
const savedTheme = localStorage . getItem ( ' theme ' ) ||
( prefersDark . matches ? ' dark ' : ' light ' );
setTheme ( savedTheme );
2. Site Search Implementation
Google Custom Search integration for 100+ posts:
<div class= "search-container" >
<script async src= "https://cse.google.com/cse.js?cx=YOUR_SEARCH_ENGINE_ID" ></script>
<div class= "gcse-search" ></div>
</div>
3. Reading Progress Indicator
Visual feedback for long technical articles:
window . addEventListener ( ' scroll ' , function () {
const winScroll = document . body . scrollTop || document . documentElement . scrollTop ;
const height = document . documentElement . scrollHeight - document . documentElement . clientHeight ;
const scrolled = ( winScroll / height ) * 100 ;
document . getElementById ( ' progress-bar ' ). style . width = scrolled + ' % ' ;
});
Medium Priority Features
1. Breadcrumb Navigation
Especially important for categorized technical content:
<nav class="breadcrumb">
<a href="/">Home</a>
{% if page . categories %}
{% for category in page . categories %}
<span class="separator">›</span>
<a href="/categories/{{ category | slugify }} /">{{ category | capitalize }} </a>
{% endfor %}
{% endif %}
<span class="separator">›</span>
<span class="current">{{ page . title }} </span>
</nav>
Increase content distribution:
<div class= "share-buttons" >
<a href= "https://twitter.com/intent/tweet?url={{ site.url }}{{ page.url }}&text={{ page.title }}"
target= "_blank" rel= "noopener" >
Share on Twitter
</a>
<a href= "https://www.linkedin.com/sharing/share-offsite/?url={{ site.url }}{{ page.url }}"
target= "_blank" rel= "noopener" >
Share on LinkedIn
</a>
</div>
3. Cookie Consent Banner
GDPR compliance for international readers:
function showCookieConsent () {
const consent = localStorage . getItem ( ' cookie-consent ' );
if ( ! consent ) {
document . getElementById ( ' cookie-banner ' ). style . display = ' block ' ;
}
}
function acceptCookies () {
localStorage . setItem ( ' cookie-consent ' , ' accepted ' );
document . getElementById ( ' cookie-banner ' ). style . display = ' none ' ;
// Initialize analytics after consent
initializeAnalytics ();
}
Technical Improvements
1. Custom Error Pages
Enhanced 404/500 pages with search functionality:
<!-- 404.html -->
---
layout: default
permalink: /404.html
---
<div class= "error-page" >
<h1> Page Not Found</h1>
<p> The page you're looking for doesn't exist. Try searching:</p>
<div class= "gcse-search" ></div>
<h3> Popular Articles</h3>
{% for post in site.posts limit:5 %}
<article>
<a href= "{{ post.url }}" > {{ post.title }}</a>
<p> {{ post.excerpt | strip_html | truncate: 100 }}</p>
</article>
{% endfor %}
</div>
2. Lazy Loading Implementation
Images load on demand to improve initial page load:
// Intersection Observer for lazy loading
const imageObserver = new IntersectionObserver (( entries , observer ) => {
entries . forEach ( entry => {
if ( entry . isIntersecting ) {
const img = entry . target ;
img . src = img . dataset . src ;
img . classList . remove ( ' lazy ' );
observer . unobserve ( img );
}
});
});
document . querySelectorAll ( ' img[data-src] ' ). forEach ( img => {
imageObserver . observe ( img );
});
3. Responsive Image Sets
Multiple image sizes for different devices:
<picture>
<source media= "(max-width: 480px)" srcset= "/assets/images/image-small.webp" >
<source media= "(max-width: 768px)" srcset= "/assets/images/image-medium.webp" >
<source media= "(min-width: 769px)" srcset= "/assets/images/image-large.webp" >
<img src= "/assets/images/image-large.jpg" alt= "Description" loading= "lazy" >
</picture>
Before and After Metrics
Implementing the optimizations from both parts has yielded measurable improvements:
Page Load Performance
Initial load time : Reduced from 3.2s to 1.6s (50% improvement)
Time to Interactive : Improved from 4.1s to 2.1s (49% improvement)
First Contentful Paint : Reduced from 1.8s to 0.9s (50% improvement)
Core Web Vitals
Largest Contentful Paint : Improved from 2.8s to 1.4s
First Input Delay : Reduced from 120ms to 45ms
Cumulative Layout Shift : Decreased from 0.15 to 0.05
User Engagement
Session duration : Increased by 30% (better navigation and related posts)
Pages per session : Improved by 25% (better content organization)
Bounce rate : Reduced by 35% (faster loading, better UX)
Mobile PageSpeed score : Improved from 65 to 87
Mobile usability : No issues detected
Mobile traffic : Increased by 40% (better mobile experience)
Analytics Insights
Key findings from Google Analytics after optimizations:
Content Performance
Technical tutorials have 45% longer session duration
Code-heavy posts show 60% higher engagement with copy buttons
Series articles (like this two-part post) have 25% better retention
Traffic Sources
Organic search : 65% of traffic (improved SEO working)
Direct traffic : 20% (returning readers, good sign)
Social media : 10% (room for improvement)
Referrals : 5% (technical community links)
Popular Content Categories
Proxmox/Ceph articles : Highest engagement and sharing
Dell Wyse 3040 series : Strong search traffic
Jekyll/GitHub Pages : Good for developer audience
Networking tutorials : Consistent performance
Lessons Learned from 100+ Posts
What Worked Exceptionally Well
1. Consistent Technical Focus
Focusing on homelab and infrastructure topics created a loyal readership. Technical depth matters more than broad appeal for this audience.
2. Series-Based Content
Multi-part articles (like this one) perform better than single long posts:
Better reader retention
Higher return visitor rates
More social sharing
Better SEO for related keywords
3. Real-World Examples
Posts with actual command outputs and screenshots perform 40% better than theoretical content.
4. GitHub Integration
Using GitHub for comments, hosting, and workflows creates a seamless developer experience.
What Needed Adjustment
1. Mobile Experience
Initially underestimated mobile traffic (now 35% of visitors). Mobile optimization became crucial.
2. Search Functionality
With 100+ posts, site search became essential. Readers couldn’t find older content easily.
3. Content Organization
Tags and categories needed refinement as content volume grew. Initial organization didn’t scale well.
Image optimization and lazy loading became critical as the site grew.
Unexpected Discoveries
1. International Audience
40% of traffic comes from outside the US, making GDPR compliance and internationalization important.
2. Long-Tail SEO Success
Specific technical problems (like “Dell Wyse 3040 Proxmox”) drive consistent traffic months after publication.
Technical readers prefer GitHub Discussions over traditional comments. The developer-focused audience appreciates the familiar interface.
4. Content Longevity
Technical tutorials have a much longer useful life than expected. Posts from 2023 still drive significant traffic.
Future Enhancement Roadmap
Short-term (Next 3 months)
Implement dark/light theme toggle
Add site search functionality
Create custom 404 page with search
Implement reading progress indicators
Medium-term (3-6 months)
Add breadcrumb navigation
Implement lazy loading for images
Create responsive image sets
Add social share buttons
Long-term (6+ months)
Multi-language support (considering Spanish)
Newsletter signup integration
Advanced search with filtering
Mobile app manifest (PWA)
Infrastructure Improvements
CDN implementation for assets
Advanced caching strategies
Security headers implementation
Automated backup system
Conclusion
Running a technical blog on Jekyll and GitHub Pages has been incredibly rewarding. The platform’s flexibility allows for continuous optimization while maintaining simplicity.
Key Success Factors
Focus on reader value : Every optimization should improve the reader experience
Measure everything : Use analytics to guide optimization priorities
Iterate continuously : Small, consistent improvements compound over time
Embrace the platform : Work with Jekyll’s strengths rather than against them
Final Recommendations
For anyone running a technical blog on Jekyll:
Essential Optimizations
Code copy buttons (highest reader satisfaction)
Proper SEO meta tags (crucial for discoverability)
GitHub Discussions comments (better than traditional systems)
Automated deployment (reduces friction)
Image optimization (biggest impact on load times)
Lazy loading (especially for image-heavy technical content)
Minimal JavaScript (keep it fast)
Mobile optimization (growing audience segment)
Content Strategy
Focus on niche technical topics
Use real-world examples and outputs
Create series for complex topics
Maintain consistent publishing schedule
The combination of Jekyll’s flexibility, GitHub’s reliability, and thoughtful optimization creates an excellent platform for technical content. The key is continuous improvement based on reader feedback and analytics data.
References