SEO Audit Report: What to Include and What to Leave Out

16 min readUpdated

On this page 12 sections
  1. What the report is for
  2. Start with a scope block
  3. Label every finding with its layer
  4. Three places where layers get confused
  5. Record each finding the same way
  6. Rank findings without a health score
  7. What to leave out
  8. Order the report so page one decides
  9. Local clients need one more block
  10. Where a tool helps, and where it stops
  11. Rebuild your last report in an hour
  12. Common questions

Your audit report goes to a new client on Thursday. On Friday their developer answers in one line: the report says hundreds of pages have duplicate titles, and the CMS export shows a handful. You reopen the crawl and find that you were both right. Your crawler followed filter and tracking-parameter URLs, while the CMS export lists only the pages it publishes. Nothing in the report said what was crawled, with which settings, or on what day. The next call is now about the report instead of the website, and the findings that matter sit underneath the argument.

An SEO audit report is a set of claims about a site. Each one has to survive a developer, a skeptical owner and your own memory of what you did three weeks ago. This guide covers what belongs in the report, how to record evidence so that any finding can be re-checked quickly, how to rank findings without a vendor score, and what to cut so the important items stay visible.

Disclosure: I build Rankfinity, a rank tracker with a site audit, so I have an interest in how audit reports get written. Every rule or threshold below links to the page that publishes it, and I read each of those pages on 2026-10-08, so you can check the claims without trusting me.

Key takeaways. Treat every finding as a claim with a record behind it: what was measured, with which settings, on which day, and how to reproduce it. Open the report with a scope block. Label each finding with the layer it comes from, because what a crawler saw, what Google reports and what real visitors experienced are different sources. Rank findings by reach, consequence and effort instead of a vendor health score, and cut any finding you cannot describe as “fixing this changes X for Y URLs”.

Cover page of an SEO audit report with a scope block listing the domain, crawl date, crawler settings and number of URLs crawled

3jobs of the report: what is wrong, how you know, what first
9rows in the scope block
5layers a finding can rest on
3factors that rank a finding

What the report is for

The audit is the investigation. The report is what the client acts on, and it has three jobs: say what is wrong, show how you know, and decide what happens first. Anything that does none of those is decoration, and decoration is where readers stop reading.

It helps to separate this artifact from its neighbors. A monthly performance report tracks outcomes over time. A proposal sells work. An audit report is a point-in-time diagnosis with a baseline attached, which is why the section list in a typical website audit report template matters less than whether each section carries evidence a stranger could check. The crawl behind the report can come from any tool. Where I need an example of what a tool records, I use the Rankfinity site audit, because its documentation is public and I can link each claim to it.

Monthly report

Outcomes over time

Tracks results against a baseline.

Proposal

Sells work

Describes what you would do.

Audit report

A point in time diagnosis

Claims about a site, each with a record behind it, and a baseline attached.

Each claim has to survive a developer, a skeptical owner and your own memory of what you did three weeks ago.

Start with a scope block

The scope block is the part most reports skip, and it would have saved the Friday call. It states the conditions under which every number in the report was produced. Without it, a count of errors has no meaning, because the same site crawled with different settings returns different totals.

Field Why it changes the result What to write
Crawl dates Content and server behavior change between runs The day the crawl finished, plus the tool and its version
User agent Some sites answer different agents differently The agent string the crawler sent
JavaScript rendering Text added by scripts is invisible to a crawler that reads only HTML On or off, and the pages where it matters
Start URLs and rules Include and exclude patterns decide which URLs exist for the crawl The seed URLs and every pattern used
Parameter handling Filter and tracking parameters can multiply URLs Whether parameter URLs were followed or ignored
robots.txt A crawler that obeys it skips pages a person can still open Obeyed or ignored, and which sections it blocked
Limits A crawl that stops at its page cap is a sample, not the site The cap, and whether the crawl reached it
Search Console property A domain property and a URL-prefix property cover different URLs The property type and the date range used for clicks
Other sources Analytics, field speed data and server logs each have gaps Which were used and which were not available

Two rows deserve a closer look. A crawl that stops at its limit is a sample, so a report that says “hundreds of issues” without mentioning the cap understates the site. The Rankfinity site audit marks a crawl that hit its size or time limit as “Stopped early” (site audit documentation, checked 2026-10-08), and whatever tool you use should tell you the same thing. The second row is JavaScript. The same documentation warns that pages which show text only after scripts run “may look nearly empty” to its crawl. That is a limitation worth declaring, and the scope block is where you declare it.

SCOPE BLOCK · WHAT WOULD HAVE SAVED FRIDAY
Parameter URLsfollowed
Crawl limitcap not reached
JavaScript renderingoff
Duplicate titles, with parametershundreds
Duplicate titles, published pages onlya handful
Both numbers were truedifferent scope
Illustrative example, not a real site
Scope now covers AI crawlers too

