Datasheet · SEO Factory

How the SEO Factory works

An automated SEO team that runs on a timer: it finds topics Google already half-gives us, writes the missing content, asks you to approve it, publishes it, then keeps tuning the live pages and measures whether any of it made money.

The one rule

Nothing reaches the website without you merging something

The Factory can research, write, draft, preview and measure entirely on its own. The single thing it cannot do is put new content on uktherapyguide.com without a human approval. Approval is a normal GitHub pull request — you read the change, you click Merge, it publishes on the next run. Close it instead and the work is parked, never re-opened.

1Discovery

Find the opportunity

Weekly. Reads Google Search Console for queries we already rank 5th–25th for, prices them with keyword tools, and scrapes what the pages beating us actually cover. Writes a ranked backlog. Publishes nothing.

2Publishing

Turn one into a page

Daily, one topic at a time. Research → write → anti-slop gate → open a pull request for you → publish on merge. Two human gates sit in this lane.

3Optimisation

Tune what's live

Mondays and Thursdays. One small change to one live page, then it waits 2–4 weeks and keeps or reverts it on the real Search Console numbers.

Two ways it can act on a topic

Enhance — the usual one. We already have a page ranking for the topic; the Factory writes the sections it's missing and merges them into that live page. Cheap, fast, and it inherits the page's existing ranking. 15 of our 16 topics are enhancements.

Create — no page exists, so it builds a whole cluster: one main "pillar" page plus supporting posts, published through the uktg-screens toolkit. Slower, and a brand-new page takes months to be seen by Google. One cluster (deflecting-meaning) has gone this route.

Two repositories, one job. seo-factory is the brain — it holds the plans, the research, the decisions, and every number on the dashboard. uktg-screens is the hands — it's the code that actually puts pages on the WordPress site. The brain never touches WordPress directly.
Where content comes from

The journey of one topic

Take reality testing — a topic that went live on 29 July. Here is its whole life, and every stage is a folder on disk you can open.

1 · Discover
Spotted
Search Console shows we get impressions for it but sit off page one
2 · Plan
Enhance
A page already exists — so the plan is "add the missing sections", not "build new"
3 · You
Promote
A human runs bin/promote-cluster — gate one
4 · Research
Sources
A deep-research pass gathers real citable sources; nothing may be written without them
5 · Write
Draft
Sections written, then checked by the anti-slop gate
6 · You
Merge
A pull request shows the exact rendered sections — gate two
7 · Live
5 sections
Merged into the live page, verified by re-reading it back
Everything is a file, nothing is a database. A topic is a folder — state/clusters/reality-testing/ — holding its plan, its research, its draft, its quality report and its optimisation history. That means the whole system is readable, diffable, and revertible with ordinary git. It also means there is no hidden state anywhere: if it isn't in a file, it didn't happen.
Your job

Two decisions, and nothing else is asked of you

Everything else runs unattended. These are the only two moments the Factory stops and waits for a person.

Gate 1terminal

Promote a plan

The strategy stage writes plans as planned. Running bin/promote-cluster <id> flips one to approved and lets research start. The command refuses plans with no analysed gap, no sections to add, or health-topic plans with no credentialed author.

Gate 2GitHub

Merge the gate PR

Once the draft passes the quality gate, the Factory opens a pull request on the enhance/<topic> branch. The diff is the content — the rendered sections exactly as they'll appear. Merge it and the next morning's run publishes it to the live page.

Merging is the approval — there is no separate "publish" button. The dashboard shows open gates under Awaiting you and hands you the merge link. A gate PR left sitting gets a Slack nudge after three days.

What runs on its own

Six scheduled jobs, all as systemd timers on this machine. The dashboard's Schedule panel shows their real next/last run, so a job that silently stopped is visible rather than assumed healthy.

