Build Surfer SEO

KINDAreplaces $99/mosaves $1,188/yrback to the verdict

0%0 of 20 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

Fetch the pages currently ranking for a query through a search data provider, extract their structure and vocabulary, produce a brief covering the subtopics they all address, score a draft against that coverage as a checklist, and record what actually happened to the page afterwards so the score can be judged rather than trusted.

estimated effort multi-daythe files for this build are in the project pack

DataA paid search results APIRuntimePython 3.12 with SQLiteExtractiontrafilatura for article text and a parser for heading structureAnalysisTerm frequency comparison plus subtopic coverageOutcomesRecorded position over time per page you published

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the fetching and analysis.

    Get it python.org or your package manager, then a virtual environment.

    Verify python3 --version prints 3.12 or higher

  2. API keypriced per call; a few hundred queries a month is typically tens of US dollars and position tracking multiplies it

    Why This is the input and it has no free substitute. Scraping is against terms, unreliable and blocked, which makes every downstream number meaningless.

    Get it Choose a provider, read its per-call pricing carefully, and start on the smallest plan. Estimate your monthly calls from briefs plus position tracking before committing.

    Verify A query returns ranked results with urls

  3. have readyfree

    Why Phase 5 evaluates whether any of this works, and it needs pages whose positions you can actually track. Without them the tool cannot be judged.

    Get it Use pages you have already published. If you have none, this build cannot be evaluated yet and you should know that before spending on search data.

    Verify Ten pages with target queries are recorded

  4. decidefree

    Why The most likely finding is that coverage score and outcome are weakly related. A tool built to confirm a belief is worse than no tool.

    Get it Decide before Phase 5 that you will act on the finding either way, and write that down.

    Verify The commitment is recorded before outcomes are measured

  5. decidethe cap you choose

    Why Per-call pricing plus weekly position tracking grows faster than expected, and the point of leaving a subscription is spending less.

    Get it Set a figure and a hard cap at the provider before the first bulk run.

    Verify A provider spend cap is configured

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- queries(id, text, locale, device, checked_at)
- serp_results(query_id, position, url, title, fetched_at)
- pages(id, url, fetched_at, word_count, headings_json, text, status)
- terms(page_id, term, count) · after normalisation, for comparison rather than for display
- subtopics(query_id, name, present_in_count, example_headings_json) · what most ranking pages cover
- briefs(id, query_id, created_at, subtopics_json, target_words, notes)
- drafts(id, brief_id, text, scored_at, coverage_json, score)
- outcomes(page_url, query_id, checked_on, position) · what happened after publishing, which is the only real evidence

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
SERP_API_KEYsecretrequiredreplace-with-provider-keyYour search data provider. Priced per call, so treat it as a spending instrument.
SERP_CACHE_HOURSrequired168How long a query's results are reused. Rankings do not change hourly and calls cost money.
FETCH_TIMEOUT_MSrequired8000Per-page timeout when reading ranking pages.
FETCH_USER_AGENTrequiredContentBrief/1.0 (contact: you@example.com)Identify yourself honestly. You are reading other people's sites.
TRACKING_INTERVAL_DAYSrequired7How often positions are checked. This is the cost that grows quietly.
MONTHLY_SPEND_CAP_USDrequired30Stop making billed calls at this figure. Mirror it as a hard cap at the provider.

The build, in order

  1. Search data from a supportable source

    You can fetch what currently ranks for a query, repeatedly, without being blocked.

    1. With locale and device. Read the pricing before building, because this is the recurring cost.

      Files src/serp.py

    2. These calls are priced individually and rankings do not change hourly.

      Files src/cache.py

    3. So the eventual comparison against the subscription is real rather than a feeling.

      Files src/cost.py

    done when · tick each as it passes
    watch out
    • Scraping search result pages directly is against the terms of every major engine, returns different results for automated clients, and gets blocked. It also produces data you cannot rely on, which makes every downstream analysis meaningless. Pay for the API or accept that the build has no input.
  2. Fetching and extracting the ranking pages

    You have the text and structure of the pages you are comparing against.

    1. Timeout, byte cap, rate limit, honest user agent. You are reading someone's site.

      Files src/fetch.py

    2. The hierarchy matters as much as the words for a brief.

      Files src/extract.py

    3. Never treat a failure as empty. Report the analysed count on the brief.

      Files src/extract.py

    done when · tick each as it passes
    watch out
    • Treating a failed fetch as an empty page skews every average downward and makes the target word count nonsense. Exclude failures from the analysis and report how many of the ranking pages you actually managed to read, because a brief built from three of ten pages is a different thing.
  3. Subtopics, which are more useful than terms

    The brief says what the ranking pages all cover, which is the part worth acting on.

    1. Across pages, grouping equivalent headings. Report coverage counts rather than a flat list.

      Files src/subtopics.py

    2. Word count as a range and median from analysed pages only.

      Files src/brief.py

    3. Example headings per subtopic, so the writer can judge relevance rather than obeying.

      Files src/brief.py

    done when · tick each as it passes
    watch out
    • A single target word count implies a precision that does not exist, and writing to it produces padding. Report the range and the median across the pages you actually analysed, and let the writer decide, since covering the subject well is the thing that correlates with the number rather than the reverse.
  4. Scoring a draft, honestly labelled

    A draft gets a coverage checklist rather than a number to maximise.

    1. Subtopics addressed and omitted. That is the actionable output.

      Files src/score.py

    2. Available, labelled, not the headline. Term matching is a weak proxy and should look like one.

      Files src/score.py

    3. Nothing in the interface should imply a ranking outcome. Check the strings deliberately.

      Files src/ui.py

    done when · tick each as it passes
    watch out
    • A single score invites optimisation, and optimising term frequency produces text that reads as though it was written for a machine, which is the outcome search engines have spent two decades getting better at detecting. Lead with coverage, keep terms secondary, and never phrase the score as a likelihood of ranking.
  5. What actually happened

    You record where your published pages ended up, so the tool can be judged.

    1. On a schedule, through the same paid API, with the cost accounted for.

      Files src/tracking.py

    2. At a sample size where the comparison means something. Ten pages is a minimum, not a good number.

      Files src/evaluate.py

    3. It is the most likely finding and the most useful one.

      Files src/evaluate.py

    done when · tick each as it passes
    watch out
    • Without outcome tracking this tool cannot be evaluated and you will keep using it because it feels productive. Record positions over time, and be prepared for the answer that coverage score and outcome are barely related, because that is a genuinely possible and useful finding.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more seo & marketing.