v2.0 · March 2026
INTERNAL OPERATIONS DOCUMENT

SEO Operations Playbook

The complete system for how Dotcom Design researches, builds, and delivers local SEO strategies for clients. Follow every step in order. Do not skip steps.

Version: 2.0 Updated: March 2026 Arm: SEO Strategies Status: Active
This playbook is a sequential workflow, not a reference wiki

Every step must be completed in order before moving to the next. Each step has an Entry Condition (what must be ready before you start), a Completion Gate (what you must produce before you leave), and a Next Step directive. Do not advance until the Completion Gate is fully satisfied.

How to Use This Playbook

When a new SEO strategy is assigned, start at Step 1 and work through each step sequentially. The sidebar shows all 9 steps. The step number indicators in the sidebar show your position. At the bottom of every step page, a "Next Step" button takes you directly to the next step.

The Entry Condition block at the top of each step tells you exactly what must be true before you begin that step. If the entry condition is not met, stop and complete the prior step first.

The Completion Gate block at the bottom of each step (above the Next Step button) is a checklist of deliverables. Every item must be checked before you click Next Step.

Workflow at a Glance

StepNameInputOutput
1Client Data ExtractionClient website URLVerified service list, HQ city, service area, existing pages
2Keyword ResearchService list from Step 1Raw keyword list with search volumes for all service lines
3Keyword BucketingRaw keyword list from Step 2Organized keyword families with base terms and variants
4Market AnalysisHQ city and service area from Step 1Tiered market list sorted by population
5Keyword SelectionBuckets from Step 3, markets from Step 4, plan levelFinal selected keywords and markets with combination count confirmed
6Matrix GenerationSelected keywords and markets from Step 5Complete keyword-city matrix with correct combination count
7Site AssemblyAll data from Steps 1-6Complete strategy website (index.html, app.js, charts.js, style.css)
8Visual QALocally rendered site from Step 7Verified site with no layout, data, or formatting errors
9DeploymentVerified site from Step 8Live site at seo-strategy.dotcomdesign.com/{clientdomain}
Never invent or estimate prices

The prices below are the source of truth. Do not use any other source. Do not estimate. If a plan level is not listed here, it does not exist.

Plan LevelMonthly PriceCombinationsNotes
SEO Booster$399/mo10Entry level. Often 1 keyword x 10 markets or 2 x 5.
Level A$600/mo20Most common starting plan.
Level B$900/mo30
Level C$1,200/mo40
Level D$1,600/mo50
Level E$2,000/mo60
Level F$3,000/mo90
Level G$4,000/mo120
Level H$5,000/mo150

Combination Math

The number of combinations is always: Keywords Selected x Markets Selected = Total Combinations. This must equal the plan level exactly. There is no rounding, no approximation.

Examples:

Step 1 of 9

Client Data Extraction

Extract everything you need to know about the client before touching a single keyword. This step is the foundation. If it is wrong, every subsequent step is wrong.

ENTRY CONDITION

You have the following from the user before starting this step:

  • Client website URL
  • Plan level (e.g., Level A, SEO Booster)
  • Any explicit exclusions (cities to avoid, keywords to avoid)

If any of these are missing, ask the user before proceeding.

What to Extract

Browse the client website thoroughly. Do not skim. Visit the homepage, every service page, the about page, and the contact page. Extract the following:

Data PointWhere to Find ItWhy It Matters
Business nameHomepage, logo, title tagUsed in strategy site hero and prose
HQ city and stateContact page, footer, addressAlways the first selected market
Full service listServices nav, service pages, homepage sectionsDefines which keyword buckets are valid
Business model typeAbout page, homepage languageRetail showroom vs. contractor vs. manufacturer. Critical for keyword alignment.
Service areaService area page, footer, about pageDefines the geographic scope for market analysis
Existing city pagesSitemap (/sitemap.xml, /sitemap_index.xml, /page-sitemap.xml)Avoid duplicating combinations the client already has pages for
Only include services that are explicitly on the website

