I built a weekly SEO agent that creates GitHub Issues do other stuff

And yes, I pasted a Gemini curl command into the wrong field. Twice.


Twenty years in IT and I was still manually checking SEO dashboards like it was 2008.

Here's the truth: I don't have an SEO problem. I have a follow-through problem. I know what's wrong with my sites. I've known for months. The knowledge was never the issue — the execution was.

So I automated the follow-through. In one afternoon, working with Claude Code and Claude, I built a weekly agent that pulls my Search Console data, analyses it with AI, and files GitHub Issues with specific fixes — while I eat lunch. And honestly? I'm proud of what I can build now. The speed at which I can go from "I should fix that" to "that's already in my issue tracker" has changed completely.

Here's exactly how I built it.


The architecture (it's simpler than it sounds)

Three APIs. One Python script. One cron job.

GitHub Actions (every Friday 10:00 UTC) │ ├── Google Search Console API → your real traffic data ├── Anthropic Claude API → analysis + recommendations └── GitHub Issues API → creates the actual tickets

No server. No database. No monthly infrastructure bill. Just a .yml file and a .py file sitting in your repo.

Total cost: under €1/month — the Claude API calls are tiny.


What you'll need before starting

  • Your sites verified in Google Search Console
  • A Google Cloud account (free tier is fine)
  • A GitHub repo for each site you want to audit
  • An Anthropic API key from console.anthropic.com

Step 1: Create a Google Service Account

This is the part that sounds scary but takes 10 minutes.

Go to console.cloud.google.com, create a project called seo-agent, and enable the Google Search Console API under APIs & Services → Library.

Then go to IAM & Admin → Service Accounts → Create service account. Name it seo-agent-reader. No role needed. Create it.

Once created, click on it → Keys → Add Key → Create new key → JSON.

A .json file downloads. Don't lose this file. It looks like this:

{
  "type": "service_account",
  "project_id": "seo-agent-493417",
  "private_key_id": "abc123...",
  "client_email": "seo-agent-reader@seo-agent-493417.iam.gserviceaccount.com",
  ...
}

You'll paste the entire contents of this file into a GitHub secret later.


Step 2: Give the service account access to Search Console

For each site you want to audit:

  1. Open Search Console → your property → Settings → Users and permissions
  2. Add user → paste the client_email from your JSON file
  3. Permission: Restricted (read-only is all we need)

Step 3: Create a GitHub Personal Access Token

GitHub → Settings → Developer settings → Fine-grained tokens → Generate new token.

The only permission you need: Issues: Read and write.

Make sure the token has access to the repos where you want issues created. Copy it immediately — you only see it once.


Step 4: The workflow file

Create .github/workflows/seo-audit.yml in your repo:

name: SEO Weekly Audit

on:
  schedule:
    - cron: '0 10 * * 5'   # Friday 12:00 Paris time (CEST)
  workflow_dispatch:         # Manual trigger for testing

jobs:
  seo-audit:
    runs-on: ubuntu-latest
    timeout-minutes: 15

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          pip install \
            google-auth==2.29.0 \
            google-auth-httplib2==0.2.0 \
            google-api-python-client==2.127.0 \
            anthropic>=0.50.0 \
            requests==2.32.3

      - name: Run SEO audit
        env:
          GOOGLE_SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_JSON }}
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GH_TOKEN: ${{ secrets.SEO_GITHUB_TOKEN }}
          REPO_SITE1: "yourusername/your-repo"
        run: python .github/scripts/seo_audit.py

Two things to know about the cron schedule: GitHub Actions runs in UTC, and France is UTC+2 in summer. So Friday noon Paris time = 0 10 * * 5. The 5 is Friday (0 = Sunday).


Step 5: The Python script (the important bit)

Create .github/scripts/seo_audit.py. The key parts:

Authenticating with Google:

from google.oauth2 import service_account
from googleapiclient.discovery import build

