Every Monday, checks the on-page SEO of a page you name and emails its score and what to fix, most important first.

UsesGmailGoogle PageSpeed InsightsOpenAI

Get a weekly SEO checkup of your key page by email

Every Monday morning, one page you name is put through Google's own on-page SEO checks as a mobile or desktop visitor: a title, a meta description, a crawlable page, descriptive link text, alt text on images, a readable font size and a viewport. The page itself is also read to count its H1, H2 and H3 headings, which no automated score covers. You get one email with the score and the number of fixes in the subject, the checks the page failed and why each matters, its heading structure, a list of what to fix first, and a link to the full report.

AI writes the list of fixes from those findings alone: it is told not to add checks that were not run, not to invent numbers, and not to talk about rankings, traffic or competitors. If the page cannot be scored at all, the run stops and nothing is emailed. If the site turns the check away, or no headings show up in the page source (some sites add them with JavaScript), the email says the headings could not be judged instead of telling you to add them.

You need a Google PageSpeed Insights connection (a free key from Google), an OpenAI connection and a Gmail connection. When you add it, you are asked for the page's address and the email address the checkup goes to.

ScheduleRun every Monday at 08:00.Run every Monday at 08:00.
ValuesSet pageUrl to blank.Set pageUrl to blank.
ValuesSet reportRecipient to blank.Set reportRecipient to blank.
ValuesSet deviceStrategy to mobile.Set deviceStrategy to mobile.
ValuesSet maxFindings to 20.Set maxFindings to 20.
TextTrim pageUrl and save it as auditUrl.Trim pageUrl and save it as auditUrl.
TextTrim reportRecipient and save it as sendTo.Trim reportRecipient and save it as sendTo.
TextMake deviceStrategy lowercase and save it as device.Make deviceStrategy lowercase and save it as device.
Decisions & LoopsIf not auditUrl is a valid web addressIf not auditUrl is a valid web address
Yes
Decisions & LoopsStop and report a problem: The 'pageUrl' step is not a full web address. It has to start with https:// or http:// - for example https://example.com/pricing.Stop and report a problem: The 'pageUrl' step is not a full web address. It has to start with https:// or http:// - for example https://example.com/pricing.
No
No steps
Decisions & LoopsIf not sendTo is a valid email addressIf not sendTo is a valid email address
Yes
Decisions & LoopsStop and report a problem: The 'reportRecipient' step is not a valid email address, so there is nowhere to send the audit.Stop and report a problem: The 'reportRecipient' step is not a valid email address, so there is nowhere to send the audit.
No
No steps
Decisions & LoopsIf mobile desktop doesn't contain deviceIf mobile desktop doesn't contain device
Yes
Decisions & LoopsStop and report a problem: The 'deviceStrategy' step has to be either mobile or desktop. Mobile is what Google uses for search.Stop and report a problem: The 'deviceStrategy' step has to be either mobile or desktop. Mobile is what Google uses for search.
No
No steps
Google PageSpeed InsightsGoogle PageSpeed InsightsAnalyze auditUrl with PageSpeed Insights. Save it as report.Analyze auditUrl with PageSpeed Insights. Save it as report.
TextTrim report.scores.seo and save it as seoScore.Trim report.scores.seo and save it as seoScore.
Decisions & LoopsIf seoScore is null or seoScore is emptyIf seoScore is null or seoScore is empty
Yes
Decisions & LoopsStop and report a problem: No on-page SEO score came back for this page, so there is nothing to report and nothing has been emailed. Check the address in 'pageUrl' is publicly reachable, then run it again.Stop and report a problem: No on-page SEO score came back for this page, so there is nothing to report and nothing has been emailed. Check the address in 'pageUrl' is publicly reachable, then run it again.
No
No steps
ValuesSet auditedAddress to auditUrl.Set auditedAddress to auditUrl.
TextTrim report.url and save it as finalUrl.Trim report.url and save it as finalUrl.
Decisions & LoopsIf finalUrl isn't empty and finalUrl is not nullIf finalUrl isn't empty and finalUrl is not null
Yes
ValuesChange auditedAddress to finalUrl.Change auditedAddress to finalUrl.
No
No steps
TextTrim report.report_url and save it as reportLink.Trim report.report_url and save it as reportLink.
Decisions & LoopsIf reportLink is null or reportLink is emptyIf reportLink is null or reportLink is empty
Yes
ValuesChange reportLink to not available for this run.Change reportLink to not available for this run.
No
No steps
TextTrim report.analyzed_at and save it as checkedOn.Trim report.analyzed_at and save it as checkedOn.
Decisions & LoopsIf checkedOn is null or checkedOn is emptyIf checkedOn is null or checkedOn is empty
Yes
ValuesChange checkedOn to not reported.Change checkedOn to not reported.
No
Dates & TimesMake checkedOn readable as “Monday, November 2, 2026” and save it as checkedOn.Make checkedOn readable as “Monday, November 2, 2026” and save it as checkedOn.
ValuesSet findings to an empty list.Set findings to an empty list.
ValuesSet findingCount to 0.Set findingCount to 0.
Decisions & LoopsFor each audit in report.failed_audits:For each audit in report.failed_audits:
TextTrim audit.category and save it as auditCategory.Trim audit.category and save it as auditCategory.
Decisions & LoopsIf auditCategory is not seoIf auditCategory is not seo
Yes
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
Decisions & LoopsIf findingCount is greater than or equal to maxFindings multiplied by 1If findingCount is greater than or equal to maxFindings multiplied by 1
Yes
Decisions & LoopsStop repeating.Stop repeating.
No
No steps
TextReplace ` with in audit.title and save it as auditTitle.Replace ` with in audit.title and save it as auditTitle.
Decisions & LoopsIf auditTitle is empty or auditTitle is nullIf auditTitle is empty or auditTitle is null
Yes
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
ValuesSet findingLine to - auditTitle.Set findingLine to - auditTitle.
TextTrim audit.display_value and save it as auditDetail.Trim audit.display_value and save it as auditDetail.
Decisions & LoopsIf auditDetail isn't empty and auditDetail is not nullIf auditDetail isn't empty and auditDetail is not null
Yes
ValuesChange findingLine to findingLine (auditDetail).Change findingLine to findingLine (auditDetail).
No
No steps
TextReplace the pattern \[([^\]]+)\]\(([^)\s]+)\) with $1 ($2) in audit.description and save it as auditWhy.Replace the pattern \[([^\]]+)\]\(([^)\s]+)\) with $1 ($2) in audit.description and save it as auditWhy.
TextReplace ` with in auditWhy and save it as auditWhy.Replace ` with in auditWhy and save it as auditWhy.
Decisions & LoopsIf auditWhy isn't empty and auditWhy is not nullIf auditWhy isn't empty and auditWhy is not null
Yes
ValuesChange findingLine to findingLineChange findingLine to findingLine Why it matters: auditWhy.
No
No steps
ListsAdd findingLine to the end of findings and save it as findings.Add findingLine to the end of findings and save it as findings.
ValuesAdd 1 to findingCount.Add 1 to findingCount.
ValuesSet failedText to None - every on-page check in this audit passed..Set failedText to None - every on-page check in this audit passed..
Decisions & LoopsIf findingCount is greater than 0If findingCount is greater than 0
Yes
TextJoin findings with a new line and save it as failedText.Join findings with a new line and save it as failedText.
No
No steps
ValuesSet pageHtml to blank.Set pageHtml to blank.
ValuesSet structureText to The page source could not be read from this workflow, so its heading structure was not checked..Set structureText to The page source could not be read from this workflow, so its heading structure was not checked..
ValuesSet headingFixes to 0.Set headingFixes to 0.
Decisions & LoopsIf a step below fails, save the error as fetchErrorIf a step below fails, save the error as fetchError
Try
HTTPFetch auditUrl and save it as pageFetch.Fetch auditUrl and save it as pageFetch.
Decisions & LoopsIf pageFetch.ok is yesIf pageFetch.ok is yes
Yes
ValuesChange pageHtml to pageFetch.body.Change pageHtml to pageFetch.body.
No
TextBuild the text The site answered this workflow with status @pageFetch.status instead of the page (some sites turn away automated visitors), so its heading structure was not c... and save it as structureText.Build the text The site answered this workflow with status @pageFetch.status instead of the page (some sites turn away automated visitors), so its heading structure was not c... and save it as structureText.
On error
TextBuild the text The page could not be downloaded by this workflow (@fetchError.message), so its heading structure was not checked. and save it as structureText.Build the text The page could not be downloaded by this workflow (@fetchError.message), so its heading structure was not checked. and save it as structureText.
Decisions & LoopsIf the length of pageHtml is greater than or equal to 400If the length of pageHtml is greater than or equal to 400
Yes
TextMake pageHtml lowercase and save it as htmlLower.Make pageHtml lowercase and save it as htmlLower.
MathSet h1Count to the length of htmlLower split by <h1 minus 1.Set h1Count to the length of htmlLower split by <h1 minus 1.
MathSet h2Count to the length of htmlLower split by <h2 minus 1.Set h2Count to the length of htmlLower split by <h2 minus 1.
MathSet h3Count to the length of htmlLower split by <h3 minus 1.Set h3Count to the length of htmlLower split by <h3 minus 1.
Decisions & LoopsIf h1Count plus h2Count plus h3Count is 0If h1Count plus h2Count plus h3Count is 0
Yes
ValuesChange structureText to No H1, H2 or H3 headings were found in the page source. They may be added by JavaScript after the page loads, or the site may have shown this check a different page, so the heading structure could not be judged. Open the page and check its headings yourself..Change structureText to No H1, H2 or H3 headings were found in the page source. They may be added by JavaScript after the page loads, or the site may have shown this check a different page, so the heading structure could not be judged. Open the page and check its headings yourself..
No
ValuesSet structureLines to an empty list.Set structureLines to an empty list.
ListsAdd - Headings found: H1 h1Count as text, H2 h2Count as text, H3 h3Count as text to the end of structureLines and save it as structureLines.Add - Headings found: H1 h1Count as text, H2 h2Count as text, H3 h3Count as text to the end of structureLines and save it as structureLines.
Decisions & LoopsIf h1Count is 0If h1Count is 0
Yes
ListsAdd - There is no H1 on the page. Give it one heading that states what the page is about. to the end of structureLines and save it as structureLines.Add - There is no H1 on the page. Give it one heading that states what the page is about. to the end of structureLines and save it as structureLines.
ValuesAdd 1 to headingFixes.Add 1 to headingFixes.
No
No steps
Decisions & LoopsIf h1Count is greater than 1If h1Count is greater than 1
Yes
ListsAdd - The page has more than one H1. Keep one, and demote the rest to H2. to the end of structureLines and save it as structureLines.Add - The page has more than one H1. Keep one, and demote the rest to H2. to the end of structureLines and save it as structureLines.
ValuesAdd 1 to headingFixes.Add 1 to headingFixes.
No
No steps
Decisions & LoopsIf h2Count is 0If h2Count is 0
Yes
ListsAdd - There are no H2 subheadings, so the page has no visible structure under its title. Break the content into sections. to the end of structureLines and save it as structureLines.Add - There are no H2 subheadings, so the page has no visible structure under its title. Break the content into sections. to the end of structureLines and save it as structureLines.
ValuesAdd 1 to headingFixes.Add 1 to headingFixes.
No
No steps
TextJoin structureLines with a new line and save it as structureText.Join structureLines with a new line and save it as structureText.
No
No steps
ValuesSet auditPrompt to:Set auditPrompt to:You are an SEO specialist writing to the owner of one web page. Below is everything an automated on-page audit of that page found. Write a short, prioritised list of what to fix, most important first, in plain sentences a non-specialist can act on. Say what to change and where. Rules you must follow: - Use ONLY the findings below. Do not add checks that are not listed. - Do not mention search rankings, traffic, competitors or keywords - none of that was measured here. - Do not invent any number, page title or wording that does not appear below. - If the heading structure says it was not che...
ValuesChange auditPrompt to auditPromptChange auditPrompt to auditPrompt Page audited: auditedAddress On-page SEO score out of 100: seoScore.
ValuesChange auditPrompt to auditPromptChange auditPrompt to auditPrompt Failed on-page checks: failedText.
ValuesChange auditPrompt to auditPromptChange auditPrompt to auditPrompt Heading structure: structureText.
ValuesSet advice to blank.Set advice to blank.
Decisions & LoopsIf a step below fails, save the error as adviceErrorIf a step below fails, save the error as adviceError
Try
OpenAIOpenAIAsk OpenAI: auditPrompt. Save it as answer.Ask OpenAI: auditPrompt. Save it as answer.
TextTrim answer.response_text and save it as answerText.Trim answer.response_text and save it as answerText.
Decisions & LoopsIf answerText isn't empty and answerText is not nullIf answerText isn't empty and answerText is not null
Yes
ValuesChange advice to answerText.Change advice to answerText.
No
No steps
On error
ValuesShow in the output: Could not write the recommendations for this audit: adviceError as text.Show in the output: Could not write the recommendations for this audit: adviceError as text.
Decisions & LoopsIf advice is emptyIf advice is empty
Yes
ValuesChange advice to No written recommendations were produced this run - the checks listed above are the audit..Change advice to No written recommendations were produced this run - the checks listed above are the audit..
No
No steps
ValuesSet bodyLines to an empty list.Set bodyLines to an empty list.
ListsAdd On-page SEO audit for auditedAddress to the end of bodyLines and save it as bodyLines.Add On-page SEO audit for auditedAddress to the end of bodyLines and save it as bodyLines.
ListsAdd Checked on checkedOn as a device visitor. to the end of bodyLines and save it as bodyLines.Add Checked on checkedOn as a device visitor. to the end of bodyLines and save it as bodyLines.
ListsAdd Add On-page SEO score: seoScore out of 100 to the end of bodyLines and save it as bodyLines.
ListsAdd Add Failed on-page checks failedText to the end of bodyLines and save it as bodyLines.
ListsAdd Add Heading structure structureText to the end of bodyLines and save it as bodyLines.
ListsAdd Add What to fix first advice to the end of bodyLines and save it as bodyLines.
ListsAdd Add Full technical report: reportLink to the end of bodyLines and save it as bodyLines.
TextJoin bodyLines with a new line and save it as emailBody.Join bodyLines with a new line and save it as emailBody.
MathSet fixCount to findingCount plus headingFixes.Set fixCount to findingCount plus headingFixes.
ValuesSet fixSummary to fixCount fixes.Set fixSummary to fixCount fixes.
Decisions & LoopsIf fixCount is 0If fixCount is 0
Yes
ValuesChange fixSummary to nothing to fix.Change fixSummary to nothing to fix.
Else if @fixCount is 1
ValuesChange fixSummary to 1 fix.Change fixSummary to 1 fix.
Otherwise
No steps
TextReplace the pattern ^https?://(www\.)?|/$ with in auditedAddress and save it as pageLabel.Replace the pattern ^https?://(www\.)?|/$ with in auditedAddress and save it as pageLabel.
GmailGmailSend an email to sendTo.Send an email to sendTo. Subject: SEO seoScore/100 · fixSummary for pageLabelemailBody