Do not infer services. Do not add services based on industry knowledge. If "cabinet makers" is not on the website, it is not a service. If "outdoor kitchen" is not on the website, it is not a service. The website is the only source of truth for services.

Business Model Classification

Before leaving this step, classify the client's business model. This classification directly controls which keywords are valid in Step 3.

Model TypeDescriptionValid KeywordsInvalid Keywords
Retail ShowroomSells products from a physical location. Customers come to them."near me", "showroom", "store", "shop""makers", "contractor", "remodeling", "installation"
Contractor / ServiceComes to the customer's home or job site."near me", "contractor", "company", "service", "installation""showroom", "store", "shop"
ManufacturerMakes products, sells wholesale or direct."custom", "made to order", "wholesale""near me", "showroom", "contractor"
COMPLETION GATE

Before advancing to Step 2, confirm you have all of the following:

  • Business name confirmed
  • HQ city and state confirmed
  • Full service list documented (only services explicitly on the website)
  • Business model classified (Retail Showroom, Contractor, or Manufacturer)
  • Service area documented
  • Existing city pages noted (or confirmed none exist)
NEXT STEP Step 2: Keyword Research
Step 2 of 9

Keyword Research

Generate a raw list of all candidate keywords across every service line. Do not filter or select yet. That happens in Step 3 and Step 5.

ENTRY CONDITION

Step 1 is complete. You have:

  • A verified service list (only services on the client website)
  • The business model classification

Using the SEMrush API

Run scripts/semrush_keyword_research.py using each service line as a seed keyword. The SEMrush API key is stored in the SEO Strategist skill.

If the SEMrush API balance is zero, use known industry search volumes from prior research. Document which keywords were sourced from SEMrush vs. estimated, so the data can be verified later.

Keyword Generation Rules

For each service line, generate keyword variants using these modifiers:

Modifier TypeExamplesNotes
Local intentnear me, in [region]Highest commercial intent. Always include.
Business typestore, showroom, company, companies, contractorMust match business model. A showroom gets "store/showroom." A contractor gets "company/contractor."
Qualifiercustom, local, best, affordableInclude if they have meaningful search volume.
Actionbuy, install, designInclude only if relevant to the business model.
Four things that must never appear in the keyword list

1. City or state names embedded in keywords (e.g., "kitchen cabinets Dallas") — cities are applied at the matrix stage, not the keyword stage. 2. DIY or how-to terms (e.g., "how to install kitchen cabinets"). 3. Job-seeking terms (e.g., "cabinet maker jobs"). 4. Terms outside the client's confirmed service list.

Volume Thresholds

Include all keywords with national monthly search volume above 100. Do not discard low-volume keywords at this stage — they may be valuable for niche service lines. The selection decision happens in Step 5, not here.

COMPLETION GATE

Before advancing to Step 3, confirm:

  • At least 5 keyword candidates per service line
  • Every keyword has a documented monthly search volume
  • No city names embedded in any keyword
  • No DIY, informational, or job-seeking terms included
  • No terms outside the client's confirmed service list
NEXT STEP Step 3: Keyword Bucketing
Step 3 of 9

Keyword Bucketing

Organize the raw keyword list into tight, logical families. This structure directly controls how keywords are displayed on the strategy site and how variants are grouped.

ENTRY CONDITION

Step 2 is complete. You have a raw keyword list with search volumes for all service lines.

The Core Rule: Same Core Term Only

A keyword is only a variant within a bucket if it shares the exact same core term. This is not a guideline. It is the rule. If two keywords have different core terms, they are different buckets, regardless of how similar they seem.

Wrong vs. right bucketing: real examples from past errors

WRONG: "custom kitchen cabinets" as a variant of "cabinet makers." These are different core terms ("kitchen cabinets" vs. "cabinet makers"). They are separate buckets.

WRONG: "bathroom vanity" as a variant of "bathroom cabinets." Different products, different core terms. Separate buckets.

WRONG: "kitchen cabinet showroom" as a variant of "kitchen cabinet store." "Showroom" and "store" are different core terms. Separate buckets.

RIGHT: "kitchen cabinets near me" and "custom kitchen cabinets" are both variants of the "kitchen cabinets" bucket. Same core term, different modifiers.