Add one row for AI crawlers to the scope block: which search bots and training bots your robots.txt allows or blocks, and the date you last checked. The bot-by-bot list, with the role of each one and what a block does, is in Is Your Site Ready for AI Agents? The 2026 Checklist (20 Checks).

Label every finding with its layer

Three-layer diagram: what the crawler saw, what Google Search Console reports, and what real visitors experienced, with one example finding tagged to each layer

Most disputed findings are disputed because they mix sources. A crawler shows what a bot can reach and what each page says about itself. Google reports what it did with a URL. Field data shows how real visitors experienced a page, while lab data shows how one simulated load behaved. Outcomes show what changed for the business. Each layer answers a different question, and the report should say which one a finding rests on.

Layer Where it comes from What it can tell you Typical mistake
Crawl Your crawler’s requests and the parsed HTML What a bot can reach, what each URL returns and what its tags say Calling a page indexed because the crawl found no noindex tag
Google’s index Search Console Page indexing report and URL Inspection What Google did with the URL when it last looked Treating a crawl-only finding as proof that Google acted on it
Field data Real-user measurements such as the Chrome User Experience Report How the page behaved for actual visitors Describing visitors with lab numbers
Lab data A simulated load, such as Lighthouse How the page behaved on one device and one network profile Reporting a lab score as a Core Web Vitals verdict
Outcomes Search Console clicks, analytics, CRM What changed for the business Leaving this layer out, so no finding connects to a result

Take a service page that carries a noindex tag by mistake. The crawl shows the tag. The Page indexing report in Search Console, which “shows the Google indexing status of all URLs that Google knows about in your property” (Search Console Help, checked 2026-10-08), lists the URL as excluded, and its explanation says that when Google tried to index the page it “encountered a ‘noindex’ directive and therefore did not index it”. The URL’s clicks in the date range then show what the exclusion cost. Three layers tell one story, so the finding gets a crawl row, a Google row and an outcome row, and nobody has to take your word for it.

The split matters because a crawler can only report eligibility: a 200 response, no noindex, a canonical that points at the page itself. It cannot say the page is indexed. The status names in Google’s report show how fine the differences are. “Crawled – currently not indexed” is explained as “The page was crawled by Google but not indexed.” while “Discovered – currently not indexed” means “The page was found by Google, but not crawled yet.” They call for different fixes, and a crawl export cannot tell them apart.

  1. Crawl rowThe service page carries a noindex tag.
  2. Google rowSearch Console lists the URL as excluded because Google encountered a noindex directive.
  3. Outcome rowThe URL’s clicks over the date range show what the exclusion cost.
Three stacked rows for the same URL labelled crawl, Google and outcome. The first shows a noindex tag, the second an excluded status, the third a clicks line falling to zero
Three layers, one story: nobody has to take your word for it.

Three places where layers get confused

Indexed version versus live test

When a client says a page is fixed, ask which version they looked at. The URL Inspection tool reports on the “most recently indexed version of a page, not the live version on the web”, and its live test carries its own warning: “A positive result is not a guarantee that it will appear in Search results” (URL Inspection tool help, checked 2026-10-08). A fix can be live and still not be reflected in the indexed version for a while.

Blocked versus not indexed

These are separate states. Google’s documentation says a robots.txt file “is not a mechanism for keeping a web page out of Google” and points to noindex or password protection for that job (Google Search Central, checked 2026-10-08). If your report calls a page blocked, say what the evidence shows: the robots.txt rule that matched, or the index status Google reports. Do not use one word for both.

Lab data versus field data

Speed findings are where layers collide most often. Google’s guidance for Core Web Vitals is to aim for Largest Contentful Paint within the first 2.5 seconds, Interaction to Next Paint under 200 milliseconds and Cumulative Layout Shift under 0.1 (Core Web Vitals in Google Search, checked 2026-10-08). PageSpeed Insights then separates two kinds of data. Lab data is “useful for debugging issues” but “may not capture real-world bottlenecks”, while field data is “useful for capturing true, real-world user experience” (PageSpeed Insights documentation, checked 2026-10-08). A speed finding should therefore name its data source. A lab-only failure is a lead for the developer. Only field data is a statement about visitors.

Indexed vs live

Ask which version

A fix can be live and not yet reflected in the indexed version.

Blocked vs not indexed

Say what the evidence shows

The robots.txt rule that matched, or the index status Google reports. Never one word for both.

Lab vs field

Name the data source

A lab only failure is a lead for the developer. Only field data speaks for visitors.

2.5 sLargest Contentful Paint
200 msInteraction to Next Paint
0.1Cumulative Layout Shift
Fieldthe only data that describes visitors

