Short answer: I built an SEO automation engine in Python, 25 commands across 28 modules, and pointed it at my own domain. It returned a technical health score of 92 out of 100 and zero non-brand clicks in seven and a half weeks. Every attributable click came from someone who already knew my name. The engine also found why: my privacy policy holds more internal link authority than any service page.

Why I built an SEO automation tool instead of buying one

I needed to answer one question honestly: is my own site working? The uncomfortable part of consulting is that a site selling technical SEO is itself evidence. If I cannot measure my own domain rigorously, there is no reason to trust me with yours.

Commercial tools would have answered it, but they answer with a number and rarely with a provenance. When a dashboard says a keyword has 1,300 searches a month, that figure is usually modelled, and the model is not shown. For a market like Nepal, where volumes are small enough that estimates get rounded into fiction, that is a real problem. I wanted a system where every number either came from a measurement or was explicitly labelled as not measured.

So the design principle came first, and the code followed from it.

The one design decision that matters: every finding is labelled

Each finding the engine emits carries one of three labels.

LabelMeaningExample
OBSERVEDDirectly measured from a fetched document or an exportThis page returned HTTP 200 with this title
DERIVEDComputed from measurements, with the inputs statedInternal link authority scores, CTR by segment
UNVERIFIEDCould not be checked with the sources availableSearch volume where no real source supplied a figure

The rule that makes this worth anything: anything unmeasurable becomes an explicit open question rather than a silent pass. A tool that quietly omits what it could not check is more dangerous than one that reports nothing, because the gap is invisible.

In practice this meant writing code that refuses to do the convenient thing:

  • It detected that my Search Console export was filtered to Country=Nepal and labelled every downstream number a slice rather than a total.
  • It will not publish a search volume unless a real source supplies one. No modelled estimates.
  • A page with no matching keyword is reported as none, not assigned the least-bad guess.
  • Zero-click position buckets are excluded from the CTR curve, so a site can never be benchmarked against its own failure and told it is doing fine.
  • Internal link insertion is skipped on listing pages where the correct placement is ambiguous.
  • The command that writes files refuses to run in a non-git directory or a dirty tree.

That last one is the difference between automation you can run and automation you can trust. Every change it makes is reversible with git checkout.

What the engine actually is

Measured from the repository, not estimated:

ComponentCount
CLI commands25
Engine modules28
Lines of engine code11,712
Lines of test code2,754
Tests, all passing264
GitHub Actions workflows5
Paid APIs used0

The 25 commands group by function: crawling and auditing (crawl, report, issues, verify), search data (search, pull, track), keywords (discover, keywords, map, volume), content (brief, pages), links (internal, links), competitive analysis (competitors), performance (vitals, health), output (dashboard, plan, run), setup (init, clients, version) and execution (apply).

Five scheduled workflows run it without me: continuous integration on every commit, a daily health check, a weekly monitor, a monthly analysis, and a cross-repository fix pass.

The code is public and MIT licensed

Inspect the SEO automation repository on GitHub. The source, 264-test suite and five workflow files are all visible, so the counts above are independently checkable rather than claims you have to take from me. Clone it, install the declared requirements and run pytest; if a number here and the repository disagree, the repository wins.

What it found: the headline block

MetricValue
Technical health92 / 100
Pages crawled64
Clicks26
Impressions245
Non-brand clicks0
P0 actions outstanding2

A technical health score of 92 next to zero non-brand clicks is the entire lesson of this exercise. The mechanical work is done. Status codes resolve, canonicals are correct, the sitemap matches what is published, titles are unique and in range, structured data parses. None of it produced a stranger.

Brand versus non-brand: the number that matters

SegmentClicksImpressionsCTR
Brand178021.25%
Non-brand0880.00%

Read that second row carefully. The site was shown 88 times to people searching for something other than my name, and not one of them clicked. Over seven and a half weeks, zero strangers were acquired from Nepali search.

This is the figure any agency would leave out of a report, and it is the only one that describes the business honestly. A 21.25% brand CTR is not a marketing achievement; it means people who already knew me typed my name and found me, which is the minimum a website must do. The commercial question is whether search introduces you to people who have never heard of you, and the answer here was no.

Where the site actually sits

Position bandQueries
1–34
4–105
11–200
21–508
51+17

Thirty-four queries in total. Nine sit on page one and twenty-five sit beyond page two, with nothing at all in the 11–20 band. That empty middle is the shape of a site that ranks for its own name and almost nothing else: you are either first for a term nobody else contests, or you are nowhere.

The commercial terms are all in the second group:

QueryAvg. positionImpressionsClicks
digital marketing in nepal78.1170
digital marketing nepal79.7120
marketing in nepal82.3120
digital marketing cost in nepal46.730

Position 78 means page eight. Nobody goes to page eight. These are real commercial queries with real impressions, and the site is registering for them in the way a lottery ticket registers for a jackpot.

The engine computes an internal link authority score, a PageRank-style distribution of link equity across the site. This is DERIVED, computed from the crawl rather than measured directly.

PageAuthorityInternal links in
Homepage100.0031
/privacy-policy/90.0731
/blog/61.11
/services/60.51
Median commercial page13.85

