Files
the-other-dude/docs/website/blog/index.html
Jason Staack cc34877b76 docs(website): update analytics disclaimer to reflect engagement tracking
Changed "analytics pixel to count page views" to "analytics to measure
page views and engagement" across all 22 site pages to accurately
describe the updated telemetry script.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 08:36:23 -05:00

277 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blog — The Other Dude</title>
<meta name="description" content="Updates, insights, and the occasional rant about open source MikroTik fleet management, network operations, and building software with AI.">
<meta name="keywords" content="MikroTik blog, RouterOS fleet management, MSP blog, network management blog">
<meta name="author" content="The Other Dude">
<meta name="robots" content="index, follow">
<meta name="theme-color" content="#111113">
<link rel="canonical" href="https://theotherdude.net/blog/">
<link rel="icon" href="../data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect x='2' y='2' width='60' height='60' rx='8' fill='none' stroke='%238B1A1A' stroke-width='2'/><path d='M32 18 L46 32 L32 46 L18 32 Z' fill='%238B1A1A'/><path d='M32 19 L38 32 L32 45 L26 32 Z' fill='%232A9D8F'/><circle cx='32' cy='32' r='5' fill='%238B1A1A'/><circle cx='32' cy='32' r='2.5' fill='%232A9D8F'/></svg>">
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:title" content="Blog — The Other Dude">
<meta property="og:description" content="Updates, insights, and the occasional rant about MikroTik fleet management, network operations, and building software with AI.">
<meta property="og:url" content="https://theotherdude.net/blog/">
<meta property="og:site_name" content="The Other Dude">
<!-- Fonts -->
<link rel="stylesheet" href="../style.css?v=3">
<style>
.blog-index {
max-width: 720px;
margin: 0 auto;
padding: 80px 24px 120px;
}
.blog-index h1 {
font-family: "Manrope", sans-serif;
font-weight: 700;
font-size: 2.5rem;
color: var(--text-primary);
margin-bottom: 8px;
}
.blog-index .blog-subtitle {
color: var(--text-muted);
font-size: 1.05rem;
margin-bottom: 48px;
}
.blog-list {
list-style: none;
padding: 0;
margin: 0;
}
.blog-list li {
border-bottom: 1px solid var(--border);
padding: 24px 0;
}
.blog-list li:first-child {
border-top: 1px solid var(--border);
}
.blog-list a {
text-decoration: none;
display: block;
}
.blog-list a:hover .blog-list-title {
color: var(--accent);
}
.blog-list-date {
color: var(--text-muted);
font-size: 13px;
margin-bottom: 4px;
}
.blog-list-title {
font-family: "Manrope", sans-serif;
font-weight: 600;
font-size: 1.25rem;
color: var(--text-primary);
margin-bottom: 6px;
transition: color 0.2s ease;
}
.blog-list-excerpt {
color: var(--text-secondary);
font-size: 0.95rem;
line-height: 1.6;
}
@media (max-width: 480px) {
.blog-index h1 { font-size: 1.8rem; }
.blog-index { padding: 60px 20px 80px; }
}
</style>
</head>
<body>
<nav class="site-nav site-nav--dark">
<div class="nav-inner container">
<a href="../index.html" class="nav-logo">
<svg class="nav-logo-mark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="32" height="32" aria-label="The Other Dude logo">
<rect x="2" y="2" width="60" height="60" rx="8" fill="none" stroke="#8B1A1A" stroke-width="2"/>
<rect x="6" y="6" width="52" height="52" rx="5" fill="none" stroke="#F5E6C8" stroke-width="1.5"/>
<rect x="8" y="8" width="48" height="48" rx="4" fill="#8B1A1A" opacity="0.15"/>
<path d="M32 8 L56 32 L32 56 L8 32 Z" fill="none" stroke="#8B1A1A" stroke-width="2"/>
<path d="M32 13 L51 32 L32 51 L13 32 Z" fill="none" stroke="#F5E6C8" stroke-width="1.5"/>
<path d="M32 18 L46 32 L32 46 L18 32 Z" fill="#8B1A1A"/>
<path d="M32 19 L38 32 L32 45 L26 32 Z" fill="#2A9D8F"/>
<path d="M19 32 L32 26 L45 32 L32 38 Z" fill="#F5E6C8"/>
<circle cx="32" cy="32" r="5" fill="#8B1A1A"/>
<circle cx="32" cy="32" r="2.5" fill="#2A9D8F"/>
<path d="M10 10 L16 10 L10 16 Z" fill="#2A9D8F" opacity="0.7"/>
<path d="M54 10 L54 16 L48 10 Z" fill="#2A9D8F" opacity="0.7"/>
<path d="M10 54 L16 54 L10 48 Z" fill="#2A9D8F" opacity="0.7"/>
<path d="M54 54 L48 54 L54 48 Z" fill="#2A9D8F" opacity="0.7"/>
</svg>
<span>The Other Dude</span>
</a>
<div class="nav-links">
<a href="../index.html#what-it-does" class="nav-link">Features</a>
<a href="../docs.html" class="nav-link">Docs</a>
<a href="index.html" class="nav-link">Blog</a>
<a href="https://github.com/staack/the-other-dude" class="nav-link" rel="noopener">GitHub</a>
<a href="../docs.html#quickstart" class="nav-cta">Get Started</a>
</div>
</div>
</nav>
<main>
<div class="blog-index">
<h1>Blog</h1>
<p class="blog-subtitle">Updates, insights, and the occasional rant about MikroTik fleet management.</p>
<ul class="blog-list">
<li>
<a href="500-devices-broke-the-api.html">
<div class="blog-list-date">March 21, 2026</div>
<div class="blog-list-title">500 Devices Broke the API</div>
<div class="blog-list-excerpt">The API container got OOM-killed under realistic load. Here's what happened, what was wrong, and how three config changes fixed it.</div>
</a>
</li>
<li>
<a href="not-posting-on-reddit.html">
<div class="blog-list-date">March 19, 2026</div>
<div class="blog-list-title">Why I'm Not Posting This on Reddit</div>
<div class="blog-list-excerpt">I built something and I'm not posting it on Reddit, Hacker News, or anywhere that runs on upvotes. Here's why building in public on forums is a trap.</div>
</a>
</li>
<li>
<a href="free-tier-cap.html">
<div class="blog-list-date">March 19, 2026</div>
<div class="blog-list-title">Free Is Now Capped at 250 Devices</div>
<div class="blog-list-excerpt">The free tier moved from "basically unlimited" to 250 devices. Here's why, what it means, and what hasn't changed.</div>
</a>
</li>
<li>
<a href="100-simulated-routers.html">
<div class="blog-list-date">March 18, 2026</div>
<div class="blog-list-title">Found a Bug Running 100 Simulated Routers</div>
<div class="blog-list-excerpt">A 100-device simulation exposed a NATS JetStream memory issue caused by message retention behavior. Here's what happened, why, and the fix.</div>
</a>
</li>
<li>
<a href="what-you-can-do-today.html">
<div class="blog-list-date">March 17, 2026</div>
<div class="blog-list-title">What You Can Do With It Today (And What You Can't)</div>
<div class="blog-list-excerpt">An honest look at what The Other Dude actually does today. No roadmap promises, no marketing. What works, what's rough, and what's missing entirely.</div>
</a>
</li>
<li>
<a href="not-stable-software.html">
<div class="blog-list-date">March 16, 2026</div>
<div class="blog-list-title">This Is Not Stable Software</div>
<div class="blog-list-excerpt">The Other Dude is under active development. Things break, APIs change, and that's the point. Here's why, and when stability starts mattering.</div>
</a>
</li>
<li>
<a href="why-this-exists.html">
<div class="blog-list-date">March 15, 2026</div>
<div class="blog-list-title">Why This Exists</div>
<div class="blog-list-excerpt">The story behind The Other Dude: two decades of wanting better MikroTik fleet management, AI making it possible, and why I probably won't answer your email.</div>
</a>
</li>
</ul>
</div>
</main>
<footer class="site-footer">
<div class="footer-inner container">
<div class="footer-brand">
<span class="footer-logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="24" height="24" aria-hidden="true" style="vertical-align: middle; margin-right: 8px;">
<rect x="2" y="2" width="60" height="60" rx="8" fill="none" stroke="#8B1A1A" stroke-width="2"/>
<rect x="6" y="6" width="52" height="52" rx="5" fill="none" stroke="#F5E6C8" stroke-width="1.5"/>
<rect x="8" y="8" width="48" height="48" rx="4" fill="#8B1A1A" opacity="0.15"/>
<path d="M32 18 L46 32 L32 46 L18 32 Z" fill="#8B1A1A"/>
<path d="M32 19 L38 32 L32 45 L26 32 Z" fill="#2A9D8F"/>
<path d="M19 32 L32 26 L45 32 L32 38 Z" fill="#F5E6C8"/>
<circle cx="32" cy="32" r="5" fill="#8B1A1A"/>
<circle cx="32" cy="32" r="2.5" fill="#2A9D8F"/>
</svg>
The Other Dude
</span>
<span class="footer-copy">&copy; 2026 The Other Dude. All rights reserved.</span>
</div>
<nav class="footer-links">
<a href="../docs.html">Docs</a>
<a href="index.html">Blog</a>
<a href="https://github.com/staack/the-other-dude" rel="noopener">GitHub</a>
<a href="mailto:license@theotherdude.net">Licensing</a>
</nav>
<p style="margin-top:12px;font-size:0.75em;color:#62627F;text-align:center;">This site uses self-hosted, cookie-free analytics to measure page views and engagement. No personal data is collected or shared with third parties.</p>
</div>
</footer>
<script>
(function() {
var h = 'https://telemetry.theotherdude.net';
var p = location.pathname;
var t = document.title;
var r = document.referrer;
// Session page count via sessionStorage.
var sc = parseInt(sessionStorage.getItem('_tc_sc') || '0', 10) + 1;
sessionStorage.setItem('_tc_sc', sc);
// UTM params.
var sp = new URLSearchParams(location.search);
var us = sp.get('utm_source') || '';
var um = sp.get('utm_medium') || '';
var uc = sp.get('utm_campaign') || '';
// Pixel URL with all params.
var params = new URLSearchParams({
p: p, t: t, r: r,
sw: screen.width, sh: screen.height,
vw: innerWidth, vh: innerHeight,
tz: new Date().getTimezoneOffset(),
dpr: devicePixelRatio || 1,
touch: navigator.maxTouchPoints > 0 ? 1 : 0,
cd: screen.colorDepth,
plt: Math.round(performance.now()),
sc: sc
});
if (us) params.set('us', us);
if (um) params.set('um', um);
if (uc) params.set('uc', uc);
var ct = navigator.connection ? navigator.connection.effectiveType : '';
if (ct) params.set('ct', ct);
new Image().src = h + '/px?' + params.toString();
// Engagement tracking.
var startTime = performance.now();
var maxScroll = 0;
function getScrollDepth() {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
var docHeight = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
var winHeight = innerHeight;
if (docHeight <= winHeight) return 100;
var pct = Math.round((scrollTop + winHeight) / docHeight * 100);
return Math.min(pct, 100);
}
window.addEventListener('scroll', function() {
var d = getScrollDepth();
if (d > maxScroll) maxScroll = d;
}, {passive: true});
// Send beacon on page hide.
function sendBeacon() {
var top = Math.round(performance.now() - startTime);
var data = new URLSearchParams({p: p, top: top, sd: maxScroll});
navigator.sendBeacon(h + '/px/beacon', data);
}
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') sendBeacon();
});
window.addEventListener('pagehide', sendBeacon);
})();
</script>
</body>
</html>