Report

Report

The report is the brief plus two extra sections: comparison (did the page's score move since the last completed analysis?) and serp (what the SERP looks like for this page's primary keyword). It's the single call to read the result of an analyze run — use this instead of separately calling /brief, then /analysis?compare=prev, then /outline for the SERP snapshot.

Scope: sites:read


GET /pages/{pageId}/report

Path parameters

Parameter Type Description
pageId integer The page's ID

Request

curl -s https://new.metamonster.ai/api/v1/pages/5001/report \
  -H "Authorization: Bearer mm_YOUR_API_KEY"

When to use /report vs /brief

Both bundle the page's work packet — page, fields, analysis, recommendations, keywords, queries, outline, links — with sections degrading independently and only the page itself able to 404. /report's response is a superset: everything /brief returns, plus comparison, comparison_note, and serp. Reach for /brief when you're about to make edits (it's the smaller payload); reach for /report right after an analyze job completes, when you want to know what changed and how the page ranks in search — the MCP analyze_page/get_page_report tools return exactly this shape.

The two extra keys

Section What it is Same data standalone at How it degrades
comparison Score/component/criterion deltas plus a best-effort recommendation diff against the previous completed analysis. null when there's nothing to compare — see comparison_note. GET /pages/{pageId}/analysis?compare=prev null (with comparison_note set) if there's no analysis yet, no earlier completed analysis, or the latest analysis hasn't completed.
comparison_note Present (non-null) only when comparison is null. no_previous_analysis = no earlier completed analysis to diff against (including a page's first-ever analysis, or no analysis at all). analysis_incomplete = the latest analysis hasn't finished, so it has no scores to compare. N/A
serp { analysis, snapshot, source } — the current analysis's serp_analysis component (public columns only) plus the latest outline's SERP snapshot (top results + competitor headings), composed from data already on hand. No live SERP fetch happens here. analysis mirrors the serp_analysis entry in /analysis's components; snapshot is GET /pages/{pageId}/outline's serp_snapshot analysis: null if there's no analysis or it has no serp_analysis component; snapshot: null if there's no outline (or the outline load fails); source: "none" when both are null.

serp.source tells you which half you got without checking both fields yourself: "analysis+outline" (both present), "analysis" (component only), "outline" (snapshot only), "none" (neither).

Response 200 (trimmed — see brief.md for the shared page/fields/analysis/recommendations/keywords/queries/outline/links shape)

{
  "data": {
    "page": { "id": 5001, "url": "https://example.com/pricing", "path": "/pricing" },
    "fields": { "…": "…same shape as the brief" },
    "analysis": { "id": 7201, "overall_score": 74, "overall_grade": "B-", "components": [ { "id": 9, "analysis_id": 7201, "component_type": "serp_analysis", "score": 80, "…": "…" } ] },
    "recommendations": [],
    "keywords": { "primary": { "keyword": "example pricing", "metrics": null }, "secondary": [] },
    "queries": { "data": [], "gsc_status": "available", "window": { "start_date": "2026-07-17", "end_date": "2026-08-13" } },
    "outline": { "id": 901, "status": "completed", "primary_keyword": "example pricing", "section_count": 6, "completed_at": "2026-08-10T12:00:42Z" },
    "links": { "data": [], "meta": { "total": 0, "truncated": false } },
    "comparison": {
      "previous_analysis_id": 7200,
      "previous_analyzed_at": "2026-08-10T09:00:00Z",
      "overall_score": { "prev": 68, "now": 74, "delta": 6 },
      "overall_grade": { "prev": "C+", "now": "B-" },
      "components": [ { "component_type": "title", "score": { "prev": 60, "now": 72, "delta": 12 } } ],
      "criteria": [],
      "recommendations": { "new": [], "still_open": [], "resolved": [], "dropped": [] },
      "matching": "best_effort_title"
    },
    "comparison_note": null,
    "serp": {
      "analysis": { "id": 9, "analysis_id": 7201, "component_type": "serp_analysis", "score": 80, "grade": "B", "estimated_score": null, "estimated_grade": null, "criteria_scores": {}, "rationale": "…", "model": "claude-haiku", "site_id": 42, "created_at": "2026-08-15T09:00:00Z", "updated_at": "2026-08-15T09:00:00Z", "label": "SERP Analysis", "status": "completed" },
      "snapshot": {
        "keyword": "example pricing",
        "results": [ { "position": 1, "title": "Example Pricing Plans", "url": "https://competitor.com/pricing", "snippet": "Compare plans…" } ],
        "competitors": [ { "position": 1, "title": "Example Pricing Plans", "url": "https://competitor.com/pricing", "domain": "competitor.com", "headings": [ { "level": 1, "text": "Pricing" } ], "word_count": 1200, "fetch_error": false } ]
      },
      "source": "analysis+outline"
    }
  }
}

Errors

Status When
401 unauthorized Missing/invalid key
403 forbidden Key lacks sites:read
404 not_found No such page in your organization — the only hard failure the report can produce
429 rate_limited Rate limit exceeded