How to Build a Bucket

Every bucket must have exactly this structure:

  1. Base keyword (variant_type: "base") — the core term with no modifiers. Example: "kitchen cabinets". This is the anchor row. Every bucket must have one, even if the base term alone has low search volume.
  2. Near me variant (variant_type: "near_me") — the core term plus "near me". Example: "kitchen cabinets near me". Usually the highest-volume keyword in the bucket.
  3. Additional variants — other modifiers applied to the same core term. Example: "custom kitchen cabinets", "kitchen cabinets store".
The base keyword is mandatory even if you never select it

The strategy site renderer groups variants under the base keyword row. If the base keyword is missing from the data, the renderer loses its anchor and incorrectly nests the variants under the previous bucket. This has caused repeated visual bugs. Every bucket must have a base keyword entry in the data, even if that keyword is not selected for the matrix.

Bucket Examples for Common Industries

IndustryCorrect Separate BucketsCommon Mistake
Kitchen & Bath Showroomkitchen cabinets / bathroom cabinets / bathroom vanity / countertops / granite countertops / quartz countertopsGrouping bathroom vanity under bathroom cabinets
Tree Servicetree service / tree removal / tree trimming / stump removal / stump grindingGrouping stump grinding under stump removal
Roofingroofing contractor / roof repair / roof replacement / roof installationGrouping roof repair under roofing contractor
COMPLETION GATE

Before advancing to Step 4, confirm:

  • Every keyword from Step 2 is assigned to exactly one bucket
  • Every bucket has a base keyword entry
  • No bucket contains keywords with different core terms
  • Each bucket represents a distinct product or service (not a modifier variation)
  • Buckets align with the client's business model classification from Step 1
NEXT STEP Step 4: Market Analysis
Step 4 of 9

Market Analysis

Build the full list of candidate markets within the client's service area. Sort and tier them by population. This list is the input to the market selection formula in Step 5.

ENTRY CONDITION

Step 1 is complete. You have:

  • HQ city and state
  • Service area description (e.g., "Serving the Greater Phoenix Area" or "Serving within 35 miles of Bellevue, WA")
  • Any explicitly excluded cities from the user

Building the Market List

Run scripts/market_analysis.py for the client's county or region. For multi-county service areas, run per county and combine. Filter to cities within approximately 35-40 miles of HQ.

Always include county seat cities even if their population falls below the tier thresholds. County seats carry disproportionate commercial search demand.

Tiering Rules

TierPopulation RuleNotes
Tier 1HQ city (always) + any city with population above 40,000Primary targets. Maximum search volume.
Tier 2Population 10,000 to 40,000Secondary targets. Good volume, less competition.
Tier 3Population below 10,000Expansion targets. Low volume but easy wins.

Exclusion Rules

Remove any city that the user has explicitly excluded. Document the exclusion and the reason in the strategy notes. Do not add excluded cities to the Not Used section of the strategy site — exclusions are operational notes, not keyword/market decisions.

COMPLETION GATE

Before advancing to Step 5, confirm:

  • All cities within the service area are listed
  • Every city has a verified population figure from a credible source (Census, state estimates)
  • Cities are sorted by Tier, then by population descending within each tier
  • HQ city is at the top of Tier 1
  • Excluded cities are removed and documented
NEXT STEP Step 5: Keyword Selection
Step 5 of 9

Keyword Selection

Select the final keywords and markets for the strategy. This step produces the exact combination count required by the plan level. Every decision here must be defensible.

ENTRY CONDITION

Steps 1 through 4 are complete. You have:

  • Organized keyword buckets with search volumes (from Step 3)
  • Tiered market list sorted by population (from Step 4)
  • The plan level and its required combination count (from user intake)

The Selection Formula

The formula is: Keywords x Markets = Plan Combinations. You must decide how many keywords and how many markets to use. The two strategies are:

StrategyWhen to UseExample (Level A, 20 combos)
Go Wide1-2 keywords dominate search volume. The business has a narrow, focused service offering.1 keyword x 20 markets, or 2 keywords x 10 markets
Go DeepMultiple distinct service lines each have meaningful search volume. The business has a broad offering.4 keywords x 5 markets, or 5 keywords x 4 markets

Keyword Selection Rules

  1. One keyword per service line maximum. Select the highest-volume base keyword from each service line bucket. Do not select two keywords from the same bucket.
  2. Maximize service line coverage. A lower-volume keyword for a distinct service line is more valuable than a higher-volume variant of an already-covered line.
  3. Business model alignment is mandatory. The selected keywords must match the client's business model. A retail showroom never gets "cabinet makers" or "remodeling contractor." A contractor never gets "showroom."
  4. The near me variant is almost always the right choice. "Kitchen cabinets near me" (74,000/mo) beats "kitchen cabinets" (201,000/mo) for local SEO because it has stronger local commercial intent.

Market Selection Rules

  1. Calculate the number of markets first: Plan Combinations / Number of Selected Keywords = Number of Markets.
  2. Select top-down by population, strictly. Take the top N markets from the sorted Tier 1 list, then Tier 2 if needed. No skipping. No cherry-picking.
  3. HQ city is always market #1. No exceptions.
  4. Honor all user exclusions. If the user said "not Seattle," Seattle is not in the list regardless of its population rank.
Market selection must be deterministic, not arbitrary

In past strategies, markets were selected inconsistently between versions of the same strategy. This is not acceptable. The formula produces one correct answer. Renton (108,429) always beats Issaquah (40,051) when selecting by population. There is no judgment call here.

Not Used Keywords

Every keyword that was researched but not selected must be placed in the Not Used section of the strategy site with a clear reason. Valid reasons are:

COMPLETION GATE

Before advancing to Step 6, confirm:

  • Keywords selected x Markets selected = Plan combination count exactly
  • No two selected keywords are from the same bucket
  • All selected keywords match the client's business model
  • Markets are selected in strict top-down population order
  • HQ city is market #1
  • All user exclusions are honored
  • Every non-selected keyword has a documented reason for not being selected
NEXT STEP Step 6: Matrix Generation
Step 6 of 9

Matrix Generation

Build the keyword-city combination matrix. This is the core deliverable of the strategy. Every cell represents one page that will be built for the client.

ENTRY CONDITION

Step 5 is complete. You have:

  • Final list of selected keywords
  • Final list of selected markets
  • Confirmed combination count matching the plan level

Matrix Orientation Rule

The matrix has two valid orientations. Choose based on the number of markets:

Markets CountOrientationReason
5 or fewerKeywords as rows, cities as columnsFits cleanly in the standard table width
6 or moreCities as rows, keywords as columnsCity names are too long to use as column headers without overlapping
Grand total row must not change color on hover

The grand total row at the bottom of the matrix uses a special CSS class (.grand-total-row) that overrides the default hover highlight. If this row changes color on hover, the CSS rule is missing. Check the style.css reference file.

Enforcement Rules

COMPLETION GATE

Before advancing to Step 7, confirm:

  • Matrix orientation matches the market count rule
  • Total cell count equals the plan combination count exactly
  • Row totals and column totals are accurate
  • No keyword appears in both the matrix and Not Used
  • Grand total row CSS is applied correctly
NEXT STEP Step 7: Site Assembly
Step 7 of 9

Site Assembly

Build the branded strategy website using the canonical reference templates. Do not build from scratch. Do not use a React/Vite scaffold. Use the templates.

ENTRY CONDITION

Steps 1 through 6 are complete. You have all strategy data finalized:

  • Client data (name, HQ, services, business model)
  • Keyword buckets with all variants and search volumes
  • Tiered market list (all markets, not just selected ones)
  • Selected keywords and markets
  • Combination matrix with correct counts
  • Not Used keywords with reasons
  • Additional Opportunities (upgrade paths) with correct plan pricing

File Structure

Every client strategy site lives at: /home/ubuntu/seo-strategy-repo/{clientdomain}/

The four required files are:

FileSourceWhat to Customize
index.htmlCopy from references/index_template.htmlUpdate the <base href> tag to the client domain path
app.jsCopy from references/app_template.jsReplace the STRATEGY constant with the client's data
charts.jsCopy from references/charts_template.jsUpdate market data array and selectedCount
style.cssCopy from references/style_reference.cssNo changes. Copy as-is.
Do not use webdev_init_project for strategy sites

Strategy sites are pure HTML/CSS/JS. They are not React apps. Do not use the Manus web scaffold. Write the four files directly into the client folder. Using the scaffold creates a React project that cannot be deployed to the seo-strategy-sites GitHub repo.

Writing Rules (Non-Negotiable)

opp-card Structure (Critical)

Every Additional Opportunities card must contain exactly 8 child divs in this order:

  1. opp-plan-label
  2. opp-price
  3. opp-combos-large
  4. opp-combos
  5. opp-headline
  6. opp-desc
  7. opp-new-market (use style="visibility:hidden" if no new markets are added)
  8. opp-kw-list

If any card has fewer than 8 children, the CSS subgrid alignment breaks for the entire row.

COMPLETION GATE

Before advancing to Step 8, confirm:

  • All four files exist in the client folder
  • style.css is an unmodified copy of the reference file
  • The STRATEGY constant in app.js contains all client data
  • No em dashes or en dashes in any user-visible text
  • All price fields are numeric values
  • All opp-cards have exactly 8 child divs
  • The base href in index.html matches the client domain path
NEXT STEP Step 8: Visual QA
Step 8 of 9

Visual QA

Render the site locally and verify every section before deploying. Do not deploy a site that has not been visually reviewed. Fixing errors after deployment is slower and riskier.

ENTRY CONDITION

Step 7 is complete. All four site files exist in the client folder. The site can be rendered locally via a Python HTTP server.

How to Run the Local Preview

cd /home/ubuntu/seo-strategy-repo
python3 -m http.server 8090
# Then navigate to http://localhost:8090/{clientdomain}/

What to Check

SectionWhat to Verify
Hero cardClient name, plan level text (colon format), combination count correct
Stat cardsNumbers match: combinations, keywords, markets
Market tableCorrect cities, correct populations, correct tier assignments, HQ city first
Bar chartAll selected markets highlighted, correct selectedCount
Keyword tableEach bucket is a separate group, base keyword is the first row, variants are indented, no cross-bucket nesting
MatrixCorrect orientation (cities as rows if 6+ markets), correct combination count, grand total row does not highlight on hover
Not Used cardsNo keyword appears in both the matrix and Not Used, every card has a reason
Opportunities cardsCorrect prices (from Plan Levels page), correct combination counts, each card has 8 child divs, card heights align horizontally
Mobile layoutResize browser to 375px width. All card grids should stack vertically.
COMPLETION GATE

Before advancing to Step 9, confirm every item in the table above has been visually verified. Do not rely on the data being correct. Look at the rendered output.

  • Hero section renders correctly with no formatting errors
  • All stat card numbers are accurate
  • Keyword table shows correct bucket groupings with no cross-bucket nesting
  • Matrix orientation is correct for the market count
  • Opportunities cards show correct prices from the Plan Levels table
  • Card grids align horizontally (subgrid working)
  • Mobile layout stacks cleanly
NEXT STEP Step 9: Deployment
Step 9 of 9

Deployment

Push the verified site to GitHub. Vercel auto-deploys within 1-2 minutes. Verify the live URL before delivering to the user.

ENTRY CONDITION

Step 8 is complete. The site has been visually reviewed locally and all QA items are confirmed.

Deployment Steps

  1. Pull latest from GitHub to avoid conflicts:
    cd /home/ubuntu/seo-strategy-repo && git pull origin main
  2. Add the client entry to the clients array in the root index.html
  3. Update the README.md client table
  4. Commit and push:
    git add .
    git commit -m "feat: Add [Client Name] SEO strategy site"
    git push origin main
  5. Wait 60-90 seconds for Vercel to deploy
  6. Navigate to https://seo-strategy.dotcomdesign.com/{clientdomain}/ and verify the live site renders correctly