JobWhenWhat it does
Dashboard dataDaily 06:30Pulls the fresh money + Search Console snapshot the dashboard renders
DiscoverySunday 06:00Refills the opportunity backlog
EnhanceDaily 08:00Publishes anything you merged, re-checks stuck drafts, opens gate PRs, then drafts the next topic
OptimiseMon + Thu 07:30One tuning change on one live page, and resolves any change whose window has closed
Conversion monitor1st of the monthFlags a topic whose clicks rose but whose enquiries-per-click fell — wrong-intent traffic
Read-outsSunday 07:00Regenerates the deep-dive reports (site audit, conversions, CRO scorecard)
Dashboard tour

Reading the control screen, panel by panel

The dashboard is read-only. It never approves, publishes or changes anything — it renders the files on disk, so what you see is literally the system's own state. It's one long page; the tabs across the top jump to each section.

📊 http://lucas-linux.tail3ed7a2.ts.net:8770/ — over Tailscale, no login
1 · Pipeline the board — every topic, in one column each
Discovery
2
ideas scored, not started
Strategy
1
plan waiting on you
Research
0
gathering sources
Creation
0
writing sections
Review
0
gate PR open
Live
15
sections live on the site

Six columns, left to right, in the order work moves. Each card is one topic; click it to open that topic's own page — its plan, the drafted sections, the anti-slop verdict per section, and the merge button if it's waiting on you.

Cards can't lie about being busy. A topic stuck in Research with no file activity for 12 hours turns Needs attention instead of showing a hopeful progress bar, and a draft that the quality gate blocked reads "⚠ 2/6 sections blocked" rather than "authoring content".

2 · The money the only section that answers "did this earn anything"
New clients
76
first purchase · organic + direct
Form submissions
245
placement forms from content pages
Tracked value
£21,824
gross · ≈£5,456 net to UKTG
Converting pages
43
of 363 indexed

Last 90 days, read from our own attribution tracker — not Google Analytics. A "new client" is someone's first ever tracked purchase, credited to the content page their journey started on.

Underneath sit two drill-downs. Benchmark month by month is the full history since organic tagging went live in March — click a month to see which landing pages produced it. Converting pages is the same data sliced the other way: every page that has ever produced a client, click one for its monthly split.

Then two panels that frame the whole strategy: Golden tier (pages that both convert and have search headroom — where effort pays twice) and The leak (posts pulling hundreds of clicks and converting nobody).

3 · What changed on the site content log · newest first
DatePageChangeDetail
29 Jul
Reality Testing/reality-testing-how-to-determine…
updated5 sections added
23 Jul
Deflecting/deflecting
optimisednew section added
20 Jul
What Does Deflecting Mean/what-does-deflecting-mean
optimisedtitle & meta rewritten

Every edit the Factory has made to the live site, with the page title linking straight to the live URL. updated = an enhancement published through the gate. optimised = the tuning loop's own change. reverted = a tuning change that lost and was rolled back.

This is the honest answer to "what has it actually done to my website" — it's built from the run logs, not from anyone's memory.

4 · Is it working? performance · last 90 days
Organic clicks
1,927
Search Console
Converting people
277
organic-attributed
Keywords ranking
554
queries with impressions
Pages indexed
363
WordPress audit
SERP position — tracked pagesPos14-dayImpr
Somatic Therapy/somatic-therapy-online
8.4▲ up 2.81,642
Why Can't I Cry/why-cant-i-cry-7-reasons…
8.1▼ down 1.31,254
Deflection/deflection-in-psychology…
6.8▲ up 2.1833

The four tiles are site-wide reality. Below them, By cluster puts each topic's clicks next to its forms, people and pounds — so a topic with traffic and no money is obvious at a glance.

SERP positions tracks every enhanced or live page: its average Google position over the last 14 days against the 14 before. ▲ means the page moved up the results. This is the fastest read on whether an enhancement worked, weeks before conversions could show it.

5 · Awaiting you the to-do list — usually empty

