AI Agent 4 min read

Build a SERP Content Brief Generator with Source Checks

Build a runnable JSON content brief from SERP results and reviewed passages. Validate source links, quoted text and missing evidence before article drafting.

(Updated: ) • 656 words

A SERP-based content brief should identify a search task, proposed sections and the sources an editor must review. The implementation below produces a deterministic JSON brief from search results and approved source passages. It does not generate an article, infer facts from snippets, or claim that a model has checked the evidence.

Define the output before adding a model

Field Purpose
query The search task that produced this brief
sources Source URL and an excerpt already checked against the retrieved text
sections A suggested heading with source IDs, not an unsupported claim
editor_checks Questions requiring human review before drafting

Fetch a search envelope using the Google Search API contract. Check HTTP status and the business code, then read data.organic. Review source URLs before extraction. A result snippet is useful for finding a page; it is not sufficient evidence for a price, legal conclusion or technical guarantee.

Run the brief builder with a small fixture

import json
from urllib.parse import urlsplit

def build_brief(query, envelope, reviewed_passages):
    if envelope.get("code") != 0 or not isinstance(envelope.get("data"), dict):
        raise ValueError("Search contract failed")
    rows = envelope["data"].get("organic", [])
    if not isinstance(rows, list):
        raise ValueError("Expected organic array")
    sources, sections = [], []
    for row in rows:
        url = row.get("link") if isinstance(row, dict) else None
        if not isinstance(url, str) or urlsplit(url).scheme != "https":
            continue
        source = reviewed_passages.get(url)
        if not isinstance(source, dict):
            continue
        quote, text = source.get("quote"), source.get("text")
        if not isinstance(quote, str) or not quote.strip() or not isinstance(text, str) or quote not in text:
            raise ValueError("Quote is absent from the reviewed source")
        sid = "source-" + str(len(sources) + 1)
        sources.append({"id":sid, "url":url, "quote":quote})
        sections.append({"heading":row.get("title") or "Untitled source", "source_ids":[sid]})
    if not sources:
        raise ValueError("No reviewed sources: do not generate an unsupported brief")
    return {"query":query, "sources":sources, "sections":sections,
            "editor_checks":["Does the quote support the proposed claim?", "What original contribution is missing?"]}

if __name__ == "__main__":
    # Synthetic inputs demonstrate the contract, not a live SERP or a factual finding.
    url = "https://example.com/source"
    envelope = {"code":0, "data":{"organic":[{"title":"Cache validation", "link":url}]}}
    brief = build_brief("cache validation", envelope,
        {url:{"text":"Revalidate expired records.", "quote":"Revalidate expired records."}})
    print(json.dumps(brief, indent=2))

Save this as brief.py and run python brief.py. The fixture uses a reserved example domain and fictional text. Its output contains one source and one proposed section. Replace the fixture with reviewed passages to create a real brief. The function rejects a quote absent from the source, an invalid response shape and a brief without usable evidence.

What an editor still has to decide

An exact substring match only checks that the excerpt was present. It does not prove that it supports the proposed interpretation, remains current, or represents the whole page fairly. Review the claim, omitted context and publication date. Then name the contribution this article will add: a reproducible test, an original decision rule, or a documented implementation detail. If the existing cluster owner already answers the same task, update that owner instead of generating a competing article.

An LLM can propose an outline after these checks, but its output needs the same source IDs and a schema validator. This tutorial intentionally has no placeholder “AI-generated brief” string and no dependency on an untested SDK version. To measure actual results after publishing, use the GSC and GA4 reporting contract.

Sources and reproduction

Tags:

AI Agent SERP API Reader API Tutorial LLM Python
SearchCans Team

SearchCans Team

SERP API & Reader API Experts

The SearchCans engineering team builds high-performance search APIs serving developers worldwide. We share practical tutorials, best practices, and insights on SERP data, web scraping, RAG pipelines, and AI integration.

Ready to build with SearchCans?

Test SERP API and Reader API with 100 free credits. No credit card required.