GitHub repo and Vercel project

GitHub repo: https://github.com/dotcomdesigniowa/seo-strategy-sites. Vercel auto-deploys from the main branch. Do not manually trigger Vercel deployments. Push to GitHub and wait.

COMPLETION GATE

The strategy is complete when all of the following are true:

  • Live site renders correctly at seo-strategy.dotcomdesign.com/{clientdomain}/
  • Client entry added to root index.html
  • README.md updated
  • All changes committed and pushed to GitHub
WORKFLOW COMPLETE Strategy is live and ready to deliver to the client

Writing Rules

RuleWrongRight
No em dashes or en dashes"Level B adds two keywords — near me and showroom — across 5 markets.""Level B adds two keywords (near me and showroom) across 5 markets."
Plan hero uses colon"Plan Level A - 20 Keyword-City Combinations""Plan Level A: 20 Keyword-City Combinations"
Tier labels use colon"TIER 1 — PRIMARY MARKETS""TIER 1: PRIMARY MARKETS"

Data Type Rules

FieldWrong TypeCorrect TypeExample
priceStringNumber900 not "$900/mo"
new_marketStringBooleantrue not "true"
variant_typeMissingString"base", "near_me", or "variant"

CSS Subgrid Rules

All card grids use CSS Subgrid for horizontal alignment. The pattern is:

  1. Parent container defines grid-template-rows with one track per card element
  2. Each card uses grid-row: span N and grid-template-rows: subgrid
  3. At max-width: 900px, all cards fall back to display: flex; flex-direction: column; grid-row: span 1

The opp-card specifically uses 8 tracks and grid-row: span 8. If a card has fewer than 8 children, the subgrid breaks for the entire row.

Step 1

Including services not on the client website

What happened: "Cabinet makers" was included as a keyword for a retail showroom client. The term does not appear anywhere on the client's website and implies a manufacturing business model, not a retail showroom.

The rule: Only include services that are explicitly stated on the client's website. The website is the only source of truth.

Step 3

Grouping keywords with different core terms into the same bucket

What happened: "Bathroom vanity near me" was placed as a variant under the "bathroom cabinets" bucket. These are different products with different core terms and must be separate buckets.

The rule: A keyword is only a variant if it shares the exact same core term. Different words = different buckets.

Step 3

Missing base keyword causes incorrect rendering

What happened: Countertop keywords were placed in a bucket with no base keyword entry. The renderer lost its grouping anchor and nested all countertop keywords under the previous bucket (laundry room cabinets).

The rule: Every bucket must have a variant_type: "base" entry, even if the base term alone has low search volume and will not be selected.

Step 4

Arbitrary market selection

What happened: Issaquah (population 40,051) was selected while Renton (population 108,429) was skipped. There was no documented reason for this decision.

The rule: Markets are selected in strict top-down population order. The formula produces one correct answer. There is no judgment call.

Step 5

Selecting a lower-volume keyword when a higher-volume service line is available

What happened: "Kitchen cabinet showroom" (1,900/mo) was selected over "bathroom cabinets near me" (12,100/mo). The lower-volume keyword was for a service line already covered. The higher-volume keyword opened a new service line.

The rule: A lower-volume keyword for a distinct service line beats a higher-volume variant of an already-covered line.

Step 7

Invented plan prices

What happened: Plan prices in the Additional Opportunities section were invented from memory instead of read from the Plan Levels table. The prices were wrong.

The rule: Always read the Plan Levels table in this Playbook before writing any price into the strategy data. Never estimate or recall prices from memory.

Step 7

Wrong matrix orientation with 6+ markets

What happened: A strategy with 10 markets used keywords as rows and cities as columns. City names in column headers overlapped and became unreadable.

The rule: When markets is 6 or more, always use cities as rows and keywords as columns.

This checklist is interactive

Check each item as you verify it. Progress is shown at the top. The checklist resets when you navigate away.

0 / 30 complete

Data Accuracy

Keyword Structure

Combination Math

Pricing

Visual Layout

Writing Quality

Deployment