Record each finding the same way

Finding card with fields for ID, layer, evidence, affected URLs, how to reproduce, owner and effort, filled in for a duplicate title example

Once the scope is stated, every finding gets one row in the same shape. The shape is what makes a report auditable, and it doubles as the audit report template many people search for. These are the fields I would want to see before believing a finding.

Field What to write Why it protects you
ID A stable code for the finding The client can cite it in a ticket and everyone knows which row it is
Finding One observable sentence, no adjectives “Product pages return a 302 to the trailing-slash URL” beats “bad redirects”
Layer Crawl, Google, field, lab or outcome Tells the reader how much weight the finding carries alone
Affected URLs The count, the number of URLs checked, and a link to the export A count without the number checked is not a measurement
Evidence The exact export, report name and column Shows the claim came from a record, not from memory
Reproduce The shortest steps to see it yourself A developer who can reproduce a finding in a minute rarely disputes it
Consequence What changes for crawling, indexing, rendering or visitors Separates a defect from a preference
Priority Reach, consequence and effort, each stated Makes the ordering arguable on its own terms
Owner and status Who acts, and whether it is open, in progress or verified Turns the report into a work list

The affected-versus-checked pair matters more than it looks. The Rankfinity documentation makes the same point: its error, warning and notice totals “are counts of failed checks, not of pages”, and each issue page shows pages affected next to pages checked (Rankfinity documentation, checked 2026-10-08). A report that quotes the first number without the second invites the wrong reading.

Add a “passes when” line to the top findings too. Rankfinity’s issue pages carry one, and the idea works anywhere: agree on the success condition before the work starts, and whether something is fixed stops being a matter of opinion. A re-crawl of the same URLs with the same settings then answers it.

Vague

“Bad redirects”

Nothing to reproduce, nothing to verify.

Observable

“Product pages return a 302 to the trailing-slash URL”

One sentence, no adjectives.

One finding, filled in (illustrative, not a real site)
  • ID: F-03
  • Finding: Product pages return a 302 to the trailing-slash URL
  • Layer: Crawl
  • Affected URLs: the count, the number of URLs checked, and a link to the export
  • Reproduce: request any product URL without the slash and read the status code
  • Passes when: the same crawl returns 301 or no redirect on those URLs

Rank findings without a health score

Composite scores are convenient and hard to defend. The weights belong to the vendor, the checks included change over time, and two tools give the same site two different numbers. The Rankfinity documentation says a health score can drop when nothing on the site changed, because “a new check may have been added” or “the crawl found pages it did not reach before” (same documentation page). That is honest behavior from a tool, and it is also the reason the number should not headline your report. Show it if the client expects it, define it in a footnote, and lead with affected counts.

Three factors are enough to order findings, and each can be stated with evidence. Reach is how many URLs the finding touches and how much search traffic they receive. Consequence is what changes if it is left alone. Effort is who has to do what. The consequence tier does most of the sorting.

Tier Test Typical findings
1. Blocks discovery or indexing Can Google fetch and index the page that should rank? Noindex on a page meant to rank, server errors on key URLs, redirect loops, a canonical pointing at a different page
2. Weakens how the page is understood or shown Does the page say what it is about, once? Missing or duplicate titles on money pages, orphaned pages with no internal links, duplicated copy
3. Housekeeping Would a visitor or Google notice? Oversized images, redirect chains on low-traffic URLs, cosmetic markup warnings

A tier two finding on the page that brings in most of a client’s leads can outrank a tier one finding on a retired section, which is why reach is its own field. In Rankfinity the Pages tab shows clicks and sessions beside each crawled URL when Search Console or Google Analytics is connected (crawl report documentation), and the same table can be built by joining a crawl export to a Search Console export on URL.

Finding A · tier 2

Duplicate titles on the page that brings in most leads

Reach: high. Consequence: weakens how the page is shown. Effort: one template change. Goes first.

Finding B · tier 1

Noindex on a retired section

Reach: almost none. Consequence: blocks indexing of pages nobody needs. Effort: low. Goes later.

Illustrative example, not a real site

This is why tiers alone are not enough. The consequence tier does most of the sorting, and reach decides the order inside and across tiers.

What to leave out

A report earns trust by what it declines to say. Cut every finding that fails the sentence test: “fixing this changes X for Y URLs”. If you cannot fill both blanks, the finding goes to an appendix or out.

Group repeats. Dozens of pages with the same missing description are one finding with a long export behind it, not dozens of findings. Drop issues on URLs nobody should land on, such as parameter variants that are already canonicalized, unless the canonicalization itself is the problem. Skip vendor authority scores unless the client asked for them, and label them as vendor estimates if they did. Above all, do not paste a tool’s full issue list into an appendix titled “Findings”. It swaps your judgment for volume, and the client will read the volume as the work.

