← All posts

Engineering · 2026.10.01 · 6 min · Updated 2026.10.26

SEO for a New Domain: Checking Search Volume With Self-Hosted OpenSEO Before Writing Long-Tail Guides

A new domain whose brand name is taken can only win long-tail traffic with guides. I ranked topics by OpenSEO search volume, checked each claim against primary sources, and loaded GA4 only on public pages.

Reading
Theme
Size
Width

I picked the first batch of topics for my Bitfinex auto-lending platform's guides section on gut feeling, and the phrase I targeted was "Bitfinex lending bot".

Only after checking search volume with a self-hosted OpenSEO did I learn that phrase had no volume. The volume was in "bitfinex lending" and a cluster of tax-related terms. (Unless noted otherwise, the keywords in this post are Traditional Chinese queries, translated here.)

When a new domain's brand name is already taken by another brand, category terms are the only way to get traffic.

After that, topics were ordered by search volume, every article was checked against primary sources first, and anything I couldn't verify didn't get written. The whole round of keyword research cost about US$3.5.

My brand name "EZLO" is completely taken by a smart-home brand of the same name. The top results for category searches are mostly affiliate posts pushing one competitor or another.

The guides section lives at ezlo.me/learn/, prerendered with @next/mdx and carrying Article and breadcrumb structured data. The first batch was 7 articles.

Search volume from self-hosted OpenSEO

Two weeks after the guides section launched, all I had was Search Console. I couldn't see search volume, competitors' ranking keywords or backlinks. A Semrush or Ahrefs subscription doesn't make sense at this scale.

I found the open-source OpenSEO, which pulls its data from DataForSEO's pay-as-you-go API. The minimum top-up is US$50, and the balance doesn't expire.

I first deployed it on the Cloudflare Workers free plan, where parallel queries, and even a single rank-tracking run, hit Error 1102: Worker exceeded resource limits. The same day I moved it to my own server under Docker.

In Docker mode, the cron that the Worker used to handle doesn't fire on its own, so I added a systemd timer that hits the scheduling endpoint.

OpenSEO has an MCP server. Once it's connected, Claude Code can query search volume and rankings directly.

Architecture diagram: OpenSEO runs under Docker on my own server, pulling data from DataForSEO's pay-as-you-go API (US$50 minimum top-up that doesn't expire, about US$3.5 for a round of research); Claude Code queries search volume and rankings through MCP, and a systemd timer hits the scheduling endpoint. The Cloudflare Workers free plan tried first hit Error 1102 and was abandoned the same day.

Search volume overturned my topics

Monthly search volume from OpenSEO. My original target had none:

Keyword Monthly searches
Bitfinex lending bot (my original target) No volume
bitfinex lending 480
The tax cluster About 570 combined
A few competitors' brand names A little over 200 to nearly 400 each

I rewrote the homepage title to match: "Bitfinex Lending Bot | Flat Annual Fee, No Commission | EZLO". It keeps "lending bot" but makes "Bitfinex lending" appear as one contiguous phrase.

Later topics were ordered by search volume, and I added nine more over time, on things like lending tips, whether Bitfinex is safe, lending taxes in Taiwan and withdrawing funds back to Taiwan. The guides section on PROD now has 16 articles.

For a new domain whose brand name is taken, check search volume for category terms first. Don't pick topics on gut feeling.

Rank tracking runs at the end of every month for 29 Traditional Chinese terms and 10 English terms, about US$2.8 a year. I got that estimate wrong at first: weekly tracking on two device types would have cost around US$18, and switching to monthly brought it back down.

The October 1 baseline: only 4 Traditional Chinese terms in the top 100, the best being bitfinex frr at #4.

New domains usually take 3 to 6 months to show ranking movement, so from here on it's up to the monthly automatic tracking.

Every claim checked against a primary source

Before writing each article, I sent a Claude Code subagent to check primary sources: official terms, documentation, regulations, press releases.

Check every claim in a guide against a primary source. If you can't find one, don't write it. This step caught a lot of claims that are common online, some of which I'd gotten wrong myself:

  • FRR (Bitfinex's market average funding rate) is the amount-weighted average of active fixed-rate funding, not "a smoothing of recent trades" as many blogs say.
  • Taiwan's annual cumulative foreign exchange settlement limit for individuals is no longer US$5 million. The central bank raised it to US$10 million on 2024-10-31, though the regulation's text still literally says five million.
  • A common claim online is that offers placed at FRR are charged an 18% fee. I couldn't find an official source for it; the official docs only say hidden offers are charged 18%.
  • People often say a US court has already ordered 94,000 bitcoin returned to Bitfinex. In fact, the restitution ordered in April 2025 was 0, and ownership is being handled in a separate proceeding.

Most of the "lending bot comparison" results in search are written by the competitors themselves, contain errors, and can't be cited.

Two sensitive kinds of articles got their own rules. Tax articles don't draw conclusions like "lending interest counts as overseas income". The authorities have only stated a position on buying and selling virtual assets, so the articles only describe rules that can actually be looked up.

Competitors can be named in the guides section but not on the homepage or in meta tags. Comparison articles only list facts verifiable on each company's official site and terms, note the date they were checked, and get rechecked every quarter.

GA4 only on public pages

Traffic analytics uses GA4, on the condition that app page URLs never get sent. Password reset links carry a token, and admin user-search URLs carry an email address. None of that belongs in GA.

So GA4 only loads on PROD public pages, and once a document has visited an app page, measurement stops until the next full page load.

The reason is that gtag sends the previous URL as page_referrer, and gtag('set') can't override it. If measurement resumed when the user returned to a public page, the app page URL would go out as the referrer.

Flow chart: GA4 loads only on PROD public pages; once a document has visited an app page, measurement stops until the next full page load, because gtag sends the previous URL as page_referrer; visitors from the EEA, the UK and Switzerland don't load it, with the country read from /cdn-cgi/trace, so no consent banner is needed.

Visitors from the European Economic Area, the UK and Switzerland don't load GA, with the country read from Cloudflare's /cdn-cgi/trace.

My users are in Taiwan and traffic from those regions is tiny, so I simply don't measure it, and the site doesn't need a cookie consent banner.

#GA4#SEO#Keyword Research#Content Marketing

Letters

Loading comments…

Next

Tools

Image Models Can't Write Chinese Text: AI Illustrations, and HTML Plus Playwright for Figures

Sixteen text-only guides needed images. Covers come from an image model plus a compositing script, figures with text are HTML rendered by Playwright, and every number on them is recomputed from public data.