How I Built a Keyword Ranking SEO Model That Actually Works (And Created 3 Service Pages in 90 Minutes)
Why Most Keyword Tools Miss the Point
Here’s something that frustrated me for years about SEO tools: SEMrush, Ahrefs, and Moz show you data, not strategy.
They’ll tell you things like “this keyword gets 2,400 searches a month” or “difficulty score: 47” or “your competitors rank for this.” All useful information, on the surface.
But here’s what I was never getting from any of them:
- Which keywords I was actually targeting with specific pages
- Which keywords had no target page at all — just floating out there, unattached
- Whether my content strategy made any coherent sense as a whole
- How to systematically make sure I hadn’t missed anything obvious
After many years of doing SEO from an agency point of view, I finally built something that bridges the gap between keyword research and actual execution. I built it myself, using Django and Claude Code, and it changed how I think about the whole discipline.
The Problem: Orphaned Keywords Everywhere
I ran a simple query in my Django-based SEO platform one morning:
# Find keywords without target URLs
orphaned = KeywordRanking.objects.filter(
client_id=6, # We Build Stores
target_url__isnull=True
).values('keyword').distinct()
I’d been tracking these keywords, I knew they mattered, but I’d never actually pointed them at a page. That’s the kind of gap that traditional SEO tools don’t surface because they don’t know your strategy. They just know your data.
The traditional SEO workflow:
- I export keywords to a spreadsheet
- I manually review them over a coffee
- I forget about most of them by Thursday
- I write a blog post about one or two
- I never check if it actually worked
My workflow now:
- I query the database
- I see exactly what’s missing
- I create systematic solutions for the gaps
- I update the database so it reflects reality
- I track actual rankings over time
The Solution: A Django Model That Tracks Strategy
Here’s the core of the system — a simple Django model:
class KeywordRanking(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
keyword = models.CharField(max_length=255)
target_url = models.CharField(max_length=500, blank=True, null=True)
current_position = models.IntegerField(null=True, blank=True)
search_volume = models.IntegerField(null=True, blank=True)
difficulty = models.IntegerField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
I know this isn’t revolutionary technology. It’s just structured thinking, put into code. But look at what it lets me do:
- I link keywords to actual pages — not just “I should rank for this” scribbled on a list somewhere
- I track coverage gaps — orphaned keywords show up immediately in a query
- I monitor progress — position changes over time tell me what’s working
- I plan strategically — I can group keywords by target page and see the whole picture
That’s the difference between having data and having a system.
Real Example: One Morning’s 90-Minute Sprint
After I found those 10 orphaned keywords, I sat down and grouped them by topic:
Group 1: Digital Marketing (5 keywords)
Keywords like “digital marketing agency uk”, “digital marketing services” — all related to full-service digital marketing. I had five keywords that needed a home and no page for any of them.
My decision: I’d create a comprehensive digital marketing agency page that could target all five.
Group 2: Platform Migration (1 keyword)
“ekm to shopify migration” — specific, high-value, and underserved. I knew from client work that this was a real pain point for business owners stuck on EKM, and there wasn’t much useful content out there for them.
My decision: I’d create a dedicated EKM to Shopify migration page with real pricing from actual proposals I’d written.
Group 3: Web Development Services (4 keywords)
“website speed optimisation”, “website maintenance services”, “web development uk” — all technical service keywords that I was legitimately qualified to target but had no dedicated pages for.
My decision: I’d create a web development services page covering speed, maintenance, and custom development.
The Claude Code Multiplier
Here’s where the morning got interesting. Creating three comprehensive service pages would traditionally take me at least a full day’s work, probably more. But I used Claude Code and Astro, and I had all three done in 90 minutes.
Each page I built includes:
- A comprehensive hero section
- Detailed service breakdowns
- Pricing tables with real numbers
- FAQ sections based on actual client questions
- Google reviews for social proof
- Contact forms
- Full header and footer integration
- Mobile responsive design
- SEO optimisation baked in from the start
The Database Update: Systematic Coverage
After I’d created the pages, I updated the database so the system reflected reality:
# Update digital marketing keywords
keywords = ['digital marketing agency', 'ppc management', ...]
KeywordRanking.objects.filter(
keyword__iexact__in=keywords,
client_id=6
).update(target_url='/digital-marketing-agency')
# Result: 5 keywords now have a target page
Before: 10 keywords with no strategy behind them After: 10 keywords with dedicated, comprehensive service pages Time: 90 minutes total
That’s the kind of sprint that makes you sit back and think about how you used to do this.
The Philosophy: Service Pages vs. Blog Posts
This is where I see a lot of SEO strategies go wrong. People try to rank blog posts for commercial keywords, and it doesn’t work.
The wrong approach:
- I write a blog post called “10 Tips for Digital Marketing” and I target “digital marketing agency”
- Google looks at the search results and shows actual agencies, not my tips article
- I wonder why I’m not ranking
The right approach:
- I create a proper service page at “/digital-marketing-agency” with clear services, real pricing, and strong calls to action
- I write blog posts that build authority and link back to the service pages
- The blog does the trust-building. The service page does the converting.
Now that every commercial keyword has a service page, I can write blog posts about whatever is genuinely interesting — case studies, industry insights, opinions, technical deep-dives. The blog becomes a creative space rather than a desperate attempt to rank for commercial terms.
The Technical Stack
For those who want to know what sits underneath:
Backend
# Django models
- KeywordRanking (shown above)
- Client (who I'm tracking for)
- RankingSnapshot (historical data)
Database queries I run regularly
# Coverage analysis
total_keywords = KeywordRanking.objects.filter(client_id=6).count()
covered = KeywordRanking.objects.filter(
client_id=6,
target_url__isnull=False
).count()
coverage_rate = (covered / total_keywords) * 100
# Opportunity identification
high_volume_uncovered = KeywordRanking.objects.filter(
client_id=6,
target_url__isnull=True,
search_volume__gte=500
).order_by('-search_volume')
Frontend
- Astro for service pages — fast, simple, built for SEO
- Tailwind CSS for styling
- No JavaScript bloat weighing things down
Development
- Claude Code for page creation and iteration
- Python for data analysis
- Django admin for manual review when I need to poke around
The Results: Complete Keyword Coverage
Starting position:
- 50 total keywords tracked
- 40 keywords with target pages (80% coverage)
- 10 orphaned keywords with no strategy
After 90 minutes:
- 50 total keywords tracked
- 50 keywords with target pages (100% coverage)
- Zero orphaned keywords
What this means in practice:
- Every keyword has a home — I can see the complete strategy at a glance
- Blog posts can focus on authority — I’m not forcing them to do the conversion work
- I can track whether the strategy is working — position changes over time tell me the truth
- I can optimise systematically — gradual improvements to targeted pages, guided by data
Why This Matters for Your Business
I see a lot of businesses approach SEO the wrong way round:
The common approach:
- They write some content
- They hope it ranks
- They check rankings occasionally
- They wonder why nothing’s happening
The approach that actually works:
- I identify all the relevant keywords for the business
- I map them to specific pages — either service pages or blog posts
- I make sure there’s complete coverage with no gaps
- I track performance systematically over time
- I optimise based on what the data is telling me
The Honest Truth About SEO Tools
I used to pay for SEMrush. It’s genuinely useful for competitor research and keyword discovery. But it doesn’t tell me what to do. It gives me ingredients. I still need to cook.
That’s what the custom Django system does. It turns data into action:
- Which keywords need pages?
- Which pages need optimisation?
- What’s my coverage rate right now?
- Where are the gaps I haven’t spotted?
You could build something like this yourself with Django, a database, basic Python knowledge, Claude Code, and some time to think strategically about how you want it to work.
Or you could work with someone who’s already built it.
The Real Lesson: Build Tools That Match Your Thinking
The best SEO tool isn’t the one with the most features. It’s the one that matches how you actually think about strategy.For me, that means keyword-to-URL mapping, coverage gap identification, historical tracking, and easy querying. Those are the things I need to see every morning when I sit down to work.
Your needs might be different. Maybe you need client reporting automation, or rank tracking by location, or competitor monitoring, or a structured link building workflow.
The point is this: off-the-shelf tools solve generic problems. Custom tools solve your specific problems. And the businesses that win at SEO are the ones who know what their specific problems are.
What Happens Next
Now that I have complete keyword coverage, the real work begins — the optimisation phase:
- I monitor rankings for all 50 keywords
- I identify the quick wins — keywords sitting on page two or three that need a push
- I optimise systematically — on-page SEO, content depth, internal linking
- I track what works and what doesn’t
- I scale the patterns that succeed
Want to See This in Action?
The three pages I built that morning are live:
- Digital Marketing Agency - targeting 5 keywords
- EKM to Shopify Migration - targeting 1 high-value keyword
- Web Development Services - targeting 4 keywords
Take a look. They’re comprehensive, they load fast, and I built all three in 90 minutes.
That’s the result of strategic thinking combined with custom tools combined with AI that knows how to execute. I mapped every keyword to a destination page, which means I can’t miss a gap. I can see exactly where the weak points are and I can address them one by one.
Tony Cooper
Founder
Put My Crackerjack Digital Marketing Skills To Work On Your Next Website Design Project!
Get Started