GROUPING REPEATS
Pages missing a meta descriptionmany rows → 1 finding
Parameter variants already canonicaliseddropped
Redirect chains on retired URLsappendix
On page onethe few findings that decide the quarter
Illustrative example, not a real site

Order the report so page one decides

Section Contents Length
Summary The few findings that decide the next quarter, the decision you need from the client, and one line on scope One page
Scope and method The scope block from above Half a page
Findings One row per finding in the shared shape, grouped by consequence tier As long as the evidence needs
Action plan Owner, dependency and the passes-when line for each item One table
Baseline Positions, clicks and conversions as of the audit date One table
Appendix Raw exports, crawl configuration and a list of what was not checked Links, not pages

The baseline is easy to forget and expensive to lack. An audit with no starting measurements can say what was wrong but never what changed. Pull positions with the check settings stored, as organic rank tracking with the SERP record kept per check does, and if two sources disagree, the explanation is usually in the settings, which why two rank trackers show different positions walks through. For competitive context, name the sites that outrank the client on the baseline keywords; the competitors and share of voice view is built for that.

Skeleton of a report page by page: a one page summary, half a page of scope, findings grouped by tier, an action plan table, a baseline table and an appendix of links
Page one decides. Everything after it is evidence.

Put the baseline next to the audit

Branded client reports keep positions, clicks and the audit baseline in one document, so the next report starts from this one.

See client reportsDisclosure: this is our product

Local clients need one more block

Screenshot of a geo-grid scan for a local business with a legend, scan date and the business listing it was matched to

For a plumber or a dental clinic, a site audit explains only part of the picture. Add a block for map visibility with a scope of its own: the keyword, the grid size and spacing, the center point and the date. Each grid point is a separate map search from exact coordinates, and the business is matched by its Google place_id rather than by name, so a similarly named competitor never gets counted as the client. How to read the resulting patterns is covered on the geo-grid rank tracking page. Keep this block apart from the site findings. One measures the website, the other measures where the business appears on the map.

Where a tool helps, and where it stops

A crawler gives you the first layer quickly and keeps the history. The Rankfinity site audit lists the affected pages for each issue, exports them as CSV and compares any two crawls, so “what changed since the last audit” becomes a lookup (site audit documentation, checked 2026-10-08). It does not know which findings matter to this client, whether a flagged page is meant to rank, or whether a developer’s fix is acceptable. That judgment is your part of the job. When the results need to sit in a branded document next to rankings, branded client reports are built for that.

The crawler does

Fast, with history

  • Lists affected pages for each issue
  • Exports them as CSV
  • Compares any two crawls
Your part

Judgment

  • Which findings matter to this client
  • Whether a flagged page is meant to rank
  • Whether a developer’s fix is acceptable

Affected pages, pass conditions, crawl history

The Rankfinity site audit keeps a record per issue, so your next report can point to a record instead of a memory.

See the site auditDisclosure: this is our product

Rebuild your last report in an hour

  1. Write the scope blockDates, agent, rendering, rules, parameters, robots.txt, limits, property, other sources.
  2. Pick the ten findings that matterThe ones that decide the next quarter.
  3. Add a layer and a reproduce line to eachSo a developer can see it in a minute.
  4. Add a passes-when lineAgree the success condition before the work starts.
  5. Re-crawl with the same settings after the fixThe re-crawl answers whether it is fixed.

Common questions

How long should an SEO audit report be?

Long enough to hold the evidence and short enough that page one can be read in a few minutes. Put the decisions on the first page and move exports to an appendix. If the main body runs past what the client will read, the findings are probably not grouped or ranked tightly enough.

Should an SEO audit report include a health score?

Only with its definition. If the client expects one, show it with a note on which tool and settings produced it, and lead with affected URL counts. A score that can move when a tool adds a check is weak evidence of progress.

What is the difference between an SEO audit report and an SEO report?

An audit report is a point-in-time diagnosis with a baseline and a prioritized plan. An SEO report in the monthly sense tracks outcomes against that baseline over time. Build the audit so its baseline table becomes the first column of every report that follows.

Do I need a screenshot for every finding?

No. A reproduce line and an export cover most findings. Use a screenshot where the problem is visual, such as a rendered page missing its main content, and note the date and device.

How often should I re-run the audit?

Re-run the same crawl with the same settings after each significant release and before any meeting where you will claim progress. Changing settings between runs breaks the comparison, so record them in the scope block.

Next step: take the last audit report you sent and add a scope block plus a reproduce line to its ten most important findings. Then see how Rankfinity’s site audit records affected pages, pass conditions and crawl history for each issue, so your next report can point to a record instead of a memory.

← All articles

Keep reading

All articles →