Open gate PRs, each with its Review-and-merge link, plus any plans sitting at the promote gate. When it says "No open gates — nothing waiting on you", the pipeline genuinely has nothing blocked on a human.

If the Slack webhook itself is broken, a red banner appears here — otherwise a dead webhook would silently swallow every alert the pipeline believed it sent.

6 · Schedule what runs on its own, and whether it actually ran
JobCadenceNextLast
Optimisation cyclebin/optimise-live
Mon,Thu 07:30Mon 03 AugThu 30 Jul
Draft one enhance topicbin/enhance-next
Daily 08:00Fri 31 JulThu 30 Jul

Read straight from systemd, so an inactive timer shows (off) and a never-run job says "never" — no wishful thinking. Underneath, Which clusters the loop touches explains why the tuning loop only acts on 1 of 16 topics: a topic joins the loop when its status becomes live, which today only deflecting-meaning is.

7 · Inside a cluster carousel · one topic at a time

A flip-through of every topic showing its plan: which live page it enhances, the exact list of sections being added, its target keyword, and whether it's flagged as a health topic requiring a clinician-credentialed author. Click the title to open the full topic page.

8 · The compounding loop the tuning ledger
PlayUsedKeptForms
REWRITE_TITLE_AND_META
2watching
ADD_H2_SECTION
1watching

Left: weekly clicks across every page in the tuning loop, with a chip per change — kept, watching, or reverted. Right: which plays pay off, ranked by the enquiry-form lift they've produced across every use.

A play needs 5 resolved uses before it counts as proven. One that loses 60% of the time gets ⛔ and the optimiser stops proposing it until a human clears its record. Today all three changes are still in their evaluation window, so the ledger reads honestly empty rather than guessing.

9 · Read-outs the deep dives

The long-form reports the pipeline generates — site audit, conversion analysis, CRO scorecard, discovery run, content-gap analyses. Newest of each type, rendered in-browser. Anything gone stale carries a "36d old" badge so you don't quote a number from a report nobody has refreshed.

10 · Activity log what the system actually did, line by line
07:35 ├─ cycle start deflecting-meaning (today 2026-07-30)
07:35 ├─ metrics 4 pages pulled from GSC
07:35 ├─ hold deflecting-meaning: in_window
07:35 └─ cycle end nothing to commit this cycle

The last three runs, each step with its timestamp, plus the run's duration, error count and API cost. Every loop writes one of these files when it finishes, so "the optimiser ran but did nothing" is distinguishable from "the optimiser never ran".

Where numbers come from

Four sources, no spreadsheets, no manual entry

Every figure on the dashboard traces to one of four systems, refreshed by the 06:30 job each morning.

GSCfree

Google Search Console

Clicks, impressions, average position, and which queries a page surfaces for. The source for opportunity-spotting and for every keep/revert decision.

£own data

Our attribution tracker

The UKTG plugin that records real journeys — form submissions, bookings, purchases. Conversions are credited to the content page the visitor was actually on, not the site they first landed on.

WPREST

The WordPress site itself

The page inventory — what exists, what's indexable. 363 pages today. Also how enhancements are written back and then re-read to verify they landed.

APIpaid

Keyword & research tools

Search volumes and difficulty, competitor page scraping, and one deep-research pass per topic for citable sources. Roughly £2–3 per topic researched, a few dollars a week on keyword data.

Why conversions credit the content page

A visitor arrives on a blog post from Google, browses to a service page, and fills the form there. Naïve tracking credits the service page and the blog post looks worthless. We record the page the visitor was on at each step, so the post that earned the visit keeps the credit. That's the whole reason "The leak" panel is meaningful — those four posts pull 550+ clicks a quarter and genuinely convert nobody, rather than merely being under-credited.

That leak is now plugged, and being measured. Gentle call-to-action blocks were added to the eight highest-traffic posts — a button to the therapist-match flow and a text link to the topic's converting service page. They're live on all eight. The test is simple: those posts should stop reading zero on the next conversion report.
The optimiser

