Getting found online

Run an on-page SEO audit of your own site with n8n

Most on-page problems are dull and mechanical: a missing description, a title Google cuts off, an image with no alt text. Finding them is a machine's job and fixing them takes ten minutes.

Build time
An afternoon
Difficulty
Intermediate
Template
8 nodes

What you need before you start

  • An n8n instance.
  • A sitemap at yoursite.co.uk/sitemap.xml. Almost every CMS produces one.
  • A Google Sheet.
  • No paid SEO tool. That is rather the point of this one.

There are two kinds of SEO problem. One needs a writer, a week and an argument about what the page is for. The other is a missing meta description.

This finds the second kind. All of it, every page, in about ninety seconds.

What it checks

Seven things, all of them unambiguous, all of them fixable in minutes once you know:

  • Title missing, or over about 60 characters
  • Meta description missing, over about 160 characters, or duplicated on another page
  • No <h1>, or more than one
  • Images with no alt attribute
  • Internal links that return anything other than a 200
  • Pages with fewer than 300 words of body text
  • Canonical tag missing, or pointing somewhere unexpected

None of that is judgement. Every one is either true or it is not, which is exactly what makes it worth handing to a machine.

The build, eight nodes

1. Schedule Trigger. Weekly. Sunday night is as good a time as any.

2. HTTP Request, called Sitemap. Fetch https://yoursite.co.uk/sitemap.xml.

If yours is a sitemap index pointing at other sitemaps, which most CMS platforms produce, you need one extra fetch. An IF node checking whether the XML contains <sitemapindex handles it, with the true branch fetching each child sitemap first.

3. XML node. Converts the response into something you can work with. n8n has this built in and it saves you writing a parser.

4. Split Out. Field urlset.url. One item per page.

5. HTTP Request, called Fetch Page. Get each URL. Response format: string, so you get the raw HTML rather than n8n trying to interpret it.

Turn on Continue on Fail, and set batching to about five requests with a short interval between batches. You are crawling your own server and it will cope, but there is no reason to hit it forty times a second, and if the site is on shared hosting there is a real reason not to.

6. Code node, called Checks. The whole audit, in one node. Regex against the HTML rather than a DOM parser, because for these seven checks it is quicker and there is nothing to install:

const html = $json.data || '';
const url = $json.loc;
const problems = [];

const title = (html.match(/<title[^>]*>([\s\S]*?)<\/title>/i) || [])[1] || '';
if (!title.trim()) problems.push('no title');
else if (title.length > 60) problems.push(`title ${title.length} chars`);

const desc = (html.match(
  /<meta[^>]+name=["']description["'][^>]*content=["']([^"']*)["']/i
) || [])[1] || '';
if (!desc.trim()) problems.push('no meta description');
else if (desc.length > 160) problems.push(`description ${desc.length} chars`);

const h1s = html.match(/<h1[\s>]/gi) || [];
if (h1s.length === 0) problems.push('no h1');
if (h1s.length > 1) problems.push(`${h1s.length} h1 tags`);

const imgs = html.match(/<img\b[^>]*>/gi) || [];
const noAlt = imgs.filter((t) => !/\salt\s*=/i.test(t));
if (noAlt.length) problems.push(`${noAlt.length} images without alt`);

const words = html
  .replace(/<script[\s\S]*?<\/script>/gi, ' ')
  .replace(/<style[\s\S]*?<\/style>/gi, ' ')
  .replace(/<[^>]+>/g, ' ')
  .split(/\s+/)
  .filter(Boolean).length;
if (words < 300) problems.push(`thin: ${words} words`);

if (!/rel=["']canonical["']/i.test(html)) problems.push('no canonical');

return [{ json: { url, title, desc, words, problems, count: problems.length } }];

One warning about that meta description regex. It only matches when the attributes appear in that order and are double or single quoted. Most templates output them consistently so it works, but a minifier that reorders attributes or strips quotes will make it find nothing, and a check that finds nothing looks exactly like a site with no problems. Test it against a page you know is broken before you believe a clean result.

We learned that one the hard way on this site, twice, on this exact check.

7. Filter. Keep only items where count is greater than zero. A sheet listing every page including the fine ones is a sheet nobody opens.

8. Google Sheets. Clear the sheet, then append. Clearing rather than appending matters here: this is a current state, not a log, and a fixed page should stop appearing rather than sitting there forever next to its own fix.

Reading the output

Sort by count descending and start at the top. A page with five problems is usually a page built from a broken template, and fixing the template fixes forty pages at once.

Then work through by type rather than by page. Doing every missing alt attribute in one sitting is faster than doing one page completely, because you stay in the same file and the same frame of mind.

The thin flag is the one to treat with suspicion. Under 300 words is a signal, not a verdict. A contact page is meant to be short, and so is a category page whose job is to point elsewhere. Look at the URL before you assume there is a problem.

It is the most useful check on the list and it doubles the build time, which is why it is not in the seven nodes above.

Pull every href starting with / or your own domain out of each page, deduplicate the lot, fetch each one with method HEAD, and record anything that does not come back 200. A HEAD request gets you the status without the body, so it is fast enough to run across a few hundred links.

What it finds is nearly always the same thing: a page renamed six months ago with four links still pointing at the old address. Nobody notices, because nobody clicks their own site’s links. Google does.

What it will not tell you

Whether the page deserves to rank.

Every check here is about whether the page is put together properly. That is table stakes rather than an advantage, and a technically perfect page about nothing anybody searches for will rank for nothing.

The useful way to think about it: this workflow removes reasons not to rank. Finding reasons to is a different job, and the content gap build is closer to it.

Published 28 August 2026. Written by the people who run this sort of thing for clients, on n8n, including our own lead pipeline.

Next in getting found online: One post, published out to everywhere. Or go back to all 4 in this category.

Questions about this build

How long should a title tag be?

Google truncates on pixel width rather than character count, and the practical limit lands around 55 to 60 characters for most fonts. Past that the end gets cut, which matters when the end is where your town or your service is. Treat 60 as an amber line rather than a rule, and check the ones that go past it rather than rewriting all of them.

What length should a meta description be?

Somewhere around 150 to 160 characters. Google rewrites descriptions much of the time regardless, so this is not the highest-value fix on the list, but a description cut off in the middle of a sentence looks careless in a result page and it costs nothing to shorten. We ran this check over our own site and found thirteen that were too long.

Can this replace a paid SEO tool?

For the mechanical checks on your own site, yes. Missing titles, duplicate descriptions, absent alt text, broken internal links and thin pages are all things you can find with an HTTP request and some string handling. What paid tools give you that this cannot is competitor data, keyword volume and backlink information, none of which live on your own pages.

How often should it run?

Weekly is plenty for a site that changes occasionally. What matters more than frequency is that it runs at all after a redesign, because that is when a template change silently strips the descriptions off forty pages at once.

Does it check whether the page is any good?

No, and nothing automated does. It finds what is measurable. Whether the page answers the question somebody typed is the thing that decides rankings, and no crawler has an opinion on it worth listening to.

The next step

Stop losing leads.Let's fix it this week.

Tell us what keeps slipping and we'll scope something around it. You'll be talking to Max, who runs the work, not a sales team. Most clients are live within 48–72 hours of that first conversation.

30-day rolling retainers. No lock-in. Cancel anytime.