# SEO Automation Guide 2026: API Limits and a Python Script

> SEO automation guide: which SEO tasks to automate and which to keep manual, the Google API limits that cap you, and a Python alert script you can copy.

- URL: https://missiongrowth.io/blog/seo-automation
- Published: 2026-11-08
- Author: Furkan Aktaş, Co-Founder, Mission Growth
- Publisher: Mission Growth. Company facts: https://missiongrowth.io/llms.txt

SEO automation is the use of scripts, workflow builders and AI to run repetitive search tasks on a schedule. The part worth automating is the part a script can verify against something measurable.

Most advice stops at "automate what's repetitive". That rule fails the first time a repetitive job, such as rewriting meta descriptions across a CMS, produces output nobody can check. So this guide uses a sharper test, then shows what Google's own APIs allow a job to do each day.

This SEO automation tutorial ends with a first job you can run. If you want to automate SEO tasks without a mess to clean up, the test comes first.

In this guide:

- **The tier rule:** which of 9 common SEO tasks run unattended, which alert you, and which stay drafts.
- **Google's API limits:** the daily and per-minute caps that size any job.
- **A copyable Python script:** a Search Console alert for pages that lost clicks.
- **What to review:** the outputs Google's guidance puts in front of a person.

The short answer to "what is SEO automation?" in practice: automate what a script can check, and put a person in front of what it can't.

## What is SEO automation, and which tasks qualify?

SEO automation is scripts, workflow tools and AI taking over repetitive search tasks without anyone starting each run, and a task qualifies only when a script can verify its output.

It pays off in two ways. A script applies consistent rules to every URL, so the last page gets the same check as the first. And it works at scale a person can't check by hand.

Neither benefit survives output you can't verify. That gives one rule: a task runs unattended only when a script can compare the result with something measurable, like a status code, a canonical tag or a validator result. If no such check exists, the output is a draft, whatever the task is.

Can a script verify it? That single question sorts the work. Reversibility and the full keep-human list belong to the AI agent discussion, so this guide only adds the verifier. The same rule applies to SEO automation AI features: clustering and drafting sit in the draft tiers because the model can't check its own output.

### The four tiers

The table sorts nine tasks by that one criterion, with internal links split into inject and suggest rows. The tiers are run unattended, run and alert, draft for review, and keep human.

| Task | Input data | What verifies the output | Tier |
|---|---|---|---|
| Rank and click reporting | Search Console rows | Totals reconcile with the source report | Run unattended |
| Technical audit | Crawl of your own URLs | Status codes, canonicals and schema validity | Run and alert |
| Internal links: inject | Link graph plus target pages | Target returns 200, is self-canonical and indexable | Run and alert, with a rollback list |
| Internal links: suggest | Page text and a topic map | Nothing checks relevance | Draft for review |
| Keyword clustering | Keyword list and volumes | No ground truth exists; a person samples the groups | Draft for review |
| Content briefs | SERP and page data | A person reads the brief against the intent | Draft for review |
| First-draft articles | Brief plus sources | A person fact-checks every claim | Draft for review |
| Title and meta rewrites | Current tags plus page content | A script checks length and duplicates; a person reads them | Draft for review |
| Link outreach and digital PR | Prospect lists | The output is a relationship, and no check can score it | Keep human |
| Strategy and priorities | Business goals, market data | No script can test whether a priority is right | Keep human |

Read the table by tier. Reporting runs unattended because the data is Google's own and the output reconciles. Audits and link injection run, but they alert you, since a wrong result lands on live pages. Clustering, briefs, drafts and tag rewrites come back as a draft for review. Outreach and strategy stay with a person because nothing can check them.