One change at a time, then two to four weeks of silence

SEO can't be A/B tested — there's one Google result per URL, so the only honest measurement is before-versus-after on the same page. Everything about this loop is built around not fooling ourselves.

One cycle

Pull the numbers → resolve any change whose window has closed → pick one page with nothing in flight → form a hypothesis about why it underperforms → pick the matching play → commit it and deploy. Then stop. A page with a change in flight is locked, so two edits can never overlap and muddy the reading.

What the numbers sayWhat it doesWhy
Page improved, topic healthyKeepIt worked.
Page improved, topic droppedRevert + flag a humanThe page probably won by stealing its neighbours' rankings.
Page got worseRevertRoll back to the previous version.
No real change, topic healthyKeepReverting noise risks undoing a real gain hidden inside it.
Three flat results in a rowStop, flag a humanThe plays aren't moving this page; more tweaking is waste.
Enquiry forms collapsed 60%+Revert regardless of clicksMore traffic that converts less is not a win.

The window is 14 days, or 28 for a quiet page — a low-traffic page needs longer for a real effect to clear its own week-to-week noise. A move smaller than the page's historical swing counts as no change at all, not as a win.

The deploy owns the clock, not the commit. A change that was committed but failed to deploy is not live, so it gets no start date and cannot be graded — the window starts the day a deploy actually lands. A late start truncates the measurement honestly; an early one would measure days the change didn't exist. Known Google core-update dates are recorded so a contaminated window is paused rather than misread.
Guardrails

Why it doesn't publish slop

This is health content on a site people trust with a hard moment in their lives. Six things stand between the model and the website.

Nothing is written from memory

Writing happens only after a research pass has gathered real sources, and every claim-shaped sentence must carry a citation that resolves to one of them. An invented citation — or a claim with none — blocks the section. It never reaches a pull request.

It can't diagnose anyone

Phrases that tell a reader they have a condition are blocked outright; the copy has to say "you may be experiencing". On health topics, a section without crisis support signposting (Samaritans, 116 123) is blocked too.

A blocked draft is visible, not silent

A topic whose sections failed the gate shows on the board as "⚠ 2 of 6 sections blocked", not as healthy work in progress. Each cycle re-checks stored drafts, so a gate fix applies retroactively without rewriting anything.

Every write is idempotent and verified

Published sections are wrapped in topic-scoped markers, so a re-run replaces them and can never duplicate. After writing, it re-reads the live page and confirms the content is actually there — a silent failure fails loudly instead.

It stays off the money pages

Hard rule in code: the Factory never touches the enquiry funnel, the placement form, or the therapist directory. Those are the revenue path and stay under human control. The call-to-action injector refuses those targets outright.

Everything is revertible

Every autonomous commit is signed by a bot author, so git log separates machine work from human work. A bad change is a normal git revert plus a redeploy — the git history is the rollback mechanism.

Limits

Four things to hold while reading it

SEO pays out in months, not days

An enhancement changes rankings over weeks; a brand-new page can take a quarter to be taken seriously by Google. The one created-from-scratch cluster has had almost no traffic since going live — that's expected for a new page, not a fault in the machine.

The tuning loop only touches live clusters

Fifteen of sixteen topics are enhancements to existing pages, and those deliberately end at "enhanced" rather than entering the loop — the optimiser's plays assume it owns the whole page, which it doesn't on a page the wider site also edits. So the loop currently works on exactly one topic.

Traffic and money are two different scoreboards

Clicks are visible within weeks; a new client can take months and needs the visitor to actually reach a form. Judge an enhancement first on SERP position, then on clicks, and only much later on pounds.

The dashboard is only as fresh as its 06:30 job

Money and performance render from a snapshot file, not a live query. The header carries its refresh date — if that date is old, the job didn't run, and the Schedule panel will show why.