SEO Automation in Nepal: I Built an Engine to Audit My Own Site, and It Found Zero Non-Brand Clicks
Every SEO site in Nepal publishes its wins. This one publishes the output of a tool I wrote to grade my own work, including the number that says the site is not yet working. The zero is the most useful figure on the page.
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.
| Label | Meaning | Example |
|---|---|---|
OBSERVED | Directly measured from a fetched document or an export | This page returned HTTP 200 with this title |
DERIVED | Computed from measurements, with the inputs stated | Internal link authority scores, CTR by segment |
UNVERIFIED | Could not be checked with the sources available | Search 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=Nepaland 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:
| Component | Count |
|---|---|
| CLI commands | 25 |
| Engine modules | 28 |
| Lines of engine code | 11,712 |
| Lines of test code | 2,754 |
| Tests, all passing | 264 |
| GitHub Actions workflows | 5 |
| Paid APIs used | 0 |
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
| Metric | Value |
|---|---|
| Technical health | 92 / 100 |
| Pages crawled | 64 |
| Clicks | 26 |
| Impressions | 245 |
| Non-brand clicks | 0 |
| P0 actions outstanding | 2 |
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
| Segment | Clicks | Impressions | CTR |
|---|---|---|---|
| Brand | 17 | 80 | 21.25% |
| Non-brand | 0 | 88 | 0.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 band | Queries |
|---|---|
| 1–3 | 4 |
| 4–10 | 5 |
| 11–20 | 0 |
| 21–50 | 8 |
| 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:
| Query | Avg. position | Impressions | Clicks |
|---|---|---|---|
| digital marketing in nepal | 78.1 | 17 | 0 |
| digital marketing nepal | 79.7 | 12 | 0 |
| marketing in nepal | 82.3 | 12 | 0 |
| digital marketing cost in nepal | 46.7 | 3 | 0 |
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 most surprising finding: my privacy policy outranks my service pages
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.
| Page | Authority | Internal links in |
|---|---|---|
| Homepage | 100.00 | 31 |
| /privacy-policy/ | 90.07 | 31 |
| /blog/ | 61.11 | — |
| /services/ | 60.51 | — |
| Median commercial page | 13.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
| Site | Pages | Median words | Schema types | FAQ pages |
|---|---|---|---|---|
| shashikantshah.com.np | 32 | 1,969 | 14 | 25 |
| seoexpertsnepal.com | 17 | 629 | 10 | 0 |
| narayanadhikari.com | 36 | 1,247 | 9 | 0 |
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
UNVERIFIEDrather 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:
- 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.
- 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.
- 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.