def build_search_console_service():
    raw  = os.environ.get("GOOGLE_SERVICE_ACCOUNT_JSON")
    info = json.loads(raw)
    creds = service_account.Credentials.from_service_account_info(
        info,
        scopes=["https://www.googleapis.com/auth/webmasters.readonly"],
    )
    return build("searchconsole", "v1", credentials=creds, cache_discovery=False)

Asking Claude for analysis:

def ask_claude(site_name, data_block):
    client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
    msg = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=4000,
        system="""You are an SEO expert. Analyse Search Console data and return
ONLY a valid JSON array of GitHub issues. Each issue: title, body, labels, priority.
Be terse — data evidence + exact fix steps. Nothing else.""",
        messages=[{"role": "user", "content": f"Analyse {site_name}:\n\n{data_block}"}],
    )
    return json.loads(msg.content[0].text.strip())

Creating the GitHub issues:

def create_github_issue(repo, issue, site_name):
    requests.post(
        f"https://api.github.com/repos/{repo}/issues",
        headers={"Authorization": f"Bearer {os.environ['GH_TOKEN']}"},
        json={
            "title":  issue["title"],
            "body":   issue["body"],
            "labels": issue["labels"] + ["seo-agent"],
        }
    )

The full script with error handling, multi-site support, and label fallback is on my GitHub.


Step 6: Add the three secrets

GitHub repo → Settings → Secrets and variables → Actions (Secrets tab, not Variables):

Secret nameValue
GOOGLE_SERVICE_ACCOUNT_JSONFull contents of your downloaded .json file
ANTHROPIC_API_KEYYour Anthropic key (sk-ant-...)
SEO_GITHUB_TOKENYour GitHub PAT (github_pat_...)

The mistakes I made (so you don't have to)

I pasted a Gemini curl command into the GOOGLE_SERVICE_ACCOUNT_JSON field.

In my defence, I had six tabs open and was multitasking. The secret needs to contain the raw JSON from the file you downloaded — not a curl command, not a URL, not anything else. Open the .json file in a text editor, select all, paste.

I used anthropic==0.28.0 and got a proxies TypeError.

The pinned version was too old and conflicted with a newer httpx. Fix: use anthropic>=0.50.0 instead.

I got 404s when creating issues.

My GitHub token was named seo-reader-token — and indeed it only had read access. Naming things matters, apparently. Regenerate the token with Issues: Read and write.

Claude's JSON was getting truncated.

max_tokens=2000 wasn't enough for 5 detailed issues. Bumped to 4000, problem solved.


What the output looks like

After the first successful run, I had 5 issues in my repo within 2 minutes:

  • [SEO] Homepage title/meta underperforming: pos 4.4, 25 impr, only 4% CTR
  • [SEO] HTTP URLs indexed — migrate http://raphaelreck.com/* to HTTPS
  • [SEO] /memes/laugh.html: 12 impressions, pos 3.7, zero clicks — fix title/meta
  • [SEO] /blog/when-webservices-lie.html: 13 impr, pos 7.7 — optimise to reach page 1
  • [SEO] hook_webform_submission_insert: pos 9, 6 impr — target Drupal niche keyword

Each one includes the Search Console data that justifies it, and exact steps to fix it. Not vague advice — specific changes with context.

These are things I already knew I should do. The difference is they're now in my issue tracker with labels, instead of floating in my head as vague intentions.


Do you even need Google Analytics?

Short answer: not for this.

Search Console tells you what people search for, which pages appear, how often they click, and where you rank. That's the SEO signal. Analytics tells you what people do after they land. Useful, but separate. Start with Search Console. Add Analytics later if you need conversion data.


What's next

This is Phase 1. Phase 2 is a second agent that reads these issues and actually implements the fixes — rewriting meta descriptions, updating title tags, fixing redirect chains. The SEO agent files the tickets; the fix agent closes them.

For now, having the analysis automated is already a 10x improvement over "stare at dashboard, close tab, repeat."

The full script is on github.com/djassoRaph/raphaelwebsite — questions or war stories about your own setup, find me on X.

Thank you for reading.




← Back to Blog Index