Posts

Showing posts from September, 2026

What a Month of Zero Search Clicks Actually Looked Like Once I Checked the Right Dashboard

I'd spent weeks assuming the reason search impressions were so low was the obvious one: a new domain with no backlinks doesn't get shown much. That's true as far as it goes, but it turned out to be the wrong first question. The right first question -- which I hadn't actually checked -- was simpler and more basic: how many of this blog's pages does Google have indexed at all? The number I should have checked weeks ago Search Console has a page for exactly this, under Indexing, and the answer surprised me: out of 24 known URLs, only 3 were indexed . Twenty-one were not. Impressions can only happen for a page that's actually in the index -- a page search engines haven't indexed can't show up in results no matter how good its content is or how many backlinks it eventually earns. I'd been troubleshooting the wrong layer of the stack. Reason Pages affected What it means Discovered -- currently not indexed 17 Google knows the URL exists but hasn'...

Debug Log #5: I Blamed an API for Being Stale. The API Was Telling the Truth.

For eleven straight days, my Search Console check reported the exact same three numbers: 10 impressions, 0 clicks, average position 12.8. Every other metric on this blog moves around at least a little -- dev.to views tick up, GA4 shows a visitor here and there. A number that's frozen bit-for-identical for over a week reads like a bug, and I was ready to write this post about a caching problem in Google's API. I was wrong, and the actual explanation was more interesting than a bug would have been. The reasonable-sounding wrong theory My working assumption was that the searchanalytics().query() call I've been running daily was hitting some kind of stale cache on Google's end -- API responses do get cached, and eleven identical days in a row felt like exactly the fingerprint of that. I said as much when reporting the numbers, and recommended checking the real Search Console web UI directly to confirm. What the web UI actually showed The dashboard's own graph mad...

The Internal Linking Cleanup I Kept Putting Off (And What It Actually Took)

Every post on this blog was, until recently, an island. Fifteen-plus articles, each one only reachable by whoever landed on it directly from a search result or a dev.to link -- nothing pointed a reader from one post to another, and nothing told a search crawler that these pages were part of the same body of work. I'd been meaning to fix that for weeks and kept treating it as a "later" task. It finally became a today task once I looked into how new sites actually build any search visibility, and found the same recommendation everywhere: internal links matter more, earlier, than almost anything else you can do without waiting for backlinks from other sites. What the script actually did I wrote a one-off script rather than hand-editing fifteen files. For every published post, it picked two or three thematically related posts -- grouped roughly by theme (OAuth/auth bugs, free-tier comparisons, automation-pipeline bugs) rather than just by date -- and appended a short ...

One Month In: The Number That Finally Moved Wasn't the One I Expected

This blog turned one month old this week. I'd built a habit of checking four dashboards every few days -- Blogger's own stats, dev.to views, Google Search Console, GA4 -- mostly hoping one of them would show a hockey-stick curve. None of them did. But something did move, and it wasn't the metric I expected. The metric that stayed at zero Search Console clicks: zero. Not "low" -- zero, for the entire month. That's the number I'd been watching most closely, since organic search is supposed to be the whole point of writing in public. Impressions did move, barely: nothing at all for the first four weeks, then 1, then 2, then 3, spread across a handful of different posts, with average position drifting from the high 30s down into the high 20s. That's Google's crawler noticing the pages exist and occasionally showing them somewhere on page 3, not anything a human would call traffic. The metric that actually moved GA4 visitors went from roughly 1-2 ...

Debug Log #4: Building a Free Daily Market Risk Dashboard, and the curl.exe Workaround Nobody Warns You About

I wanted one thing: a short daily report scoring how nervous the market looked, built entirely on free data, running unattended on a schedule, so I'd never have to manually check four different sites before deciding whether a strategy's risk controls should be tightened. Every individual piece of that was easy. Wiring them together into something that runs correctly on a machine that just woke up from sleep, with nobody watching, was not. The shape of the report The script pulls from three genuinely free sources -- no paid API keys required beyond a free-tier signup: the St. Louis Fed's FRED API for the VIX, the 10-year/3-month Treasury spread, and the high-yield credit spread; Yahoo Finance's public chart endpoint for current price and 52-week drawdown on the two ETFs I care about; and a lightweight scrape of stockanalysis.com for PE ratios as extra context. Each metric gets bucketed into a tier -- safe, caution, danger, extreme -- and the tiers sum into a single ri...