Two rows deserve a closer look. Clustering looks like the perfect automation target, but a cluster has no right answer to compare against, so you sample it before anyone acts on it. And injecting links is a different job from suggesting them: the script verifies the target page before writing the link, which is the check your [internal linking strategy](https://missiongrowth.io/blog/internal-linking-strategy) should already assume.

For the reporting row, the data source's limits matter more than the template, and the [SEO reporting](https://missiongrowth.io/blog/seo-reporting) guide covers the template side. The next section covers the limits.

## SEO automation limits: what Google's APIs let you automate

Google's Search Console and Indexing APIs cap how much a job can check or submit per day, so quotas size an automation before tool features do.

The quota table below shows the numbers from [Google's Search Console limits page](https://developers.google.com/webmaster-tools/limits) and the Indexing API quota documentation. Check the live page before you size a job.

| API and method | Limit | Scope |
|---|---|---|
| Search Analytics | 1,200 queries per minute | Per site |
| URL Inspection API | 2,000 queries per day | Per site |
| URL Inspection API | 600 queries per minute | Per site |
| Indexing API publish | 200 requests per day by default | Per project |

The rows are different operations with different scopes, so don't compare them as a ratio. A per-project publish quota and a per-site inspection quota answer different questions.

One more cap sits outside the table. Beyond the usage quota, the Search Analytics method exposes at most 50K rows per day per search type. A site with more pages than that gets truncated page rows, which is why the script later in this guide stops when it hits the ceiling.

The arithmetic is where the quotas bite. The URL Inspection API allows 2,000 queries per day per site at 600 per minute, so a job running at full speed spends the whole day's allowance in 3.3 minutes (2,000 divided by 600). A 10,000-URL site, as an example, needs 5 days for one full pass (10,000 divided by 2,000).

So inspect from a priority list instead of walking the sitemap. Spend inspection quota on newly published and recently changed URLs, plus a rotating slice of the rest. A full sweep of a large site is a weekly project that no nightly job can finish. The same quota math applies to any automated [SEO audit process](https://missiongrowth.io/blog/how-to-do-seo-audit) that calls the inspection endpoint.

### Why the Indexing API is not an auto-submit button

The Indexing API cannot submit ordinary new pages.

Google's documentation says it [can only be used to crawl pages](https://developers.google.com/search/apis/indexing-api/v3/using-api) with either JobPosting or BroadcastEvent embedded in a VideoObject markup.

Its default is 200 publish requests per day, and that quota belongs to the project. A blog, a store or a SaaS site without those two markups has nothing eligible to submit. Don't build a "publish, then ping Google" step around it.

## SEO automation example: a traffic-decliner alert in Python

A traffic-decliner alert compares clicks by page across two complete 28-day windows of finalized data that end three days ago, and flags pages that lost 30% or more.

This job is a good first build for three reasons. The data is Google's own, the output is a list, and nothing live changes. A wrong alert costs you a short look, never a broken page.

The script is an SEO automation Python pattern, offered as a starting point. It isn't something we ran against a client site.

As an SEO automation workflow it has three stages: fetch two windows, check the data, report. Setup takes four steps:

1. Create a service account in Google Cloud and download its key as `key.json`.
2. Add the service account's email as a user on your Search Console property.
3. Install `google-api-python-client` and `google-auth`.
4. Change `SITE` to your property and run the script on a schedule.

The script is written for sites under 50K pages. It stops with a message if a window returns 50K or more page rows, because Search Analytics exposes at most 50K rows per day per search type and the result would be truncated.

```python
from datetime import date, timedelta
from googleapiclient.discovery import build
from google.oauth2 import service_account

SITE = "sc-domain:example.com"
WINDOW = 28        # days per comparison window
LAG = 3            # finalized Search Console data is typically 2-3 days late
MAX_ROWS = 50000   # Search Analytics exposes at most 50K rows per day per search type
DROP = 0.30        # flag pages that lost 30% of clicks or more
MIN_CLICKS = 50    # ignore pages too small to judge

creds = service_account.Credentials.from_service_account_file(
    "key.json", scopes=["https://www.googleapis.com/auth/webmasters.readonly"])
gsc = build("searchconsole", "v1", credentials=creds)

def clicks_by_page(start, end):
    rows, start_row = {}, 0
    while True:
        body = {"startDate": start.isoformat(), "endDate": end.isoformat(),
                "dimensions": ["page"], "dataState": "final",
                "rowLimit": 25000, "startRow": start_row}
        resp = gsc.searchanalytics().query(siteUrl=SITE, body=body).execute()
        batch = resp.get("rows", [])
        for r in batch:
            rows[r["keys"][0]] = r["clicks"]
        if len(batch) < 25000:
            break
        start_row += 25000
    if len(rows) >= MAX_ROWS:
        raise SystemExit("Truncated at 50K rows: this script is for sites under 50K pages")
    return rows

end_now = date.today() - timedelta(days=LAG)
start_now = end_now - timedelta(days=WINDOW - 1)
end_prev = start_now - timedelta(days=1)
start_prev = end_prev - timedelta(days=WINDOW - 1)

now = clicks_by_page(start_now, end_now)
prev = clicks_by_page(start_prev, end_prev)

if not now or len(now) < len(prev) / 2:
    raise SystemExit("Partial data: treat as a data problem, not a traffic drop")

flagged = [(url, c, now.get(url, 0)) for url, c in prev.items()
           if c >= MIN_CLICKS and now.get(url, 0) <= c * (1 - DROP)]
flagged.sort(key=lambda x: x[1] - x[2], reverse=True)
print(f"Compared {len(prev)} pages, flagged {len(flagged)}")
for url, before, after in flagged:
    print(f"{url}: {before} -> {after} clicks")
```

Here is what each parameter does, and why:

- **WINDOW = 28:** two complete windows of four whole weeks each, so the weekday mix matches. It's this post's default, not a Google recommendation.
- **LAG = 3:** the windows end three days ago because finalized data is typically available after 2-3 days.
- **DROP at 30% and MIN_CLICKS at 50:** editorial defaults you tune. The minimum keeps a page that fell from 4 clicks to 2 out of the report.
- **dataState set to final:** the script requests finalized data explicitly. It's also what you get when the parameter is omitted.
- **MAX_ROWS and the half-size guard:** the first aborts on truncated data, the second aborts when the current window has fewer than half the pages of the prior one.

### Why the window ends three days ago

Finalized data is the only kind that makes two windows comparable, and it arrives late.

Google's documentation says Search Console data is typically available after 2-3 days. With dataState=final, which is also the default when the parameter is omitted, the API returns only finalized rows.

Set dataState=all and you get fresh data, which can still change. Fresh but incomplete is the trade. A window that ends today would either undercount the newest days or count unfinished ones, and both read as a traffic drop. LAG=3 sits at the top of the 2-3 day delay, so the last day in each window is usually complete.

That also corrects the "real-time dashboard" claim that automation pages repeat. Fresh rows are available through the API when you ask for dataState=all, but they are incomplete and can change. For week-over-week decisions, finalized data wins.

Two more details come from the same documentation. The API returns up to 25,000 rows per response, so paging with startRow in steps of 25,000 collects the rest, and the loop stops when a batch comes back short. And grouping by page and query string together is the most expensive query shape, so the script groups by page only.

::figure{src="/blog/figures/seo-automation-1.svg" alt="SEO automation flow of a Search Console traffic-decliner alert: pull two 28-day windows ending 3 days ago, check page count, flag pages with a 30% click drop." caption="The decliner alert pulls two complete 28-day windows ending three days ago, drops partial data, then flags pages that lost 30% or more of their clicks." width="720" height="219"}

### Script, workflow builder or platform: which build path costs less?

A script costs least when one person owns the job, a workflow builder when several non-developers edit it, and a platform when the vendor should maintain the connectors.

The table compares who maintains it, where the data lives, what breaks, and integration depth: how many connectors you write or inherit, and whether the path can set dataState and page past 25,000 rows. Data volume means rows per run before truncation or a cap, so check the module or connector for it. We claim no figure.

| Build path | Who maintains it | Where the data lives | What breaks | Integration depth and data volume |
|---|---|---|---|---|
| Script | The person who wrote it | Your server or laptop | Expired credential, quota hit, changed API | Full control of dataState and paging; rows per run are yours to set |
| Workflow builder (Make, n8n) | Whoever edits the scenario | The builder's workspace | A connector breaks or changes | Make builds visual scenarios where each module performs one step; n8n is low-code with room to write code, which leans toward slightly more technical users. Check the module for dataState and paging |
| Platform | The vendor | The vendor's system | A template or data source changes | Inherited connectors; confirm what it exposes before you rely on it |

Pick by owner first, features second. If you're the only person touching the job, the script wins. If a marketer who doesn't code will edit the thresholds, a builder is cheaper. If nobody wants to own connectors, buy a platform. Tool categories and prices live in our roundup of [AI SEO tools](https://missiongrowth.io/blog/best-ai-seo-tools), and agents that act on their own are covered in the [AI SEO agent](https://missiongrowth.io/blog/ai-agent-seo) guide.

Is it worth the cost? An automation is worth it when the hours it saves each month exceed the hours someone spends maintaining it, and the subscription is the smaller term of that sum. Everything that breaks lands on whoever the table names.

That means an expired credential, a connector that breaks after an update, a quota hit or a changed page template. Count those hours maintaining the job before you count the licence.

## How to automate SEO content without publishing unreviewed text

Automated SEO content ships as a draft for review, and Google's guidance puts titles, meta descriptions, structured data and alt text inside the review alongside the article body.

Google's generative AI guidance says it is critical to [manually factcheck and review all AI-generated content](https://developers.google.com/search/docs/fundamentals/using-gen-ai-content) before publishing. It adds that the review also applies to metadata like title elements, meta description elements, structured data and alternate texts for images, which can appear in Search results.

The table shows what verifies each output, and what a miss looks like.

| Output | What verifies it | What a miss looks like |
|---|---|---|
| Article body | A person fact-checks it | A confident claim with no source |
| Title and meta description | A script checks length and duplicates; a person reads them | Truncated or duplicated snippets in results |
| Structured data | A validator, then a person confirms it matches the page | Markup describing content the page lacks |
| Image alt text | A person | Wrong or generic descriptions in image results |

Titles and descriptions need your review because they appear in results. The script can only count characters and spot duplicates.

Structured data is the only row where a machine does most of the work. Google tells you to validate the markup, so run a validator, then have a person confirm it describes what the page shows.

One workflow-builder vendor's SEO guide describes the opposite pattern as a feature:

> a weekly content refresh scenario updates meta descriptions across a CMS without a human opening each record.

That is the setup to avoid. Meta descriptions across a CMS are metadata Google lists in its review scope, and a scheduled scenario skips the step. Keep the scenario, but make it write proposed values into a review queue.

Volume is a separate risk. Google's spam policy says scaled content abuse applies no matter how the content is created, so generating many pages faster doesn't change the standard. Our post on [scaled content abuse](https://missiongrowth.io/blog/is-ai-content-bad-for-seo) covers where that line sits.

The pipeline rule follows. From keyword to published post, add two stops: a held-for-review state where drafts wait for a person, and a rollback list of the URLs each run changed. If a run goes wrong, the list tells you what to revert.

## How to tell your SEO automation is still working

A scheduled SEO job that fails silently looks the same as a site with no problems, so every job needs a heartbeat alert and a data-completeness check.

For example, take the decliner script above. If the credential expires, it stops. No flagged pages arrive, and your quiet inbox reads as a stable site. That silent failure is the most expensive kind, because nothing prompts you to look.

Here is the monitoring set that closes the gap:

- **Heartbeat alert:** the job posts "ran, compared N pages, flagged M" even when M is 0. A second check alerts when that message is missing after a scheduled run.
- **Completeness check:** the script aborts on partial data, when the page count falls below half the prior window, and on truncated data at 50K rows.
- **Run log:** every run records its window dates, row counts and result, so you can see when the numbers changed.
- **Owner and change history:** one named person per job, plus a record of every threshold change.

Jobs in the run-and-alert tier need the heartbeat most, because their value is the alert itself. The finalized-data lag matters here too: a heartbeat showing a sudden page count drop tells you the data was incomplete before you chase a traffic problem that never existed.

Build the decliner alert first. It's the one job with a verifier, a free data source and no live change. Add the heartbeat before you schedule it, and you've automated your first SEO task with a way to know it's still running.

## FAQ

### What can I automate with the Search Console API per day?

Search Analytics allows 1,200 queries per minute per site. URL Inspection allows 2,000 queries per day per site. The Indexing API defaults to 200 publish requests per day per project, and only for pages with JobPosting or BroadcastEvent markup. Size each job against those caps first.

### What is SEO automation?

Scripts, workflow builders and AI handle recurring search jobs for you. Jobs a script can verify, such as reporting and audits, run on their own. Jobs it can't verify, such as clustering, briefs and drafts, come back as drafts for a person.

### Can ChatGPT do SEO?

ChatGPT can draft briefs, cluster keywords and suggest titles, but it can't verify them against your data unless it's connected to that data. Treat its output as a draft for review. Tools built around that limit are covered in our tool roundup.

### Can I do SEO by myself?

Yes. Start with the jobs a script can check, like the decliner alert, and keep strategy, outreach and review in your own hands. A solo SEO gains most from automating the checkable work first, so the unverifiable work gets your full attention.

### Will SEO be replaced by AI?

AI changes which tasks are worth doing by hand, but the verifier rule here still holds: what a script can't check needs a person. The wider debate, including whether automating a task grows or shrinks demand for it, sits in [will AI replace SEO](https://missiongrowth.io/blog/will-ai-replace-seo).