The second-strongest page on my site is the privacy policy. Not a service page, not a case study, not the pricing page. The privacy policy.

The cause is mundane and almost universal: the footer links to it from all 31 pages. Every page on the site votes for the privacy policy on every single load. Meanwhile six commercial pages, the ones written to earn business, hold less internal authority than the median blog article.

This is why service pages with genuinely good content were sitting at zero impressions. The content was not the constraint. The site was routing its own authority into a legal document nobody searches for. I have written this finding up separately in on-page SEO in Nepal, and it is the single most actionable thing the engine produced.

Against competitors: content is not the problem

SitePagesMedian wordsSchema typesFAQ pages
shashikantshah.com.np321,9691425
seoexpertsnepal.com17629100
narayanadhikari.com361,24790

Depth and structured data are already ahead of both. Median page length is roughly three times one competitor and 58% longer than the other. So the constraint is not quality and not volume of writing. It is authority: internal distribution, which I control, and external links, which I do not.

That distinction changes what to do next. If the problem had been thin content, the answer would be to write more. It is not, so writing more would have been motion without progress.

What the engine refused to let me claim

These are printed verbatim in the dashboard output. They are the reason I trust the rest of the numbers.

The export is filtered

“This export is FILTERED (Country=Nepal). Every figure describes that slice only.” Nothing above is a worldwide total. It is Nepali search only.

Not everything is attributable

“9 clicks and 77 impressions are not attributable to any listed query. Google withholds low-volume queries for privacy.” That is why the segments sum to 17 clicks and 168 impressions while the totals read 26 and 245. The gap is disclosed rather than quietly absorbed into one of the segments.

The date range is not what it claims

“The filter claims Jun 1 2025–Aug 15 2026, but the first day with impressions is 2026-06-25.” The real window is roughly seven and a half weeks, not fourteen months. Reporting a rate across the claimed range would have understated it by an order of magnitude.

Brand matching is fuzzy, and says so

“Classified as brand by fuzzy match (likely misspellings): ‘shasikant’.” A misspelling of my name is still brand traffic, but the classification is a judgement call, so the engine names the term it judged rather than hiding the decision inside a total.

What the engine cannot see

Stated plainly, because a tool's blind spots matter as much as its outputs:

  • JavaScript-rendered content. The crawler reads the served HTML. Content that only appears after client-side rendering is invisible to it.
  • Backlinks beyond Search Console. There is no free comprehensive backlink index. What Search Console reports is what I get.
  • Competitor rankings. I can measure a competitor's pages, words and schema. I cannot see their positions or their traffic.
  • True search volume. Without Keyword Planner data the engine reports UNVERIFIED rather than estimating.

And a boundary that is a design choice rather than a limitation: the engine measures and decides, it does not execute strategy. It will not earn a link or write a page worth reading. Anyone selling you fully automated SEO is selling you the easy half.

What I got wrong

I spent weeks on technical work. Structured data, sitemaps, critical CSS, consent mode, fourteen verification gates in the build. All of it real, all of it worth having, and none of it the constraint. The score went to 92 and the non-brand clicks stayed at zero.

I also assumed the service pages were underperforming because they needed better copy. The internal link data says otherwise. I was about to rewrite pages that were fine, on a site that was starving them of authority.

The second mistake was reporting cadence. For seven weeks I looked at totals, and totals hid this completely: 26 clicks looks like a small but functioning site. Split by brand and non-brand, it is a site that has not yet started. The segmentation was a twenty-line change and it was worth more than everything else the engine does.

What happens next

Three things, in order, and I will publish the outcome whether or not it works:

  1. Redistribute internal authority. The footer link to the privacy policy stays, because it should, but the commercial pages need proportionate internal linking from relevant body content rather than nothing.
  2. Stop competing on page-eight head terms. digital marketing in nepal at position 78 is not a target, it is a rounding error. Specific commercial intent is winnable; national head terms against established agencies are not, yet.
  3. Clear the two P0 actions and keep the daily workflow running so regressions surface within a day rather than a quarter.

If the non-brand number is still zero in three months, I will publish that too. A consultant whose own site does not work is worth knowing about before you hire them, and I would rather you learn it from me.

Common questions

What is SEO automation?

Software doing the repeatable parts: crawling, pulling Search Console data, checking technical health, tracking positions, mapping keywords to pages. It is a measurement layer, not a replacement for the work.

Can SEO be fully automated?

No. Auditing and monitoring automate well. Earning links and writing something worth reading do not. My engine measures and proposes; a human applies.

Does a technical health score of 92 mean the site is working?

No, and that is the point of this article. Mine scored 92 with zero non-brand clicks. Technical health is a prerequisite, not an outcome.

Do I need Ahrefs or Semrush for this?

Not for measurement. This engine uses zero paid APIs. Paid tools buy backlink discovery, competitor rankings and volume estimates. They do not buy the audit.

Why publish a zero?

Because it is true, and because a claim you can check is worth more than a case study you cannot. Every SEO site in Nepal publishes wins. Very few publish the measurement that would expose them.

Want the same audit run against your site?

Send me your domain and Search Console access. You will get the real output, including the numbers that do not flatter you, and a straight answer on whether the constraint is technical, content or authority.

Get in touch Technical SEO