How-to · Planning & Data

How to Build a Page Matrix Before You Generate 500 Pages

Plan programmatic SEO pages by mapping dimensions, source evidence, URLs, intent, and parent relationships before generation.

A programmatic SEO project can look perfectly organized right up until the moment the generator creates 500 URLs. The keyword research is grouped. The template is approved. The spreadsheet has columns.

Then someone notices that two rows produce the same URL, a service is not actually offered in one location, half the child pages have no parent, or the only difference between pages is the city name.

A page matrix is where those problems should become visible.

It is the row-level model of the pages you intend to create. Each row should answer more than “which keyword goes here?” It should show what page would exist, why it deserves to exist, what data supports it, where it belongs in the site, and whether the combination is valid enough to move forward.

That makes the matrix a planning artifact, not just a generator input.

A page matrix is not a keyword list

A keyword list answers questions about demand and language:

  • What queries exist?
  • Which modifiers recur?
  • Which terms appear to share intent?
  • Which dimensions might be useful, such as service, location, product, integration, or industry?

That is necessary research, but it does not decide the site architecture.

Suppose your keyword research contains:

  • drain cleaning austin
  • drain cleaning dallas
  • water heater repair austin
  • water heater repair dallas

A keyword list can suggest a service × city pattern. It cannot prove that all four pages should exist. Maybe the business does not offer water-heater repair in Dallas. Maybe the Dallas query is already served by a strong existing page.

Maybe the only available data for Austin and Dallas is the city name, so the finished pages would say essentially the same thing.

The page matrix converts a keyword pattern into page decisions. One keyword can map to no page, one page, or a section of a broader page. Conversely, one page can serve several closely related keyword variants.

If you want the shorter definition, see the page matrix glossary entry. The important operational point is that a matrix is where demand meets eligibility, evidence, URLs, and site structure.

A page matrix is not a template either

A template describes how a page renders. It might contain patterns such as:

URL: /services/{{service|slug}}/{{city|slug}}/
Title: {{service|title}} in {{city}} | Northstar
H1: {{service|title}} in {{city}}
Body: {{local_constraint}} {{response_window}} {{proof_point}}

That template can be perfectly valid and still produce a terrible page set.

The template does not know whether water heater repair × Dallas is a legitimate combination. It does not know whether local_constraint is blank on 40% of rows. It does not know whether two services collapse to the same slug. It does not know whether every city page is attached to the right hub.

The matrix supplies those answers row by row.

A useful distinction is:

Artifact Main question it answers
Keyword list What searches and patterns exist?
Template How will one page be rendered?
Page matrix Which concrete pages should exist, and what supports each one?
Page plan What is the full pre-publish set, including review decisions and relationships?

In a small project the page matrix and page plan may be nearly identical. At larger scale, the matrix is often the structured construction layer that feeds a broader plan containing audit decisions, live-site collisions, publishing state, and later operational history.

Start by defining the row contract

Do not begin with 40 spreadsheet columns. Begin with the decisions one row must support.

For most programmatic landing-page families, a reviewable row needs five groups of fields.

1. Page identity

Record the dimensions and intent that make the row a candidate page.

Typical fields include:

  • entity_id
  • city
  • service
  • target_keyword
  • page_intent
  • template_id

A row should have a stable identity that does not depend on the final prose. “Austin + drain cleaning + local service intent” is an identity. A title string is not.

2. URL and hierarchy

Record the proposed URL and where the page belongs.

Useful fields include:

  • url
  • slug
  • parent_url
  • canonical
  • indexable

The URL is not just output formatting. It is part of the page model. If two rows render the same normalized URL, the conflict should be resolved before a CMS sees either one.

The same applies to hierarchy. A child page with parent_url=/services/drain-cleaning/ makes an explicit structural claim.

In pSEO Guard, a valid parent URL that is missing from the submitted page set is a Review condition rather than something silently assumed. The URL hierarchy documentation explains that relationship in more detail.

3. Source fields

Keep the facts used to render or validate the page beside the row.

For a hypothetical home-services matrix, that might include:

  • service_available
  • response_window
  • coverage_note
  • local_constraint
  • proof_point
  • source_record_id
  • source_updated_at

Not every source field needs to appear in copy. Some exist to decide whether the page is eligible at all. The source field is the traceable input; a template variable is only the placeholder that may use it.

4. Rendered page fields

The matrix should make the important output inspectable before publishing:

  • url
  • title
  • h1
  • meta_description
  • target_keyword
  • content_text or a representative body
  • parent_url

This is where you catch a matrix that looks diverse in source data but renders repetitive pages.

5. Decision fields

Finally, make review explicit:

  • eligible
  • decision
  • decision_reason
  • owner or reviewer
  • notes

You do not need the final production workflow at this stage. You do need a place to say “exclude this row because the service is unavailable” instead of deleting it from the spreadsheet and forgetting why.

Build dimensions, then test whether the cross-product is real

Dimensions are the axes you combine: city × service, industry × integration, product × use case, and so on.

The arithmetic is easy. Three services across 20 cities produce 60 combinations. The dangerous assumption is that 60 combinations automatically mean 60 valid pages.

A Cartesian product is only a candidate set.

Before accepting a dimension pair, ask:

  1. Is the combination possible in the real business or dataset?
  2. Does it represent a distinct user need?
  3. Can the row supply the facts needed to answer that need?
  4. Can it produce a stable URL without colliding with another row?
  5. Does it have a sensible parent or hub?

Here is a deliberately small example for a hypothetical service business:

city service target intent service_available page evidence proposed URL parent decision
Austin Drain cleaning local drain cleaning true Austin coverage + response window /services/drain-cleaning/austin/ /services/drain-cleaning/ Keep
Dallas Drain cleaning local drain cleaning true Dallas coverage + response window /services/drain-cleaning/dallas/ /services/drain-cleaning/ Keep
Austin Water heater repair local water-heater repair true Austin availability + service constraint /services/water-heater-repair/austin/ /services/water-heater-repair/ Keep
Dallas Water heater repair local water-heater repair false None /services/water-heater-repair/dallas/ /services/water-heater-repair/ Exclude

The fourth row is not “missing content to write later.” Its own source data says the combination is invalid. Generating it would manufacture a page first and ask whether the business can satisfy the query second, which is backwards in a rather impressively scalable way.

A matrix should preserve invalid rows long enough to explain their exclusion, then keep them out of generation.

Decide which fields are allowed to shape the URL

A stable URL should usually be derived from fields that define page identity, not fields that merely decorate or update the answer.

Good URL inputs tend to be stable identifiers:

  • service slug
  • city slug
  • product slug
  • integration slug
  • category key

Poor URL inputs tend to be volatile facts:

  • current price
  • inventory count
  • response time
  • rating
  • year, unless the page genuinely has year-specific intent

If a field can change next Tuesday without changing which page the user should land on, it probably should not be part of the URL.

Also separate hierarchy from canonicalization. parent_url says where a page belongs. canonical says which URL should be treated as the representative version when consolidation is intended. They solve different problems.

Google’s own canonicalization documentation explains that pages with the same or very similar primary content can be clustered, even when they have different URLs. A unique path therefore does not prove you created a unique page.

Make every row prove independent value

The most important matrix question is not “is this URL unique?” It is:

If I remove the entity name, what remains that changes the answer for this page?

If the Austin page and Dallas page become interchangeable after you replace the city name, you have identified two labels, not two useful answers.

Independent value can come from many kinds of evidence:

  • eligibility or availability
  • local rules or constraints
  • product attributes
  • compatibility details
  • pricing inputs
  • inventory or coverage
  • original measurements
  • customer or location proof
  • different workflows, requirements, or outcomes
  • relationships to other entities

There is no reliable universal rule such as “30% unique content is safe.” Google does not publish a magic uniqueness percentage. Its spam policies focus on whether scaled pages are created primarily to manipulate rankings and provide little or no value to users, while canonicalization is based on how similar the actual primary content is.

For planning, that means a percentage is a weak substitute for a better question: does this row have enough specific evidence to answer something its siblings cannot?

Find invalid combinations before you generate anything

An invalid combination is broader than a missing cell.

Common reasons to exclude or stop a row include:

  • The product, service, integration, or location is not actually available.
  • Two dimension values describe the same intent and should be one page.
  • The row renders a duplicate URL.
  • A field required by the URL or core answer is missing.
  • The template references a field that does not exist.
  • The row has no page-specific evidence beyond the entity name.
  • The intended parent does not exist in the plan.
  • The combination creates a page that is logically nonsensical, such as a feature that does not apply to that product.
  • A proposed page collides with an existing page that already serves the same purpose.

The last case requires evidence outside the matrix. After the internal plan is coherent, run the proposed rows through the free pSEO Audit and, when relevant, compare them with the existing site. The goal is not to collect more warning badges. It is to decide whether each row should be created, merged, renamed, differentiated, or excluded.

Review the matrix as a set, not row by row

A matrix is valuable because it lets you inspect the family.

Review it in several passes:

Count the combinations. If the dimensions imply 600 pages, make sure you can explain why there are 600 user needs rather than merely explaining the multiplication.

Group by intent. Sort or pivot on target_keyword, page_intent, service, category, or another semantic key. Look for rows that are cosmetically different but answer the same question.

Group by URL pattern. Check duplicates, empty path segments, unstable slugs, and cases where different source values normalize to the same slug.

Inspect evidence coverage. For every required evidence field, count blanks and suspicious defaults. “N/A” repeated across 200 rows is not evidence. It is a spreadsheet trying to look occupied.

Inspect parents. Make sure hubs exist, children point to the intended parent, and the hierarchy is browseable rather than a flat pile of search-entry pages.

Render representative pages. Review at least one normal row and the edge cases: longest values, shortest values, optional-field gaps, unusual characters, invalid combinations, and any row whose evidence came from a different source.

pSEO Guard’s Page Matrix Generator supports both dimension input and a one-row-per-page data table. It renders the planned URL, title, H1, metadata, target keyword, and body fields, and runs the same audit used for imported page plans.

The export also preserves source columns. That makes the tool useful for checking the model while it is still cheap to change.

Validate a small batch before expanding the matrix

Do not make the first real test the full 500-page batch.

Start with a deliberately small, representative slice. The exact number is not an SEO threshold. Coverage matters more than count. Include:

  • at least one row from every important dimension combination
  • a page with the richest evidence
  • a page with the thinnest legitimate evidence
  • rows with optional fields missing
  • the longest and shortest slugs
  • a child from each parent family
  • at least one combination you expect to reject

Render those pages. Read them. Run the audit. Check the URLs and hierarchy. If you already have a site, compare them with live pages.

Then fix the model, not the individual sample page.

If five sample pages reveal that local_constraint is missing across one entire service family, the answer is not to hand-write five paragraphs. Fix the source contract or stop that family from generating. If two service values collapse into one intent, merge the dimension values before scale multiplies the collision.

Once the representative batch survives review, expand the same matrix and repeat the set-level checks.

That is the real job of a page matrix: not to help a generator reach 500 pages faster, but to make sure the logic is still defensible when it does.

Make the rows visible before the CMS does.

Use dimensions or a data table, generate the page set, audit it locally, and export the matrix with its source evidence.

Build your page matrix →

Continue with

Related resources

Related terms