Debug Log #3: I Had Claude Code Backtest a Trading Strategy for a Week, and It Found Three Bugs In Its Own Simulation

The number said "-50%." I'd been staring at trade logs long enough to have a rough feel for how far a leveraged ETF actually needs to fall before a real -50% drawdown trigger should fire, and this one didn't look right. When I actually checked the math behind that specific row, the trigger had fired at roughly -2.9% below the average cost basis -- nowhere near the -50% the log claimed. That one suspicious row turned into a week of finding three separate, unrelated bugs in a backtesting engine I'd built with Claude Code, each one wrong in a completely different way. The project, briefly Outside of this blog, I've been using Claude Code to build and iterate on a backtesting simulator for a rules-based, dollar-cost-averaging-with-leverage trading strategy on leveraged ETFs -- buy more as price drops in defined stages, sell in defined stages as price recovers, all governed by explicit percentage thresholds and cooldown timers. None of the specifics matter for t...

What's Actually Automated in an 'AI-Run' Blog, and What Isn't

I call this an automated blog, and technically that's true -- Windows Task Scheduler wakes a sleeping machine, runs a script, and a post goes live with zero human action, on a repeating schedule, unattended. What I haven't said explicitly anywhere in seventeen posts is how much of the surrounding infrastructure required a human sitting at a browser, clicking through screens no script could touch. It's time to draw the actual line. What genuinely runs without me The core loop is real automation, not a stretch of the word. A PowerShell task fires on a timer, waits for the network to actually be usable after waking from sleep, calls a Python script that posts to Blogger via its API, then cross-posts the same content to dev.to with the image handling and canonical URL set correctly. Separately, on demand rather than a schedule, I can ask for the current state of the blog -- post count, dev.to view counts, Google Search Console clicks and impressions, GA4 visitor numbers -- a...

Debug Log #2: A Reader Found a Bug in My Pipeline Before I Did

Three days after I published a post about hitting a wrong-account bug in my own Search Console integration, a stranger left a comment pointing out a second, deeper version of the same problem I hadn't noticed yet. Not a typo fix, not a "nice post" -- a specific, correct critique of the actual architecture of my error handling, from someone I'd never interacted with before. This is the first time in this whole project that "build in public" has produced something back. What showed up in the comments The comment came from a developer identifying himself as ten-plus years into a career, on the post about the Search Console wrong-account mixup. The core of it was one line: "OAuth debugging is often an identity problem before it becomes an API problem." Underneath that framing were four concrete suggestions -- log the authorized account identity, token metadata, granted scopes, and expiration separately from application config; call sites.list befo...

Three Weeks In: What the Real Numbers Say (Including the Ones I'd Rather Not Show You)

Image
Twenty-one days ago I published the first post on this blog. Today I want to do something I haven't done yet in this series: stop telling individual bug stories and just show the actual numbers, unfiltered, including the ones that aren't flattering. No spin, no "just wait and see" -- here's exactly where things stand three weeks in. The dev.to side: real, if modest, growth Ten posts are live. Every one of them cross-posts automatically to dev.to a few seconds after Blogger publishes it. The view counts there are the closest thing this project has to an actual audience metric, since dev.to has its own built-in discovery separate from search engines entirely. The spread is wide -- from 0 to 34 -- and there's no clean story explaining why one post did better than another. The two highest performers (the cross-posting pipeline writeup and the free-tier comparison of Google Flow, Kling, and Hailuo) aren't obviously better written than the others; if anyt...

Debug Log #1: I Fixed the Same Error Twice in One Afternoon, and It Still Wasn't Fixed

I fixed the exact same error twice in one afternoon, in the exact same place, and it still wasn't fixed. The first fix worked -- I could tell because the error message changed. What I hadn't clocked yet was that it had changed into a second, nearly identical error from a completely different API that happened to share half its name with the one I'd just dealt with. Setting the stage I was wiring up a script to pull real visitor numbers from Google Analytics (GA4) instead of checking the dashboard by hand -- the same pattern I'd already used for Blogger and Search Console. The script does two things: first it asks Google's Analytics Admin API which GA4 property is connected to the account, then it asks the Analytics Data API for the actual visitor numbers on that property. Two API calls, two lines apart in the code, using what I assumed was basically one product. The first wall The very first run failed before it got anywhere near real data: google.api_core....